From 7c03a3d676c065f2f1a9e95d8d4689431bd48b59 Mon Sep 17 00:00:00 2001 From: npm CLI robot Date: Mon, 16 Jan 2023 22:38:23 -0500 Subject: [PATCH] deps: upgrade npm to 9.3.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/46193 Reviewed-By: Luigi Pinca Reviewed-By: Tobias Nießen Reviewed-By: Jiawen Geng Reviewed-By: Colin Ihrig Reviewed-By: Myles Borins Reviewed-By: Rich Trott --- Makefile | 2 +- deps/npm/docs/content/commands/npm-access.md | 2 + deps/npm/docs/content/commands/npm-adduser.md | 3 +- deps/npm/docs/content/commands/npm-ci.md | 4 +- deps/npm/docs/content/commands/npm-dedupe.md | 4 +- .../docs/content/commands/npm-find-dupes.md | 4 +- deps/npm/docs/content/commands/npm-init.md | 2 +- .../content/commands/npm-install-ci-test.md | 4 +- .../docs/content/commands/npm-install-test.md | 4 +- deps/npm/docs/content/commands/npm-install.md | 4 +- deps/npm/docs/content/commands/npm-link.md | 4 +- deps/npm/docs/content/commands/npm-login.md | 3 +- deps/npm/docs/content/commands/npm-ls.md | 2 +- deps/npm/docs/content/commands/npm-owner.md | 2 - deps/npm/docs/content/commands/npm-publish.md | 4 +- deps/npm/docs/content/commands/npm-root.md | 2 + deps/npm/docs/content/commands/npm-update.md | 4 +- deps/npm/docs/content/commands/npm.md | 6 +- .../docs/content/configuring-npm/install.md | 6 +- deps/npm/docs/content/using-npm/config.md | 11 +- deps/npm/docs/content/using-npm/registry.md | 2 +- deps/npm/docs/content/using-npm/removal.md | 4 +- deps/npm/docs/content/using-npm/scripts.md | 2 +- deps/npm/docs/output/commands/npm-access.html | 1 + .../npm/docs/output/commands/npm-adduser.html | 3 +- deps/npm/docs/output/commands/npm-ci.html | 4 +- deps/npm/docs/output/commands/npm-dedupe.html | 4 +- .../docs/output/commands/npm-find-dupes.html | 4 +- deps/npm/docs/output/commands/npm-init.html | 2 +- .../output/commands/npm-install-ci-test.html | 4 +- .../output/commands/npm-install-test.html | 4 +- .../npm/docs/output/commands/npm-install.html | 4 +- deps/npm/docs/output/commands/npm-link.html | 4 +- deps/npm/docs/output/commands/npm-login.html | 3 +- deps/npm/docs/output/commands/npm-ls.html | 2 +- deps/npm/docs/output/commands/npm-owner.html | 1 - .../npm/docs/output/commands/npm-publish.html | 4 +- deps/npm/docs/output/commands/npm-root.html | 1 + deps/npm/docs/output/commands/npm-update.html | 4 +- deps/npm/docs/output/commands/npm.html | 5 +- .../docs/output/configuring-npm/install.html | 6 +- deps/npm/docs/output/using-npm/config.html | 11 +- deps/npm/docs/output/using-npm/registry.html | 2 +- deps/npm/docs/output/using-npm/removal.html | 4 +- deps/npm/docs/output/using-npm/scripts.html | 2 +- deps/npm/lib/arborist-cmd.js | 31 +- deps/npm/lib/base-command.js | 81 +- deps/npm/lib/cli.js | 13 +- deps/npm/lib/commands/access.js | 2 - deps/npm/lib/commands/adduser.js | 2 - deps/npm/lib/commands/audit.js | 2 +- deps/npm/lib/commands/cache.js | 15 +- deps/npm/lib/commands/ci.js | 9 +- deps/npm/lib/commands/completion.js | 25 +- deps/npm/lib/commands/config.js | 11 +- deps/npm/lib/commands/diff.js | 5 +- deps/npm/lib/commands/dist-tag.js | 17 +- deps/npm/lib/commands/edit.js | 16 +- deps/npm/lib/commands/exec.js | 37 +- deps/npm/lib/commands/find-dupes.js | 2 +- deps/npm/lib/commands/fund.js | 95 +- deps/npm/lib/commands/help-search.js | 9 +- deps/npm/lib/commands/help.js | 99 +- deps/npm/lib/commands/hook.js | 18 +- deps/npm/lib/commands/init.js | 39 +- deps/npm/lib/commands/install-ci-test.js | 2 +- deps/npm/lib/commands/install-test.js | 2 +- deps/npm/lib/commands/login.js | 2 - deps/npm/lib/commands/logout.js | 2 - deps/npm/lib/commands/ls.js | 10 +- deps/npm/lib/commands/org.js | 11 +- deps/npm/lib/commands/outdated.js | 4 +- deps/npm/lib/commands/owner.js | 7 +- deps/npm/lib/commands/pack.js | 5 +- deps/npm/lib/commands/ping.js | 7 +- deps/npm/lib/commands/pkg.js | 7 +- deps/npm/lib/commands/prefix.js | 1 - deps/npm/lib/commands/profile.js | 4 +- deps/npm/lib/commands/publish.js | 7 +- deps/npm/lib/commands/query.js | 5 +- deps/npm/lib/commands/restart.js | 3 +- deps/npm/lib/commands/root.js | 1 - deps/npm/lib/commands/run-script.js | 17 +- deps/npm/lib/commands/search.js | 1 - deps/npm/lib/commands/start.js | 3 +- deps/npm/lib/commands/stop.js | 3 +- deps/npm/lib/commands/test.js | 3 +- deps/npm/lib/commands/token.js | 13 +- deps/npm/lib/commands/uninstall.js | 17 +- deps/npm/lib/commands/unpublish.js | 7 +- deps/npm/lib/commands/update.js | 4 +- deps/npm/lib/commands/version.js | 15 +- deps/npm/lib/commands/view.js | 89 +- deps/npm/lib/commands/whoami.js | 1 - deps/npm/lib/lifecycle-cmd.js | 6 +- deps/npm/lib/npm.js | 201 +- deps/npm/lib/package-url-cmd.js | 7 +- deps/npm/lib/utils/config/definitions.js | 16 +- deps/npm/lib/utils/error-message.js | 22 +- deps/npm/lib/utils/exit-handler.js | 20 +- deps/npm/lib/utils/explain-dep.js | 6 +- deps/npm/lib/utils/log-file.js | 8 +- deps/npm/lib/utils/npm-usage.js | 3 +- deps/npm/lib/utils/open-url.js | 2 +- deps/npm/lib/utils/queryable.js | 15 +- deps/npm/lib/utils/read-user-info.js | 6 +- deps/npm/lib/utils/reify-output.js | 4 +- deps/npm/lib/workspaces/get-workspaces.js | 2 +- deps/npm/man/man1/npm-access.1 | 4 +- deps/npm/man/man1/npm-adduser.1 | 4 +- deps/npm/man/man1/npm-audit.1 | 2 +- deps/npm/man/man1/npm-bugs.1 | 2 +- deps/npm/man/man1/npm-cache.1 | 2 +- deps/npm/man/man1/npm-ci.1 | 6 +- deps/npm/man/man1/npm-completion.1 | 2 +- deps/npm/man/man1/npm-config.1 | 2 +- deps/npm/man/man1/npm-dedupe.1 | 6 +- deps/npm/man/man1/npm-deprecate.1 | 2 +- deps/npm/man/man1/npm-diff.1 | 2 +- deps/npm/man/man1/npm-dist-tag.1 | 2 +- deps/npm/man/man1/npm-docs.1 | 2 +- deps/npm/man/man1/npm-doctor.1 | 2 +- deps/npm/man/man1/npm-edit.1 | 2 +- deps/npm/man/man1/npm-exec.1 | 2 +- deps/npm/man/man1/npm-explain.1 | 2 +- deps/npm/man/man1/npm-explore.1 | 2 +- deps/npm/man/man1/npm-find-dupes.1 | 6 +- deps/npm/man/man1/npm-fund.1 | 2 +- deps/npm/man/man1/npm-help-search.1 | 2 +- deps/npm/man/man1/npm-help.1 | 2 +- deps/npm/man/man1/npm-hook.1 | 2 +- deps/npm/man/man1/npm-init.1 | 4 +- deps/npm/man/man1/npm-install-ci-test.1 | 6 +- deps/npm/man/man1/npm-install-test.1 | 6 +- deps/npm/man/man1/npm-install.1 | 6 +- deps/npm/man/man1/npm-link.1 | 6 +- deps/npm/man/man1/npm-login.1 | 4 +- deps/npm/man/man1/npm-logout.1 | 2 +- deps/npm/man/man1/npm-ls.1 | 4 +- deps/npm/man/man1/npm-org.1 | 2 +- deps/npm/man/man1/npm-outdated.1 | 2 +- deps/npm/man/man1/npm-owner.1 | 4 +- deps/npm/man/man1/npm-pack.1 | 2 +- deps/npm/man/man1/npm-ping.1 | 2 +- deps/npm/man/man1/npm-pkg.1 | 2 +- deps/npm/man/man1/npm-prefix.1 | 2 +- deps/npm/man/man1/npm-profile.1 | 2 +- deps/npm/man/man1/npm-prune.1 | 2 +- deps/npm/man/man1/npm-publish.1 | 4 +- deps/npm/man/man1/npm-query.1 | 2 +- deps/npm/man/man1/npm-rebuild.1 | 2 +- deps/npm/man/man1/npm-repo.1 | 2 +- deps/npm/man/man1/npm-restart.1 | 2 +- deps/npm/man/man1/npm-root.1 | 4 +- deps/npm/man/man1/npm-run-script.1 | 2 +- deps/npm/man/man1/npm-search.1 | 2 +- deps/npm/man/man1/npm-shrinkwrap.1 | 2 +- deps/npm/man/man1/npm-star.1 | 2 +- deps/npm/man/man1/npm-stars.1 | 2 +- deps/npm/man/man1/npm-start.1 | 2 +- deps/npm/man/man1/npm-stop.1 | 2 +- deps/npm/man/man1/npm-team.1 | 2 +- deps/npm/man/man1/npm-test.1 | 2 +- deps/npm/man/man1/npm-token.1 | 2 +- deps/npm/man/man1/npm-uninstall.1 | 2 +- deps/npm/man/man1/npm-unpublish.1 | 2 +- deps/npm/man/man1/npm-unstar.1 | 2 +- deps/npm/man/man1/npm-update.1 | 6 +- deps/npm/man/man1/npm-version.1 | 2 +- deps/npm/man/man1/npm-view.1 | 2 +- deps/npm/man/man1/npm-whoami.1 | 2 +- deps/npm/man/man1/npm.1 | 8 +- deps/npm/man/man1/npx.1 | 2 +- deps/npm/man/man5/folders.5 | 2 +- deps/npm/man/man5/install.5 | 8 +- deps/npm/man/man5/npm-global.5 | 2 +- deps/npm/man/man5/npm-json.5 | 2 +- deps/npm/man/man5/npm-shrinkwrap-json.5 | 2 +- deps/npm/man/man5/npmrc.5 | 2 +- deps/npm/man/man5/package-json.5 | 2 +- deps/npm/man/man5/package-lock-json.5 | 2 +- deps/npm/man/man7/config.7 | 10 +- deps/npm/man/man7/dependency-selectors.7 | 2 +- deps/npm/man/man7/developers.7 | 2 +- deps/npm/man/man7/logging.7 | 2 +- deps/npm/man/man7/orgs.7 | 2 +- deps/npm/man/man7/package-spec.7 | 2 +- deps/npm/man/man7/registry.7 | 4 +- deps/npm/man/man7/removal.7 | 4 +- deps/npm/man/man7/scope.7 | 2 +- deps/npm/man/man7/scripts.7 | 4 +- deps/npm/man/man7/workspaces.7 | 2 +- .../arborist/lib/arborist/build-ideal-tree.js | 4 +- .../arborist/lib/arborist/load-virtual.js | 4 +- .../arborist/lib/arborist/load-workspaces.js | 22 +- .../@npmcli/arborist/lib/override-resolves.js | 2 +- .../@npmcli/arborist/lib/override-set.js | 29 +- .../@npmcli/arborist/lib/place-dep.js | 3 +- .../@npmcli/arborist/package.json | 7 +- .../node_modules/@npmcli/config/lib/index.js | 49 +- .../node_modules/@npmcli/config/package.json | 4 +- .../node_modules/libnpmaccess/package.json | 2 +- deps/npm/node_modules/libnpmdiff/package.json | 6 +- deps/npm/node_modules/libnpmexec/package.json | 8 +- deps/npm/node_modules/libnpmfund/package.json | 6 +- deps/npm/node_modules/libnpmhook/package.json | 2 +- deps/npm/node_modules/libnpmorg/package.json | 2 +- deps/npm/node_modules/libnpmpack/package.json | 6 +- .../node_modules/libnpmpublish/package.json | 4 +- .../node_modules/libnpmsearch/package.json | 2 +- deps/npm/node_modules/libnpmteam/package.json | 2 +- .../node_modules/libnpmversion/package.json | 2 +- .../node_modules/minipass/LICENSE | 15 - .../node_modules/minipass/index.d.ts | 155 - .../node_modules/minipass/index.js | 649 -- .../node_modules/minipass/package.json | 56 - .../node_modules/minipass-fetch/package.json | 11 +- deps/npm/package.json | 20 +- .../test/lib/commands/audit.js.test.cjs | 4 +- .../test/lib/commands/config.js.test.cjs | 1 - .../test/lib/commands/diff.js.test.cjs | 88 + .../test/lib/commands/dist-tag.js.test.cjs | 25 +- .../test/lib/commands/doctor.js.test.cjs | 96 +- .../test/lib/commands/fund.js.test.cjs | 44 +- .../test/lib/commands/init.js.test.cjs | 55 +- .../test/lib/commands/link.js.test.cjs | 34 +- .../test/lib/commands/ls.js.test.cjs | 388 +- .../test/lib/commands/outdated.js.test.cjs | 161 +- .../test/lib/commands/profile.js.test.cjs | 3 +- .../test/lib/commands/query.js.test.cjs | 44 +- .../test/lib/commands/stars.js.test.cjs | 1 - .../test/lib/commands/team.js.test.cjs | 15 +- .../tap-snapshots/test/lib/docs.js.test.cjs | 77 +- .../test/lib/utils/error-message.js.test.cjs | 89 +- .../test/lib/utils/exit-handler.js.test.cjs | 26 +- .../test/lib/utils/log-file.js.test.cjs | 2 +- .../test/lib/utils/reify-output.js.test.cjs | 438 +- deps/npm/test/bin/npm-cli.js | 6 +- deps/npm/test/bin/npx-cli.js | 72 +- deps/npm/test/fixtures/clean-snapshot.js | 30 +- deps/npm/test/fixtures/merge-conflict.json | 36 + deps/npm/test/fixtures/mock-globals.js | 34 +- deps/npm/test/fixtures/mock-npm.js | 353 +- deps/npm/test/fixtures/sandbox.js | 6 +- deps/npm/test/fixtures/tmock.js | 27 + deps/npm/test/index.js | 32 +- deps/npm/test/lib/arborist-cmd.js | 201 +- deps/npm/test/lib/cli.js | 43 +- deps/npm/test/lib/commands/audit.js | 49 +- deps/npm/test/lib/commands/bugs.js | 142 +- deps/npm/test/lib/commands/config.js | 8 +- deps/npm/test/lib/commands/diff.js | 1691 +++-- deps/npm/test/lib/commands/dist-tag.js | 336 +- deps/npm/test/lib/commands/docs.js | 172 +- deps/npm/test/lib/commands/doctor.js | 40 +- deps/npm/test/lib/commands/edit.js | 8 +- deps/npm/test/lib/commands/exec.js | 9 - deps/npm/test/lib/commands/explain.js | 416 +- deps/npm/test/lib/commands/explore.js | 352 +- deps/npm/test/lib/commands/fund.js | 700 +- deps/npm/test/lib/commands/help-search.js | 145 +- deps/npm/test/lib/commands/help.js | 420 +- deps/npm/test/lib/commands/hook.js | 419 +- deps/npm/test/lib/commands/init.js | 521 +- deps/npm/test/lib/commands/install.js | 361 +- deps/npm/test/lib/commands/link.js | 544 +- deps/npm/test/lib/commands/ll.js | 5 +- deps/npm/test/lib/commands/logout.js | 255 +- deps/npm/test/lib/commands/ls.js | 6140 +++++++++-------- deps/npm/test/lib/commands/org.js | 342 +- deps/npm/test/lib/commands/outdated.js | 610 +- deps/npm/test/lib/commands/owner.js | 38 +- deps/npm/test/lib/commands/pack.js | 16 - deps/npm/test/lib/commands/pkg.js | 383 +- deps/npm/test/lib/commands/profile.js | 694 +- deps/npm/test/lib/commands/prune.js | 2 +- deps/npm/test/lib/commands/publish.js | 93 +- deps/npm/test/lib/commands/query.js | 32 +- deps/npm/test/lib/commands/rebuild.js | 231 +- deps/npm/test/lib/commands/repo.js | 110 +- deps/npm/test/lib/commands/restart.js | 4 +- deps/npm/test/lib/commands/run-script.js | 761 +- deps/npm/test/lib/commands/set.js | 99 +- deps/npm/test/lib/commands/stars.js | 105 +- deps/npm/test/lib/commands/start.js | 4 +- deps/npm/test/lib/commands/stop.js | 4 +- deps/npm/test/lib/commands/team.js | 294 +- deps/npm/test/lib/commands/test.js | 4 +- deps/npm/test/lib/commands/token.js | 752 +- deps/npm/test/lib/commands/uninstall.js | 298 +- deps/npm/test/lib/commands/update.js | 201 +- deps/npm/test/lib/commands/version.js | 489 +- deps/npm/test/lib/commands/view.js | 196 +- deps/npm/test/lib/docs.js | 2 +- deps/npm/test/lib/fixtures/mock-globals.js | 14 +- deps/npm/test/lib/lifecycle-cmd.js | 23 +- deps/npm/test/lib/load-all-commands.js | 35 +- deps/npm/test/lib/npm.js | 58 +- deps/npm/test/lib/utils/audit-error.js | 136 +- .../lib/utils/completion/installed-deep.js | 3 +- .../lib/utils/completion/installed-shallow.js | 7 +- deps/npm/test/lib/utils/config/definitions.js | 14 +- deps/npm/test/lib/utils/display.js | 7 +- deps/npm/test/lib/utils/error-message.js | 196 +- deps/npm/test/lib/utils/exit-handler.js | 61 +- deps/npm/test/lib/utils/explain-dep.js | 11 +- deps/npm/test/lib/utils/log-file.js | 20 +- deps/npm/test/lib/utils/log-shim.js | 3 +- deps/npm/test/lib/utils/open-url-prompt.js | 19 +- deps/npm/test/lib/utils/open-url.js | 3 +- deps/npm/test/lib/utils/otplease.js | 159 +- deps/npm/test/lib/utils/pulse-till-done.js | 3 +- deps/npm/test/lib/utils/read-user-info.js | 3 +- deps/npm/test/lib/utils/reify-finish.js | 8 +- deps/npm/test/lib/utils/reify-output.js | 231 +- deps/npm/test/lib/utils/tar.js | 3 +- deps/npm/test/lib/utils/timers.js | 3 +- deps/npm/test/lib/utils/update-notifier.js | 12 +- deps/npm/test/lib/utils/web-auth.js | 3 +- 319 files changed, 11263 insertions(+), 13277 deletions(-) delete mode 100644 deps/npm/node_modules/minipass-fetch/node_modules/minipass/LICENSE delete mode 100644 deps/npm/node_modules/minipass-fetch/node_modules/minipass/index.d.ts delete mode 100644 deps/npm/node_modules/minipass-fetch/node_modules/minipass/index.js delete mode 100644 deps/npm/node_modules/minipass-fetch/node_modules/minipass/package.json create mode 100644 deps/npm/tap-snapshots/test/lib/commands/diff.js.test.cjs create mode 100644 deps/npm/test/fixtures/merge-conflict.json create mode 100644 deps/npm/test/fixtures/tmock.js diff --git a/Makefile b/Makefile index ab696b45b645ec..94013466239e9c 100644 --- a/Makefile +++ b/Makefile @@ -1550,7 +1550,7 @@ CONFLICT_RE=^>>>>>>> [[:xdigit:]]+|^<<<<<<< [[:alpha:]]+ # Related CI job: node-test-linter lint-ci: lint-js-ci lint-cpp lint-py lint-md lint-addon-docs lint-yaml-build lint-yaml - @if ! ( grep -IEqrs "$(CONFLICT_RE)" --exclude="error-message.js" benchmark deps doc lib src test tools ) \ + @if ! ( grep -IEqrs "$(CONFLICT_RE)" --exclude="error-message.js" --exclude="merge-conflict.json" benchmark deps doc lib src test tools ) \ && ! ( $(FIND) . -maxdepth 1 -type f | xargs grep -IEqs "$(CONFLICT_RE)" ); then \ exit 0 ; \ else \ diff --git a/deps/npm/docs/content/commands/npm-access.md b/deps/npm/docs/content/commands/npm-access.md index f2078e1c9c38dd..7c7e1ffdcc22e5 100644 --- a/deps/npm/docs/content/commands/npm-access.md +++ b/deps/npm/docs/content/commands/npm-access.md @@ -16,6 +16,8 @@ npm access grant [] npm access revoke [] ``` +Note: This command is unaware of workspaces. + ### Description Used to set access controls on private packages. diff --git a/deps/npm/docs/content/commands/npm-adduser.md b/deps/npm/docs/content/commands/npm-adduser.md index f0cd57be25a2b6..bc7d888a2f3d2d 100644 --- a/deps/npm/docs/content/commands/npm-adduser.md +++ b/deps/npm/docs/content/commands/npm-adduser.md @@ -67,7 +67,8 @@ npm init --scope=@foo --yes * Default: "web" * Type: "legacy" or "web" -What authentication strategy to use with `login`. +What authentication strategy to use with `login`. Note that if an `otp` +config is given, this value will always be set to `legacy`. ### See Also diff --git a/deps/npm/docs/content/commands/npm-ci.md b/deps/npm/docs/content/commands/npm-ci.md index 4a5caf7d0c691f..1e9220b6a63a76 100644 --- a/deps/npm/docs/content/commands/npm-ci.md +++ b/deps/npm/docs/content/commands/npm-ci.md @@ -138,7 +138,7 @@ de-duplicating. Sets `--install-strategy=nested`. `--install-strategy=shallow` Only install direct dependencies in the top level `node_modules`, but hoist -on deeper dependendencies. Sets `--install-strategy=shallow`. +on deeper dependencies. Sets `--install-strategy=shallow`. #### `omit` @@ -173,7 +173,7 @@ be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's `peerDependencies` object. -When such and override is performed, a warning is printed, explaining the +When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If `--strict-peer-deps` is set, then this warning is treated as a failure. diff --git a/deps/npm/docs/content/commands/npm-dedupe.md b/deps/npm/docs/content/commands/npm-dedupe.md index 80353bad5d0d7a..c32b50fbc5fb13 100644 --- a/deps/npm/docs/content/commands/npm-dedupe.md +++ b/deps/npm/docs/content/commands/npm-dedupe.md @@ -109,7 +109,7 @@ de-duplicating. Sets `--install-strategy=nested`. `--install-strategy=shallow` Only install direct dependencies in the top level `node_modules`, but hoist -on deeper dependendencies. Sets `--install-strategy=shallow`. +on deeper dependencies. Sets `--install-strategy=shallow`. #### `strict-peer-deps` @@ -126,7 +126,7 @@ be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's `peerDependencies` object. -When such and override is performed, a warning is printed, explaining the +When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If `--strict-peer-deps` is set, then this warning is treated as a failure. diff --git a/deps/npm/docs/content/commands/npm-find-dupes.md b/deps/npm/docs/content/commands/npm-find-dupes.md index a3ef44eb5b7fb1..e80f338239a84a 100644 --- a/deps/npm/docs/content/commands/npm-find-dupes.md +++ b/deps/npm/docs/content/commands/npm-find-dupes.md @@ -49,7 +49,7 @@ de-duplicating. Sets `--install-strategy=nested`. `--install-strategy=shallow` Only install direct dependencies in the top level `node_modules`, but hoist -on deeper dependendencies. Sets `--install-strategy=shallow`. +on deeper dependencies. Sets `--install-strategy=shallow`. #### `strict-peer-deps` @@ -66,7 +66,7 @@ be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's `peerDependencies` object. -When such and override is performed, a warning is printed, explaining the +When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If `--strict-peer-deps` is set, then this warning is treated as a failure. diff --git a/deps/npm/docs/content/commands/npm-init.md b/deps/npm/docs/content/commands/npm-init.md index cf8bb3936acea5..d8d7acee77f018 100644 --- a/deps/npm/docs/content/commands/npm-init.md +++ b/deps/npm/docs/content/commands/npm-init.md @@ -7,7 +7,7 @@ description: Create a package.json file ### Synopsis ```bash -npm init (same as `npx ) +npm init (same as `npx `) npm init <@scope> (same as `npx <@scope>/create`) aliases: create, innit diff --git a/deps/npm/docs/content/commands/npm-install-ci-test.md b/deps/npm/docs/content/commands/npm-install-ci-test.md index 9fd7c267b102f5..c7a75510232857 100644 --- a/deps/npm/docs/content/commands/npm-install-ci-test.md +++ b/deps/npm/docs/content/commands/npm-install-ci-test.md @@ -84,7 +84,7 @@ de-duplicating. Sets `--install-strategy=nested`. `--install-strategy=shallow` Only install direct dependencies in the top level `node_modules`, but hoist -on deeper dependendencies. Sets `--install-strategy=shallow`. +on deeper dependencies. Sets `--install-strategy=shallow`. #### `omit` @@ -119,7 +119,7 @@ be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's `peerDependencies` object. -When such and override is performed, a warning is printed, explaining the +When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If `--strict-peer-deps` is set, then this warning is treated as a failure. diff --git a/deps/npm/docs/content/commands/npm-install-test.md b/deps/npm/docs/content/commands/npm-install-test.md index 5642472630b530..464a4487481747 100644 --- a/deps/npm/docs/content/commands/npm-install-test.md +++ b/deps/npm/docs/content/commands/npm-install-test.md @@ -85,7 +85,7 @@ de-duplicating. Sets `--install-strategy=nested`. `--install-strategy=shallow` Only install direct dependencies in the top level `node_modules`, but hoist -on deeper dependendencies. Sets `--install-strategy=shallow`. +on deeper dependencies. Sets `--install-strategy=shallow`. #### `omit` @@ -120,7 +120,7 @@ be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's `peerDependencies` object. -When such and override is performed, a warning is printed, explaining the +When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If `--strict-peer-deps` is set, then this warning is treated as a failure. diff --git a/deps/npm/docs/content/commands/npm-install.md b/deps/npm/docs/content/commands/npm-install.md index 3604aab4b940f2..8353ea25a93b15 100644 --- a/deps/npm/docs/content/commands/npm-install.md +++ b/deps/npm/docs/content/commands/npm-install.md @@ -475,7 +475,7 @@ de-duplicating. Sets `--install-strategy=nested`. `--install-strategy=shallow` Only install direct dependencies in the top level `node_modules`, but hoist -on deeper dependendencies. Sets `--install-strategy=shallow`. +on deeper dependencies. Sets `--install-strategy=shallow`. #### `omit` @@ -510,7 +510,7 @@ be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's `peerDependencies` object. -When such and override is performed, a warning is printed, explaining the +When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If `--strict-peer-deps` is set, then this warning is treated as a failure. diff --git a/deps/npm/docs/content/commands/npm-link.md b/deps/npm/docs/content/commands/npm-link.md index 09459cc0ca8a50..9de0ff2c0a59de 100644 --- a/deps/npm/docs/content/commands/npm-link.md +++ b/deps/npm/docs/content/commands/npm-link.md @@ -176,7 +176,7 @@ de-duplicating. Sets `--install-strategy=nested`. `--install-strategy=shallow` Only install direct dependencies in the top level `node_modules`, but hoist -on deeper dependendencies. Sets `--install-strategy=shallow`. +on deeper dependencies. Sets `--install-strategy=shallow`. #### `strict-peer-deps` @@ -193,7 +193,7 @@ be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's `peerDependencies` object. -When such and override is performed, a warning is printed, explaining the +When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If `--strict-peer-deps` is set, then this warning is treated as a failure. diff --git a/deps/npm/docs/content/commands/npm-login.md b/deps/npm/docs/content/commands/npm-login.md index 4feb7150400268..00f10ad95eeb52 100644 --- a/deps/npm/docs/content/commands/npm-login.md +++ b/deps/npm/docs/content/commands/npm-login.md @@ -74,7 +74,8 @@ npm init --scope=@foo --yes * Default: "web" * Type: "legacy" or "web" -What authentication strategy to use with `login`. +What authentication strategy to use with `login`. Note that if an `otp` +config is given, this value will always be set to `legacy`. ### See Also diff --git a/deps/npm/docs/content/commands/npm-ls.md b/deps/npm/docs/content/commands/npm-ls.md index 2ae99e7e7c16e3..d8b6f4a7de63dc 100644 --- a/deps/npm/docs/content/commands/npm-ls.md +++ b/deps/npm/docs/content/commands/npm-ls.md @@ -27,7 +27,7 @@ packages will *also* show the paths to the specified packages. For example, running `npm ls promzard` in npm's source tree will show: ```bash -npm@9.2.0 /path/to/npm +npm@9.3.0 /path/to/npm └─┬ init-package-json@0.0.4 └── promzard@0.1.5 ``` diff --git a/deps/npm/docs/content/commands/npm-owner.md b/deps/npm/docs/content/commands/npm-owner.md index c5bace6b2bcc94..2b04f635b1372b 100644 --- a/deps/npm/docs/content/commands/npm-owner.md +++ b/deps/npm/docs/content/commands/npm-owner.md @@ -14,8 +14,6 @@ npm owner ls alias: author ``` -Note: This command is unaware of workspaces. - ### Description Manage ownership of published packages. diff --git a/deps/npm/docs/content/commands/npm-publish.md b/deps/npm/docs/content/commands/npm-publish.md index 09756aedf02724..b23d9ad8a1fb2a 100644 --- a/deps/npm/docs/content/commands/npm-publish.md +++ b/deps/npm/docs/content/commands/npm-publish.md @@ -107,8 +107,8 @@ tarball that will be compared with the local files by default. current level * Type: null, "restricted", or "public" -If do not want your scoped package to be publicly viewable (and installable) -set `--access=restricted`. +If you do not want your scoped package to be publicly viewable (and +installable) set `--access=restricted`. Unscoped packages can not be set to `restricted`. diff --git a/deps/npm/docs/content/commands/npm-root.md b/deps/npm/docs/content/commands/npm-root.md index 89195744c9d18d..b34321eb961394 100644 --- a/deps/npm/docs/content/commands/npm-root.md +++ b/deps/npm/docs/content/commands/npm-root.md @@ -10,6 +10,8 @@ description: Display npm root npm root ``` +Note: This command is unaware of workspaces. + ### Description Print the effective `node_modules` folder to standard out. diff --git a/deps/npm/docs/content/commands/npm-update.md b/deps/npm/docs/content/commands/npm-update.md index cdd3190828a2cb..16c8e4df66d571 100644 --- a/deps/npm/docs/content/commands/npm-update.md +++ b/deps/npm/docs/content/commands/npm-update.md @@ -215,7 +215,7 @@ de-duplicating. Sets `--install-strategy=nested`. `--install-strategy=shallow` Only install direct dependencies in the top level `node_modules`, but hoist -on deeper dependendencies. Sets `--install-strategy=shallow`. +on deeper dependencies. Sets `--install-strategy=shallow`. #### `omit` @@ -250,7 +250,7 @@ be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's `peerDependencies` object. -When such and override is performed, a warning is printed, explaining the +When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If `--strict-peer-deps` is set, then this warning is treated as a failure. diff --git a/deps/npm/docs/content/commands/npm.md b/deps/npm/docs/content/commands/npm.md index be17431b58f360..2396b40cf5e8c7 100644 --- a/deps/npm/docs/content/commands/npm.md +++ b/deps/npm/docs/content/commands/npm.md @@ -10,9 +10,11 @@ description: javascript package manager npm ``` +Note: This command is unaware of workspaces. + ### Version -9.2.0 +9.3.0 ### Description @@ -132,7 +134,7 @@ npm is extremely configurable. It reads its configuration options from in the cli, env, or user config, then that file is parsed instead. * Defaults: npm's default configuration options are defined in - lib/utils/config-defs.js. These must not be changed. + `lib/utils/config/definitions.js`. These must not be changed. See [`config`](/using-npm/config) for much much more information. diff --git a/deps/npm/docs/content/configuring-npm/install.md b/deps/npm/docs/content/configuring-npm/install.md index 43fce4868ba973..18b4421687ba9a 100644 --- a/deps/npm/docs/content/configuring-npm/install.md +++ b/deps/npm/docs/content/configuring-npm/install.md @@ -17,11 +17,11 @@ run npm packages globally. ### Overview - [Checking your version of npm and - Node.js](#checking-your-version-of-npm-and-node-js) + Node.js](#checking-your-version-of-npm-and-nodejs) - [Using a Node version manager to install Node.js and - npm](#using-a-node-version-manager-to-install-node-js-and-npm) + npm](#using-a-node-version-manager-to-install-nodejs-and-npm) - [Using a Node installer to install Node.js and - npm](#using-a-node-installer-to-install-node-js-and-npm) + npm](#using-a-node-installer-to-install-nodejs-and-npm) ### Checking your version of npm and Node.js diff --git a/deps/npm/docs/content/using-npm/config.md b/deps/npm/docs/content/using-npm/config.md index 0eda3ec5367316..c70f51d13bd381 100644 --- a/deps/npm/docs/content/using-npm/config.md +++ b/deps/npm/docs/content/using-npm/config.md @@ -142,8 +142,8 @@ safer to use a registry-provided authentication bearer token stored in the current level * Type: null, "restricted", or "public" -If do not want your scoped package to be publicly viewable (and installable) -set `--access=restricted`. +If you do not want your scoped package to be publicly viewable (and +installable) set `--access=restricted`. Unscoped packages can not be set to `restricted`. @@ -192,7 +192,8 @@ exit code. * Default: "web" * Type: "legacy" or "web" -What authentication strategy to use with `login`. +What authentication strategy to use with `login`. Note that if an `otp` +config is given, this value will always be set to `legacy`. #### `before` @@ -1240,7 +1241,7 @@ be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's `peerDependencies` object. -When such and override is performed, a warning is printed, explaining the +When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If `--strict-peer-deps` is set, then this warning is treated as a failure. @@ -1521,7 +1522,7 @@ Alias for `--include=dev`. `--install-strategy=shallow` Only install direct dependencies in the top level `node_modules`, but hoist -on deeper dependendencies. Sets `--install-strategy=shallow`. +on deeper dependencies. Sets `--install-strategy=shallow`. #### `init.author.email` diff --git a/deps/npm/docs/content/using-npm/registry.md b/deps/npm/docs/content/using-npm/registry.md index 8d5ac94160b33f..035ede5b32a3a1 100644 --- a/deps/npm/docs/content/using-npm/registry.md +++ b/deps/npm/docs/content/using-npm/registry.md @@ -35,7 +35,7 @@ Authentication configuration such as auth tokens and certificates are configured specifically scoped to an individual registry. See [Auth Related Configuration](/configuring-npm/npmrc#auth-related-configuration) -When the default registry is used in a package-lock or shrinkwrap is has the +When the default registry is used in a package-lock or shrinkwrap it has the special meaning of "the currently configured registry". If you create a lock file while using the default registry you can switch to another registry and npm will install packages from the new registry, but if you create a lock diff --git a/deps/npm/docs/content/using-npm/removal.md b/deps/npm/docs/content/using-npm/removal.md index c5e13b6741b6de..25dbb80baa7a95 100644 --- a/deps/npm/docs/content/using-npm/removal.md +++ b/deps/npm/docs/content/using-npm/removal.md @@ -28,8 +28,8 @@ continue reading. Note that this is only necessary for globally-installed packages. Local installs are completely contained within a project's `node_modules` -folder. Delete that folder, and everything is gone less a package's -install script is particularly ill-behaved). +folder. Delete that folder, and everything is gone unless a package's +install script is particularly ill-behaved. This assumes that you installed node and npm in the default place. If you configured node with a different `--prefix`, or installed npm with a diff --git a/deps/npm/docs/content/using-npm/scripts.md b/deps/npm/docs/content/using-npm/scripts.md index 9bc2bf32fe4ff7..bf212c5db24f77 100644 --- a/deps/npm/docs/content/using-npm/scripts.md +++ b/deps/npm/docs/content/using-npm/scripts.md @@ -63,7 +63,7 @@ situations. These scripts happen in addition to the `pre`, `post`, * Runs BEFORE the package is prepared and packed, ONLY on `npm publish`. **prepack** -* Runs BEFORE a tarball is packed (on "`npm pack`", "`npm publish`", and when installing a git dependencies). +* Runs BEFORE a tarball is packed (on "`npm pack`", "`npm publish`", and when installing a git dependency). * NOTE: "`npm run pack`" is NOT the same as "`npm pack`". "`npm run pack`" is an arbitrary user defined script name, where as, "`npm pack`" is a CLI defined command. **postpack** diff --git a/deps/npm/docs/output/commands/npm-access.html b/deps/npm/docs/output/commands/npm-access.html index 25569aabc1abd5..9a0bb09a9cd966 100644 --- a/deps/npm/docs/output/commands/npm-access.html +++ b/deps/npm/docs/output/commands/npm-access.html @@ -154,6 +154,7 @@

Table of contents

npm access grant <read-only|read-write> <scope:team> [<package>] npm access revoke <scope:team> [<package>] +

Note: This command is unaware of workspaces.

Description

Used to set access controls on private packages.

For all of the subcommands, npm access will perform actions on the packages diff --git a/deps/npm/docs/output/commands/npm-adduser.html b/deps/npm/docs/output/commands/npm-adduser.html index 77cde53f2fd276..e515eaa5adabda 100644 --- a/deps/npm/docs/output/commands/npm-adduser.html +++ b/deps/npm/docs/output/commands/npm-adduser.html @@ -190,7 +190,8 @@

auth-type

  • Default: "web"
  • Type: "legacy" or "web"
  • -

    What authentication strategy to use with login.

    +

    What authentication strategy to use with login. Note that if an otp +config is given, this value will always be set to legacy.

    See Also

    • npm registry
    • diff --git a/deps/npm/docs/output/commands/npm-ci.html b/deps/npm/docs/output/commands/npm-ci.html index 76223e5b47d669..07f07b5630562e 100644 --- a/deps/npm/docs/output/commands/npm-ci.html +++ b/deps/npm/docs/output/commands/npm-ci.html @@ -256,7 +256,7 @@

      global-style

      --install-strategy=shallow

    Only install direct dependencies in the top level node_modules, but hoist -on deeper dependendencies. Sets --install-strategy=shallow.

    +on deeper dependencies. Sets --install-strategy=shallow.

    omit

    • Default: 'dev' if the NODE_ENV environment variable is set to @@ -284,7 +284,7 @@

      strict-peer-deps

      be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's peerDependencies object.

      -

      When such and override is performed, a warning is printed, explaining the +

      When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If --strict-peer-deps is set, then this warning is treated as a failure.

      package-lock

      diff --git a/deps/npm/docs/output/commands/npm-dedupe.html b/deps/npm/docs/output/commands/npm-dedupe.html index fb457d7d41e58b..143398d8d7a27b 100644 --- a/deps/npm/docs/output/commands/npm-dedupe.html +++ b/deps/npm/docs/output/commands/npm-dedupe.html @@ -225,7 +225,7 @@

      global-style

      --install-strategy=shallow

    Only install direct dependencies in the top level node_modules, but hoist -on deeper dependendencies. Sets --install-strategy=shallow.

    +on deeper dependencies. Sets --install-strategy=shallow.

    strict-peer-deps

    • Default: false
    • @@ -239,7 +239,7 @@

      strict-peer-deps

      be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's peerDependencies object.

      -

      When such and override is performed, a warning is printed, explaining the +

      When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If --strict-peer-deps is set, then this warning is treated as a failure.

      package-lock

      diff --git a/deps/npm/docs/output/commands/npm-find-dupes.html b/deps/npm/docs/output/commands/npm-find-dupes.html index d527c5b4f686ba..0dd2bc375069ee 100644 --- a/deps/npm/docs/output/commands/npm-find-dupes.html +++ b/deps/npm/docs/output/commands/npm-find-dupes.html @@ -182,7 +182,7 @@

      global-style

      --install-strategy=shallow

    Only install direct dependencies in the top level node_modules, but hoist -on deeper dependendencies. Sets --install-strategy=shallow.

    +on deeper dependencies. Sets --install-strategy=shallow.

    strict-peer-deps

    • Default: false
    • @@ -196,7 +196,7 @@

      strict-peer-deps

      be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's peerDependencies object.

      -

      When such and override is performed, a warning is printed, explaining the +

      When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If --strict-peer-deps is set, then this warning is treated as a failure.

      package-lock

      diff --git a/deps/npm/docs/output/commands/npm-init.html b/deps/npm/docs/output/commands/npm-init.html index 0f539a6ad44785..e515d36c85d2ea 100644 --- a/deps/npm/docs/output/commands/npm-init.html +++ b/deps/npm/docs/output/commands/npm-init.html @@ -146,7 +146,7 @@

      Table of contents

      Synopsis

      -
      npm init <package-spec> (same as `npx <package-spec>)
      +
      npm init <package-spec> (same as `npx <package-spec>`)
       npm init <@scope> (same as `npx <@scope>/create`)
       
       aliases: create, innit
      diff --git a/deps/npm/docs/output/commands/npm-install-ci-test.html b/deps/npm/docs/output/commands/npm-install-ci-test.html
      index 634d933dc62219..0d3dea5b4cc530 100644
      --- a/deps/npm/docs/output/commands/npm-install-ci-test.html
      +++ b/deps/npm/docs/output/commands/npm-install-ci-test.html
      @@ -213,7 +213,7 @@ 

      global-style

      --install-strategy=shallow

    Only install direct dependencies in the top level node_modules, but hoist -on deeper dependendencies. Sets --install-strategy=shallow.

    +on deeper dependencies. Sets --install-strategy=shallow.

    omit

    • Default: 'dev' if the NODE_ENV environment variable is set to @@ -241,7 +241,7 @@

      strict-peer-deps

      be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's peerDependencies object.

      -

      When such and override is performed, a warning is printed, explaining the +

      When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If --strict-peer-deps is set, then this warning is treated as a failure.

      package-lock

      diff --git a/deps/npm/docs/output/commands/npm-install-test.html b/deps/npm/docs/output/commands/npm-install-test.html index 282d7755f12329..ff53148d4fb09d 100644 --- a/deps/npm/docs/output/commands/npm-install-test.html +++ b/deps/npm/docs/output/commands/npm-install-test.html @@ -214,7 +214,7 @@

      global-style

      --install-strategy=shallow

    Only install direct dependencies in the top level node_modules, but hoist -on deeper dependendencies. Sets --install-strategy=shallow.

    +on deeper dependencies. Sets --install-strategy=shallow.

    omit

    • Default: 'dev' if the NODE_ENV environment variable is set to @@ -242,7 +242,7 @@

      strict-peer-deps

      be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's peerDependencies object.

      -

      When such and override is performed, a warning is printed, explaining the +

      When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If --strict-peer-deps is set, then this warning is treated as a failure.

      package-lock

      diff --git a/deps/npm/docs/output/commands/npm-install.html b/deps/npm/docs/output/commands/npm-install.html index 83be6e751e6c34..40dc5d32b3d746 100644 --- a/deps/npm/docs/output/commands/npm-install.html +++ b/deps/npm/docs/output/commands/npm-install.html @@ -540,7 +540,7 @@

      global-style

      --install-strategy=shallow

    Only install direct dependencies in the top level node_modules, but hoist -on deeper dependendencies. Sets --install-strategy=shallow.

    +on deeper dependencies. Sets --install-strategy=shallow.

    omit

    • Default: 'dev' if the NODE_ENV environment variable is set to @@ -568,7 +568,7 @@

      strict-peer-deps

      be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's peerDependencies object.

      -

      When such and override is performed, a warning is printed, explaining the +

      When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If --strict-peer-deps is set, then this warning is treated as a failure.

      package-lock

      diff --git a/deps/npm/docs/output/commands/npm-link.html b/deps/npm/docs/output/commands/npm-link.html index bf6e7f9a2f9348..d23f83826aa9d7 100644 --- a/deps/npm/docs/output/commands/npm-link.html +++ b/deps/npm/docs/output/commands/npm-link.html @@ -277,7 +277,7 @@

      global-style

      --install-strategy=shallow

    Only install direct dependencies in the top level node_modules, but hoist -on deeper dependendencies. Sets --install-strategy=shallow.

    +on deeper dependencies. Sets --install-strategy=shallow.

    strict-peer-deps

    • Default: false
    • @@ -291,7 +291,7 @@

      strict-peer-deps

      be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's peerDependencies object.

      -

      When such and override is performed, a warning is printed, explaining the +

      When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If --strict-peer-deps is set, then this warning is treated as a failure.

      package-lock

      diff --git a/deps/npm/docs/output/commands/npm-login.html b/deps/npm/docs/output/commands/npm-login.html index 8b47a64c8e8cbb..5ffff8aa627168 100644 --- a/deps/npm/docs/output/commands/npm-login.html +++ b/deps/npm/docs/output/commands/npm-login.html @@ -194,7 +194,8 @@

      auth-type

    • Default: "web"
    • Type: "legacy" or "web"
    -

    What authentication strategy to use with login.

    +

    What authentication strategy to use with login. Note that if an otp +config is given, this value will always be set to legacy.

    See Also

    • npm registry
    • diff --git a/deps/npm/docs/output/commands/npm-ls.html b/deps/npm/docs/output/commands/npm-ls.html index 6ec045612fa513..ffe72db7c54b8c 100644 --- a/deps/npm/docs/output/commands/npm-ls.html +++ b/deps/npm/docs/output/commands/npm-ls.html @@ -160,7 +160,7 @@

      Description

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

      -
      npm@9.2.0 /path/to/npm
      +
      npm@9.3.0 /path/to/npm
       └─┬ init-package-json@0.0.4
         └── promzard@0.1.5
       
      diff --git a/deps/npm/docs/output/commands/npm-owner.html b/deps/npm/docs/output/commands/npm-owner.html index 13cf1d2209dfb3..3566602a011109 100644 --- a/deps/npm/docs/output/commands/npm-owner.html +++ b/deps/npm/docs/output/commands/npm-owner.html @@ -152,7 +152,6 @@

      Table of contents

      alias: author
      -

      Note: This command is unaware of workspaces.

      Description

      Manage ownership of published packages.

        diff --git a/deps/npm/docs/output/commands/npm-publish.html b/deps/npm/docs/output/commands/npm-publish.html index 864a03a5cbb0a8..80a136308a19c5 100644 --- a/deps/npm/docs/output/commands/npm-publish.html +++ b/deps/npm/docs/output/commands/npm-publish.html @@ -235,8 +235,8 @@

        access

        current level
      • Type: null, "restricted", or "public"
      -

      If do not want your scoped package to be publicly viewable (and installable) -set --access=restricted.

      +

      If you do not want your scoped package to be publicly viewable (and +installable) set --access=restricted.

      Unscoped packages can not be set to restricted.

      Note: This defaults to not changing the current access level for existing packages. Specifying a value of restricted or public during publish will diff --git a/deps/npm/docs/output/commands/npm-root.html b/deps/npm/docs/output/commands/npm-root.html index 292376737f4ba9..24436056c97676 100644 --- a/deps/npm/docs/output/commands/npm-root.html +++ b/deps/npm/docs/output/commands/npm-root.html @@ -148,6 +148,7 @@

      Table of contents

      Synopsis

      npm root
       
      +

      Note: This command is unaware of workspaces.

      Description

      Print the effective node_modules folder to standard out.

      Useful for using npm in shell scripts that do things with the diff --git a/deps/npm/docs/output/commands/npm-update.html b/deps/npm/docs/output/commands/npm-update.html index fbb1e8c133054b..162eb4fe54b99e 100644 --- a/deps/npm/docs/output/commands/npm-update.html +++ b/deps/npm/docs/output/commands/npm-update.html @@ -304,7 +304,7 @@

      global-style

      --install-strategy=shallow

    Only install direct dependencies in the top level node_modules, but hoist -on deeper dependendencies. Sets --install-strategy=shallow.

    +on deeper dependencies. Sets --install-strategy=shallow.

    omit

    • Default: 'dev' if the NODE_ENV environment variable is set to @@ -332,7 +332,7 @@

      strict-peer-deps

      be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's peerDependencies object.

      -

      When such and override is performed, a warning is printed, explaining the +

      When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If --strict-peer-deps is set, then this warning is treated as a failure.

      package-lock

      diff --git a/deps/npm/docs/output/commands/npm.html b/deps/npm/docs/output/commands/npm.html index 94fb3e216804cd..cb6d4ea3c7b81e 100644 --- a/deps/npm/docs/output/commands/npm.html +++ b/deps/npm/docs/output/commands/npm.html @@ -148,8 +148,9 @@

      Table of contents

      Synopsis

      npm
       
      +

      Note: This command is unaware of workspaces.

      Version

      -

      9.2.0

      +

      9.3.0

      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 @@ -247,7 +248,7 @@

      Configuration

      in the cli, env, or user config, then that file is parsed instead.
    • Defaults: npm's default configuration options are defined in -lib/utils/config-defs.js. These must not be changed.
    • +lib/utils/config/definitions.js. These must not be changed.

    See config for much much more information.

    Contributions

    diff --git a/deps/npm/docs/output/configuring-npm/install.html b/deps/npm/docs/output/configuring-npm/install.html index b5aabb23b11ae5..7acebd7fda9950 100644 --- a/deps/npm/docs/output/configuring-npm/install.html +++ b/deps/npm/docs/output/configuring-npm/install.html @@ -155,11 +155,11 @@

    Table of contents

    run npm packages globally.

    Overview

    Checking your version of npm and Node.js

    diff --git a/deps/npm/docs/output/using-npm/config.html b/deps/npm/docs/output/using-npm/config.html index 0a31adb6c46a0d..35bc3529efaeef 100644 --- a/deps/npm/docs/output/using-npm/config.html +++ b/deps/npm/docs/output/using-npm/config.html @@ -261,8 +261,8 @@

    access

    current level
  • Type: null, "restricted", or "public"
  • -

    If do not want your scoped package to be publicly viewable (and installable) -set --access=restricted.

    +

    If you do not want your scoped package to be publicly viewable (and +installable) set --access=restricted.

    Unscoped packages can not be set to restricted.

    Note: This defaults to not changing the current access level for existing packages. Specifying a value of restricted or public during publish will @@ -303,7 +303,8 @@

    auth-type

  • Default: "web"
  • Type: "legacy" or "web"
  • -

    What authentication strategy to use with login.

    +

    What authentication strategy to use with login. Note that if an otp +config is given, this value will always be set to legacy.

    before

    • Default: null
    • @@ -1181,7 +1182,7 @@

      strict-peer-deps

      be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's peerDependencies object.

      -

      When such and override is performed, a warning is printed, explaining the +

      When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If --strict-peer-deps is set, then this warning is treated as a failure.

      strict-ssl

      @@ -1420,7 +1421,7 @@

      global-style

      --install-strategy=shallow

    Only install direct dependencies in the top level node_modules, but hoist -on deeper dependendencies. Sets --install-strategy=shallow.

    +on deeper dependencies. Sets --install-strategy=shallow.

    init.author.email

    • Default: ""
    • diff --git a/deps/npm/docs/output/using-npm/registry.html b/deps/npm/docs/output/using-npm/registry.html index 0d04f4dd821065..8ff40109fe0a64 100644 --- a/deps/npm/docs/output/using-npm/registry.html +++ b/deps/npm/docs/output/using-npm/registry.html @@ -169,7 +169,7 @@

      Table of contents

      Authentication configuration such as auth tokens and certificates are configured specifically scoped to an individual registry. See Auth Related Configuration

      -

      When the default registry is used in a package-lock or shrinkwrap is has the +

      When the default registry is used in a package-lock or shrinkwrap it has the special meaning of "the currently configured registry". If you create a lock file while using the default registry you can switch to another registry and npm will install packages from the new registry, but if you create a lock diff --git a/deps/npm/docs/output/using-npm/removal.html b/deps/npm/docs/output/using-npm/removal.html index 7e9af7040bb2bf..e54187122e1f71 100644 --- a/deps/npm/docs/output/using-npm/removal.html +++ b/deps/npm/docs/output/using-npm/removal.html @@ -159,8 +159,8 @@

      More Severe Uninstalling

      continue reading.

      Note that this is only necessary for globally-installed packages. Local installs are completely contained within a project's node_modules -folder. Delete that folder, and everything is gone less a package's -install script is particularly ill-behaved).

      +folder. Delete that folder, and everything is gone unless a package's +install script is particularly ill-behaved.

      This assumes that you installed node and npm in the default place. If you configured node with a different --prefix, or installed npm with a different prefix setting, then adjust the paths accordingly, replacing diff --git a/deps/npm/docs/output/using-npm/scripts.html b/deps/npm/docs/output/using-npm/scripts.html index 79e14dc027ead0..6cc14bff7aeabe 100644 --- a/deps/npm/docs/output/using-npm/scripts.html +++ b/deps/npm/docs/output/using-npm/scripts.html @@ -208,7 +208,7 @@

      Life Cycle Scripts

    prepack

      -
    • Runs BEFORE a tarball is packed (on "npm pack", "npm publish", and when installing a git dependencies).
    • +
    • Runs BEFORE a tarball is packed (on "npm pack", "npm publish", and when installing a git dependency).
    • NOTE: "npm run pack" is NOT the same as "npm pack". "npm run pack" is an arbitrary user defined script name, where as, "npm pack" is a CLI defined command.

    postpack

    diff --git a/deps/npm/lib/arborist-cmd.js b/deps/npm/lib/arborist-cmd.js index 29efe984d9b26d..42699ece364ad1 100644 --- a/deps/npm/lib/arborist-cmd.js +++ b/deps/npm/lib/arborist-cmd.js @@ -17,22 +17,35 @@ class ArboristCmd extends BaseCommand { 'install-links', ] + static workspaces = true static ignoreImplicitWorkspace = false constructor (npm) { super(npm) - if (this.npm.config.isDefault('audit') - && (this.npm.global || this.npm.config.get('location') !== 'project') - ) { - this.npm.config.set('audit', false) - } else if (this.npm.global && this.npm.config.get('audit')) { - log.warn('config', - 'includes both --global and --audit, which is currently unsupported.') + + const { config } = this.npm + + // when location isn't set and global isn't true check for a package.json at + // the localPrefix and set the location to project if found + const locationProject = config.get('location') === 'project' || ( + config.isDefault('location') + // this is different then `npm.global` which falls back to checking + // location which we do not want to use here + && !config.get('global') + && npm.localPackage + ) + + // if audit is not set and we are in global mode and location is not project + // and we assume its not a project related context, then we set audit=false + if (config.isDefault('audit') && (this.npm.global || !locationProject)) { + config.set('audit', false) + } else if (this.npm.global && config.get('audit')) { + log.warn('config', 'includes both --global and --audit, which is currently unsupported.') } } - async execWorkspaces (args, filters) { - await this.setWorkspaces(filters) + async execWorkspaces (args) { + await this.setWorkspaces() return this.exec(args) } } diff --git a/deps/npm/lib/base-command.js b/deps/npm/lib/base-command.js index b57b7474a5efb0..0adff8e5d95ea8 100644 --- a/deps/npm/lib/base-command.js +++ b/deps/npm/lib/base-command.js @@ -8,12 +8,21 @@ const getWorkspaces = require('./workspaces/get-workspaces.js') const cmdAliases = require('./utils/cmd-list').aliases class BaseCommand { + static workspaces = false + static ignoreImplicitWorkspace = true + constructor (npm) { this.wrapWidth = 80 this.npm = npm - if (!this.skipConfigValidation) { - this.npm.config.validate() + const { config } = this.npm + + if (!this.constructor.skipConfigValidation) { + config.validate() + } + + if (config.get('workspaces') === false && config.get('workspace').length) { + throw new Error('Can not use --no-workspaces and --workspace at the same time') } } @@ -25,35 +34,31 @@ class BaseCommand { return this.constructor.description } - get ignoreImplicitWorkspace () { - return this.constructor.ignoreImplicitWorkspace - } - - get skipConfigValidation () { - return this.constructor.skipConfigValidation + get params () { + return this.constructor.params } get usage () { const usage = [ - `${this.constructor.description}`, + `${this.description}`, '', 'Usage:', ] if (!this.constructor.usage) { - usage.push(`npm ${this.constructor.name}`) + usage.push(`npm ${this.name}`) } else { - usage.push(...this.constructor.usage.map(u => `npm ${this.constructor.name} ${u}`)) + usage.push(...this.constructor.usage.map(u => `npm ${this.name} ${u}`)) } - if (this.constructor.params) { + if (this.params) { usage.push('') usage.push('Options:') usage.push(this.wrappedParams) } const aliases = Object.keys(cmdAliases).reduce((p, c) => { - if (cmdAliases[c] === this.constructor.name) { + if (cmdAliases[c] === this.name) { p.push(c) } return p @@ -68,7 +73,7 @@ class BaseCommand { } usage.push('') - usage.push(`Run "npm help ${this.constructor.name}" for more info`) + usage.push(`Run "npm help ${this.name}" for more info`) return usage.join('\n') } @@ -77,7 +82,7 @@ class BaseCommand { let results = '' let line = '' - for (const param of this.constructor.params) { + for (const param of this.params) { const usage = `[${ConfigDefinitions[param].usage}]` if (line.length && line.length + usage.length > this.wrapWidth) { results = [results, line].filter(Boolean).join('\n') @@ -98,26 +103,48 @@ class BaseCommand { }) } - async execWorkspaces (args, filters) { - throw Object.assign(new Error('This command does not support workspaces.'), { - code: 'ENOWORKSPACES', - }) - } + async cmdExec (args) { + const { config } = this.npm - async setWorkspaces (filters) { - if (this.isArboristCmd) { - this.includeWorkspaceRoot = false + if (config.get('usage')) { + return this.npm.output(this.usage) } - const relativeFrom = relative(this.npm.localPrefix, process.cwd()).startsWith('..') - ? this.npm.localPrefix - : process.cwd() + const hasWsConfig = config.get('workspaces') || config.get('workspace').length + // if cwd is a workspace, the default is set to [that workspace] + const implicitWs = config.get('workspace', 'default').length + // (-ws || -w foo) && (cwd is not a workspace || command is not ignoring implicit workspaces) + if (hasWsConfig && (!implicitWs || !this.constructor.ignoreImplicitWorkspace)) { + if (this.npm.global) { + throw new Error('Workspaces not supported for global packages') + } + if (!this.constructor.workspaces) { + throw Object.assign(new Error('This command does not support workspaces.'), { + code: 'ENOWORKSPACES', + }) + } + return this.execWorkspaces(args) + } + + return this.exec(args) + } + + async setWorkspaces () { + const includeWorkspaceRoot = this.isArboristCmd + ? false + : this.npm.config.get('include-workspace-root') + + const prefixInsideCwd = relative(this.npm.localPrefix, process.cwd()).startsWith('..') + const relativeFrom = prefixInsideCwd ? this.npm.localPrefix : process.cwd() + + const filters = this.npm.config.get('workspace') const ws = await getWorkspaces(filters, { path: this.npm.localPrefix, - includeWorkspaceRoot: this.includeWorkspaceRoot, + includeWorkspaceRoot, relativeFrom, }) + this.workspaces = ws this.workspaceNames = [...ws.keys()] this.workspacePaths = [...ws.values()] diff --git a/deps/npm/lib/cli.js b/deps/npm/lib/cli.js index 9aaf6c593675af..007778aa4b9866 100644 --- a/deps/npm/lib/cli.js +++ b/deps/npm/lib/cli.js @@ -68,6 +68,11 @@ module.exports = async process => { // leak any private CLI configs to other programs process.title = 'npm' + // if npm is called as "npmg" or "npm_g", then run in global mode. + if (process.argv[1][process.argv[1].length - 1] === 'g') { + process.argv.splice(1, 1, 'npm', '-g') + } + // Nothing should happen before this line if we can't guarantee it will // not have syntax errors in some version of node const validateEngines = createEnginesValidation() @@ -78,11 +83,6 @@ module.exports = async process => { const npm = new Npm() exitHandler.setNpm(npm) - // if npm is called as "npmg" or "npm_g", then run in global mode. - if (process.argv[1][process.argv[1].length - 1] === 'g') { - process.argv.splice(1, 1, 'npm', '-g') - } - // only log node and npm paths in argv initially since argv can contain // sensitive info. a cleaned version will be logged later const log = require('./utils/log-shim.js') @@ -112,6 +112,7 @@ module.exports = async process => { // this is how to use npm programmatically: try { await npm.load() + if (npm.config.get('version', 'cli')) { npm.output(npm.version) return exitHandler() @@ -130,7 +131,7 @@ module.exports = async process => { return exitHandler() } - await npm.exec(cmd, npm.argv) + await npm.exec(cmd) return exitHandler() } catch (err) { if (err.code === 'EUNKNOWNCOMMAND') { diff --git a/deps/npm/lib/commands/access.js b/deps/npm/lib/commands/access.js index d5ac5bb2f008e7..23e51f071b1124 100644 --- a/deps/npm/lib/commands/access.js +++ b/deps/npm/lib/commands/access.js @@ -37,8 +37,6 @@ class Access extends BaseCommand { 'registry', ] - static ignoreImplicitWorkspace = true - static usage = [ 'list packages [|| []', 'list collaborators [ []]', diff --git a/deps/npm/lib/commands/adduser.js b/deps/npm/lib/commands/adduser.js index 1e92b35f4a6623..cd4cba60511cb6 100644 --- a/deps/npm/lib/commands/adduser.js +++ b/deps/npm/lib/commands/adduser.js @@ -13,8 +13,6 @@ class AddUser extends BaseCommand { 'auth-type', ] - static ignoreImplicitWorkspace = true - async exec (args) { const scope = this.npm.config.get('scope') let registry = this.npm.config.get('registry') diff --git a/deps/npm/lib/commands/audit.js b/deps/npm/lib/commands/audit.js index feccefda0c9049..13886ea6350b66 100644 --- a/deps/npm/lib/commands/audit.js +++ b/deps/npm/lib/commands/audit.js @@ -152,7 +152,7 @@ class VerifySignatures { const keys = await fetch.json('/-/npm/v1/keys', { ...this.npm.flatOptions, registry, - }).then(({ keys }) => keys.map((key) => ({ + }).then(({ keys: ks }) => ks.map((key) => ({ ...key, pemkey: `-----BEGIN PUBLIC KEY-----\n${key.key}\n-----END PUBLIC KEY-----`, }))).catch(err => { diff --git a/deps/npm/lib/commands/cache.js b/deps/npm/lib/commands/cache.js index a2e6434b34cab5..0ab40b9ed44a9f 100644 --- a/deps/npm/lib/commands/cache.js +++ b/deps/npm/lib/commands/cache.js @@ -1,9 +1,8 @@ const cacache = require('cacache') const Arborist = require('@npmcli/arborist') -const { promisify } = require('util') const pacote = require('pacote') -const path = require('path') -const rimraf = promisify(require('rimraf')) +const fs = require('fs/promises') +const { join } = require('path') const semver = require('semver') const BaseCommand = require('../base-command.js') const npa = require('npm-package-arg') @@ -75,8 +74,6 @@ class Cache extends BaseCommand { 'verify', ] - static ignoreImplicitWorkspace = true - async completion (opts) { const argv = opts.conf.argv.remain if (argv.length === 2) { @@ -112,7 +109,7 @@ class Cache extends BaseCommand { // npm cache clean [pkg]* async clean (args) { - const cachePath = path.join(this.npm.cache, '_cacache') + const cachePath = join(this.npm.cache, '_cacache') if (args.length === 0) { if (!this.npm.config.get('force')) { throw new Error(`As of npm@5, the npm cache self-heals from corruption issues @@ -130,7 +127,7 @@ class Cache extends BaseCommand { If you're sure you want to delete the entire cache, rerun this command with --force.`) } - return rimraf(cachePath) + return fs.rm(cachePath, { recursive: true, force: true }) } for (const key of args) { let entry @@ -170,7 +167,7 @@ class Cache extends BaseCommand { } async verify () { - const cache = path.join(this.npm.cache, '_cacache') + const cache = join(this.npm.cache, '_cacache') const prefix = cache.indexOf(process.env.HOME) === 0 ? `~${cache.slice(process.env.HOME.length)}` : cache @@ -193,7 +190,7 @@ class Cache extends BaseCommand { // npm cache ls [--package ...] async ls (specs) { - const cachePath = path.join(this.npm.cache, '_cacache') + const cachePath = join(this.npm.cache, '_cacache') const cacheKeys = Object.keys(await cacache.ls(cachePath)) if (specs.length > 0) { // get results for each package spec specified diff --git a/deps/npm/lib/commands/ci.js b/deps/npm/lib/commands/ci.js index 38ee1426d982ab..a2c61044eb96ee 100644 --- a/deps/npm/lib/commands/ci.js +++ b/deps/npm/lib/commands/ci.js @@ -1,10 +1,7 @@ -const util = require('util') const Arborist = require('@npmcli/arborist') -const rimraf = util.promisify(require('rimraf')) const reifyFinish = require('../utils/reify-finish.js') const runScript = require('@npmcli/run-script') -const fs = require('fs') -const readdir = util.promisify(fs.readdir) +const fs = require('fs/promises') const log = require('../utils/log-shim.js') const validateLockfile = require('../utils/validate-lockfile.js') @@ -69,8 +66,8 @@ class CI extends ArboristWorkspaceCmd { await this.npm.time('npm-ci:rm', async () => { const path = `${where}/node_modules` // get the list of entries so we can skip the glob for performance - const entries = await readdir(path, null).catch(er => []) - return Promise.all(entries.map(f => rimraf(`${path}/${f}`, { glob: false }))) + const entries = await fs.readdir(path, null).catch(er => []) + return Promise.all(entries.map(f => fs.rm(`${path}/${f}`, { force: true }))) }) await arb.reify(opts) diff --git a/deps/npm/lib/commands/completion.js b/deps/npm/lib/commands/completion.js index 8fc05b2e82313d..f5604e099f9a27 100644 --- a/deps/npm/lib/commands/completion.js +++ b/deps/npm/lib/commands/completion.js @@ -31,6 +31,7 @@ const fs = require('fs/promises') const nopt = require('nopt') +const { resolve } = require('path') const { definitions, shorthands } = require('../utils/config/index.js') const { aliases, commands, plumbing } = require('../utils/cmd-list.js') @@ -40,21 +41,13 @@ const configNames = Object.keys(definitions) const shorthandNames = Object.keys(shorthands) const allConfs = configNames.concat(shorthandNames) const { isWindowsShell } = require('../utils/is-windows.js') -const fileExists = async (file) => { - try { - const stat = await fs.stat(file) - return stat.isFile() - } catch { - return false - } -} +const fileExists = (file) => fs.stat(file).then(s => s.isFile()).catch(() => false) const BaseCommand = require('../base-command.js') class Completion extends BaseCommand { static description = 'Tab Completion for npm' static name = 'completion' - static ignoreImplicitWorkspace = true // completion for the completion command async completion (opts) { @@ -62,7 +55,6 @@ class Completion extends BaseCommand { return } - const { resolve } = require('path') const [bashExists, zshExists] = await Promise.all([ fileExists(resolve(process.env.HOME, '.bashrc')), fileExists(resolve(process.env.HOME, '.zshrc')), @@ -93,7 +85,7 @@ class Completion extends BaseCommand { if (COMP_CWORD === undefined || COMP_LINE === undefined || COMP_POINT === undefined) { - return dumpScript() + return dumpScript(resolve(this.npm.npmRoot, 'lib', 'utils', 'completion.sh')) } // ok we're actually looking at the envs and outputting the suggestions @@ -150,9 +142,9 @@ class Completion extends BaseCommand { // take a little shortcut and use npm's arg parsing logic. // don't have to worry about the last arg being implicitly // boolean'ed, since the last block will catch that. - const types = Object.entries(definitions).reduce((types, [key, def]) => { - types[key] = def.type - return types + const types = Object.entries(definitions).reduce((acc, [key, def]) => { + acc[key] = def.type + return acc }, {}) const parsed = opts.conf = nopt(types, shorthands, partialWords.slice(0, -1), 0) @@ -196,10 +188,7 @@ class Completion extends BaseCommand { } } -const dumpScript = async () => { - const { resolve } = require('path') - const p = resolve(__dirname, '..', 'utils', 'completion.sh') - +const dumpScript = async (p) => { const d = (await fs.readFile(p, 'utf8')).replace(/^#!.*?\n/, '') await new Promise((res, rej) => { let done = false diff --git a/deps/npm/lib/commands/config.js b/deps/npm/lib/commands/config.js index 103fbb554e5d1d..ac5a74d01f7de2 100644 --- a/deps/npm/lib/commands/config.js +++ b/deps/npm/lib/commands/config.js @@ -112,11 +112,6 @@ class Config extends BaseCommand { } } - async execWorkspaces (args, filters) { - log.warn('config', 'This command does not support workspaces.') - return this.exec(args) - } - async exec ([action, ...args]) { log.disableProgress() try { @@ -251,14 +246,14 @@ ${defData} `.split('\n').join(EOL) await mkdir(dirname(file), { recursive: true }) await writeFile(file, tmpData, 'utf8') - await new Promise((resolve, reject) => { + await new Promise((res, rej) => { const [bin, ...args] = e.split(/\s+/) const editor = spawn(bin, [...args, file], { stdio: 'inherit' }) editor.on('exit', (code) => { if (code) { - return reject(new Error(`editor process exited with code: ${code}`)) + return rej(new Error(`editor process exited with code: ${code}`)) } - return resolve() + return res() }) }) } diff --git a/deps/npm/lib/commands/diff.js b/deps/npm/lib/commands/diff.js index c8fd734918d75e..1f4bfd3eb11512 100644 --- a/deps/npm/lib/commands/diff.js +++ b/deps/npm/lib/commands/diff.js @@ -32,6 +32,7 @@ class Diff extends BaseCommand { 'include-workspace-root', ] + static workspaces = true static ignoreImplicitWorkspace = false async exec (args) { @@ -67,8 +68,8 @@ class Diff extends BaseCommand { return this.npm.output(res) } - async execWorkspaces (args, filters) { - await this.setWorkspaces(filters) + async execWorkspaces (args) { + await this.setWorkspaces() for (const workspacePath of this.workspacePaths) { this.top = workspacePath this.prefix = workspacePath diff --git a/deps/npm/lib/commands/dist-tag.js b/deps/npm/lib/commands/dist-tag.js index 8052e4f7e4e38c..bc61a4691e55a0 100644 --- a/deps/npm/lib/commands/dist-tag.js +++ b/deps/npm/lib/commands/dist-tag.js @@ -17,6 +17,7 @@ class DistTag extends BaseCommand { 'ls []', ] + static workspaces = true static ignoreImplicitWorkspace = false async completion (opts) { @@ -57,14 +58,14 @@ class DistTag extends BaseCommand { } } - async execWorkspaces ([cmdName, pkg, tag], filters) { + async execWorkspaces ([cmdName, pkg, tag]) { // cmdName is some form of list // pkg is one of: // - unset // - . // - .@version if (['ls', 'l', 'sl', 'list'].includes(cmdName) && (!pkg || pkg === '.' || /^\.@/.test(pkg))) { - return this.listWorkspaces(filters) + return this.listWorkspaces() } // pkg is unset @@ -73,12 +74,12 @@ class DistTag extends BaseCommand { // - . // - .@version if (!pkg && (!cmdName || cmdName === '.' || /^\.@/.test(cmdName))) { - return this.listWorkspaces(filters) + return this.listWorkspaces() } // anything else is just a regular dist-tag command // so we fallback to the non-workspaces implementation - log.warn('Ignoring workspaces for specified package') + log.warn('dist-tag', 'Ignoring workspaces for specified package') return this.exec([cmdName, pkg, tag]) } @@ -116,7 +117,7 @@ class DistTag extends BaseCommand { }, spec, } - await otplease(this.npm, reqOpts, reqOpts => regFetch(url, reqOpts)) + await otplease(this.npm, reqOpts, o => regFetch(url, o)) this.npm.output(`+${t}: ${spec.name}@${version}`) } @@ -142,7 +143,7 @@ class DistTag extends BaseCommand { method: 'DELETE', spec, } - await otplease(this.npm, reqOpts, reqOpts => regFetch(url, reqOpts)) + await otplease(this.npm, reqOpts, o => regFetch(url, o)) this.npm.output(`-${tag}: ${spec.name}@${version}`) } @@ -172,8 +173,8 @@ class DistTag extends BaseCommand { } } - async listWorkspaces (filters) { - await this.setWorkspaces(filters) + async listWorkspaces () { + await this.setWorkspaces() for (const name of this.workspaceNames) { try { diff --git a/deps/npm/lib/commands/edit.js b/deps/npm/lib/commands/edit.js index 67ac32e0171843..a671a5d6bad5d6 100644 --- a/deps/npm/lib/commands/edit.js +++ b/deps/npm/lib/commands/edit.js @@ -51,23 +51,23 @@ class Edit extends BaseCommand { const dir = resolve(this.npm.dir, path) // graceful-fs does not promisify - await new Promise((resolve, reject) => { + await new Promise((res, rej) => { fs.lstat(dir, (err) => { if (err) { - return reject(err) + return rej(err) } - const [bin, ...args] = this.npm.config.get('editor').split(/\s+/) - const editor = cp.spawn(bin, [...args, dir], { stdio: 'inherit' }) + const [bin, ...spawnArgs] = this.npm.config.get('editor').split(/\s+/) + const editor = cp.spawn(bin, [...spawnArgs, dir], { stdio: 'inherit' }) editor.on('exit', async (code) => { if (code) { - return reject(new Error(`editor process exited with code: ${code}`)) + return rej(new Error(`editor process exited with code: ${code}`)) } try { await this.npm.exec('rebuild', [dir]) - } catch (err) { - reject(err) + } catch (execErr) { + rej(execErr) } - resolve() + res() }) }) }) diff --git a/deps/npm/lib/commands/exec.js b/deps/npm/lib/commands/exec.js index a77a6326c00f28..a5235c7845851b 100644 --- a/deps/npm/lib/commands/exec.js +++ b/deps/npm/lib/commands/exec.js @@ -1,4 +1,4 @@ -const path = require('path') +const { resolve } = require('path') const libexec = require('libnpmexec') const BaseCommand = require('../base-command.js') @@ -20,10 +20,25 @@ class Exec extends BaseCommand { '--package=foo -c \' [args...]\'', ] + static workspaces = true static ignoreImplicitWorkspace = false static isShellout = true - async exec (_args, { locationMsg, runPath } = {}) { + async exec (args) { + return this.callExec(args) + } + + async execWorkspaces (args) { + await this.setWorkspaces() + + for (const [name, path] of this.workspaces) { + const locationMsg = + `in workspace ${this.npm.chalk.green(name)} at location:\n${this.npm.chalk.dim(path)}` + await this.callExec(args, { locationMsg, runPath: path }) + } + } + + async callExec (args, { locationMsg, runPath } = {}) { // This is where libnpmexec will look for locally installed packages const localPrefix = this.npm.localPrefix @@ -32,7 +47,6 @@ class Exec extends BaseCommand { runPath = process.cwd() } - const args = [..._args] const call = this.npm.config.get('call') let globalPath const { @@ -49,10 +63,10 @@ class Exec extends BaseCommand { // is invalid (i.e. no lib/node_modules). This is not a trivial thing to // untangle and fix so we work around it here. if (this.npm.localPrefix !== this.npm.globalPrefix) { - globalPath = path.resolve(globalDir, '..') + globalPath = resolve(globalDir, '..') } - if (call && _args.length) { + if (call && args.length) { throw this.usageError() } @@ -61,7 +75,8 @@ class Exec extends BaseCommand { // we explicitly set packageLockOnly to false because if it's true // when we try to install a missing package, we won't actually install it packageLockOnly: false, - args, + // copy args so they dont get mutated + args: [...args], call, localBin, locationMsg, @@ -75,16 +90,6 @@ class Exec extends BaseCommand { yes, }) } - - async execWorkspaces (args, filters) { - await this.setWorkspaces(filters) - - for (const [name, path] of this.workspaces) { - const locationMsg = - `in workspace ${this.npm.chalk.green(name)} at location:\n${this.npm.chalk.dim(path)}` - await this.exec(args, { locationMsg, runPath: path }) - } - } } module.exports = Exec diff --git a/deps/npm/lib/commands/find-dupes.js b/deps/npm/lib/commands/find-dupes.js index b99ea7a14eb211..b1a31208603663 100644 --- a/deps/npm/lib/commands/find-dupes.js +++ b/deps/npm/lib/commands/find-dupes.js @@ -18,7 +18,7 @@ class FindDupes extends ArboristWorkspaceCmd { ...super.params, ] - async exec (args, cb) { + async exec (args) { this.npm.config.set('dry-run', true) return this.npm.exec('dedupe', []) } diff --git a/deps/npm/lib/commands/fund.js b/deps/npm/lib/commands/fund.js index 9690cbc32e0792..12762533c123e6 100644 --- a/deps/npm/lib/commands/fund.js +++ b/deps/npm/lib/commands/fund.js @@ -16,12 +16,27 @@ const getPrintableName = ({ name, version }) => { return `${name}${printableVersion}` } +const errCode = (msg, code) => Object.assign(new Error(msg), { code }) + class Fund extends ArboristWorkspaceCmd { static description = 'Retrieve funding information' static name = 'fund' static params = ['json', 'browser', 'unicode', 'workspace', 'which'] static usage = ['[]'] + // XXX: maybe worth making this generic for all commands? + usageMessage (paramsObj = {}) { + let msg = `\`npm ${this.constructor.name}` + const params = Object.entries(paramsObj) + if (params.length) { + msg += ` ${this.constructor.usage}` + } + for (const [key, value] of params) { + msg += ` --${key}=${value}` + } + return `${msg}\`` + } + // TODO /* istanbul ignore next */ async completion (opts) { @@ -30,25 +45,23 @@ class Fund extends ArboristWorkspaceCmd { async exec (args) { const spec = args[0] - const numberArg = this.npm.config.get('which') - const fundingSourceNumber = numberArg && parseInt(numberArg, 10) - - const badFundingSourceNumber = - numberArg !== null && (String(fundingSourceNumber) !== numberArg || fundingSourceNumber < 1) - - if (badFundingSourceNumber) { - const err = new Error( - '`npm fund [<@scope>/] [--which=fundingSourceNumber]` must be given a positive integer' - ) - err.code = 'EFUNDNUMBER' - throw err + let fundingSourceNumber = this.npm.config.get('which') + if (fundingSourceNumber != null) { + fundingSourceNumber = parseInt(fundingSourceNumber, 10) + if (isNaN(fundingSourceNumber) || fundingSourceNumber < 1) { + throw errCode( + `${this.usageMessage({ which: 'fundingSourceNumber' })} must be given a positive integer`, + 'EFUNDNUMBER' + ) + } } if (this.npm.global) { - const err = new Error('`npm fund` does not support global packages') - err.code = 'EFUNDGLOBAL' - throw err + throw errCode( + `${this.usageMessage()} does not support global packages`, + 'EFUNDGLOBAL' + ) } const where = this.npm.prefix @@ -146,6 +159,7 @@ class Fund extends ArboristWorkspaceCmd { async openFundingUrl ({ path, tree, spec, fundingSourceNumber }) { const arg = npa(spec, path) + const retrievePackageMetadata = () => { if (arg.type === 'directory') { if (tree.path === arg.fetchSpec) { @@ -178,32 +192,35 @@ class Fund extends ArboristWorkspaceCmd { const validSources = [].concat(normalizeFunding(funding)).filter(isValidFunding) - const matchesValidSource = - validSources.length === 1 || - (fundingSourceNumber > 0 && fundingSourceNumber <= validSources.length) - - if (matchesValidSource) { - const index = fundingSourceNumber ? fundingSourceNumber - 1 : 0 - const { type, url } = validSources[index] - const typePrefix = type ? `${type} funding` : 'Funding' - const msg = `${typePrefix} available at the following URL` - return openUrl(this.npm, url, msg) - } else if (validSources.length && !(fundingSourceNumber >= 1)) { - validSources.forEach(({ type, url }, i) => { - const typePrefix = type ? `${type} funding` : 'Funding' - const msg = `${typePrefix} available at the following URL` - this.npm.output(`${i + 1}: ${msg}: ${url}`) - }) - this.npm.output( - /* eslint-disable-next-line max-len */ - 'Run `npm fund [<@scope>/] --which=1`, for example, to open the first funding URL listed in that package' - ) - } else { - const noFundingError = new Error(`No valid funding method available for: ${spec}`) - noFundingError.code = 'ENOFUND' + if (!validSources.length) { + throw errCode(`No valid funding method available for: ${spec}`, 'ENOFUND') + } - throw noFundingError + const fundSource = fundingSourceNumber + ? validSources[fundingSourceNumber - 1] + : validSources.length === 1 ? validSources[0] + : null + + if (fundSource) { + return openUrl(this.npm, ...this.urlMessage(fundSource)) + } + + const ambiguousUrlMsg = [ + ...validSources.map((s, i) => `${i + 1}: ${this.urlMessage(s).reverse().join(': ')}`), + `Run ${this.usageMessage({ which: '1' })}` + + ', for example, to open the first funding URL listed in that package', + ] + if (fundingSourceNumber) { + ambiguousUrlMsg.unshift(`--which=${fundingSourceNumber} is not a valid index`) } + this.npm.output(ambiguousUrlMsg.join('\n')) + } + + urlMessage (source) { + const { type, url } = source + const typePrefix = type ? `${type} funding` : 'Funding' + const message = `${typePrefix} available at the following URL` + return [url, message] } } module.exports = Fund diff --git a/deps/npm/lib/commands/help-search.js b/deps/npm/lib/commands/help-search.js index 488189bbbc5cd8..afb82bfaca9eea 100644 --- a/deps/npm/lib/commands/help-search.js +++ b/deps/npm/lib/commands/help-search.js @@ -13,14 +13,13 @@ class HelpSearch extends BaseCommand { static name = 'help-search' static usage = [''] static params = ['long'] - static ignoreImplicitWorkspace = true async exec (args) { if (!args.length) { throw this.usageError() } - const docPath = path.resolve(__dirname, '..', '..', 'docs/content') + const docPath = path.resolve(this.npm.npmRoot, 'docs/content') const files = await glob(`${globify(docPath)}/*/*.md`) const data = await this.readFiles(files) const results = await this.searchFiles(args, data, files) @@ -142,7 +141,7 @@ class HelpSearch extends BaseCommand { formatResults (args, results) { const cols = Math.min(process.stdout.columns || Infinity, 80) + 1 - const out = results.map(res => { + const output = results.map(res => { const out = [res.cmd] const r = Object.keys(res.hits) .map(k => `${k}:${res.hits[k]}`) @@ -189,10 +188,10 @@ class HelpSearch extends BaseCommand { const finalOut = results.length && !this.npm.config.get('long') ? 'Top hits for ' + (args.map(JSON.stringify).join(' ')) + '\n' + '—'.repeat(cols - 1) + '\n' + - out + '\n' + + output + '\n' + '—'.repeat(cols - 1) + '\n' + '(run with -l or --long to see more context)' - : out + : output return finalOut.trim() } diff --git a/deps/npm/lib/commands/help.js b/deps/npm/lib/commands/help.js index e7d6395a1b01a6..3ab2c563198680 100644 --- a/deps/npm/lib/commands/help.js +++ b/deps/npm/lib/commands/help.js @@ -1,4 +1,4 @@ -const { spawn } = require('child_process') +const spawn = require('@npmcli/promise-spawn') const path = require('path') const openUrl = require('../utils/open-url.js') const { promisify } = require('util') @@ -14,19 +14,26 @@ const BaseCommand = require('../base-command.js') const manNumberRegex = /\.(\d+)(\.[^/\\]*)?$/ // Searches for the "npm-" prefix in page names, to prefer those. const manNpmPrefixRegex = /\/npm-/ +// hardcoded names for mansections +// XXX: these are used in the docs workspace and should be exported +// from npm so section names can changed more easily +const manSectionNames = { + 1: 'commands', + 5: 'configuring-npm', + 7: 'using-npm', +} class Help extends BaseCommand { static description = 'Get help on npm' static name = 'help' static usage = [' []'] static params = ['viewer'] - static ignoreImplicitWorkspace = true async completion (opts) { if (opts.conf.argv.remain.length > 2) { return [] } - const g = path.resolve(__dirname, '../../man/man[0-9]/*.[0-9]') + const g = path.resolve(this.npm.npmRoot, 'man/man[0-9]/*.[0-9]') const files = await glob(globify(g)) return Object.keys(files.reduce(function (acc, file) { @@ -40,10 +47,7 @@ class Help extends BaseCommand { async exec (args) { // By default we search all of our man subdirectories, but if the user has // asked for a specific one we limit the search to just there - let manSearch = 'man*' - if (/^\d+$/.test(args[0])) { - manSearch = `man${args.shift()}` - } + const manSearch = /^\d+$/.test(args[0]) ? `man${args.shift()}` : 'man*' if (!args.length) { return this.npm.output(await this.npm.usage) @@ -54,20 +58,18 @@ class Help extends BaseCommand { return this.helpSearch(args) } - let section = this.npm.deref(args[0]) || args[0] - - // support `npm help package.json` - section = section.replace('.json', '-json') + // `npm help package.json` + const arg = (this.npm.deref(args[0]) || args[0]).replace('.json', '-json') - const manroot = path.resolve(__dirname, '..', '..', 'man') // find either section.n or npm-section.n - const f = `${manroot}/${manSearch}/?(npm-)${section}.[0-9]*` - let mans = await glob(globify(f)) - mans = mans.sort((a, b) => { + const f = globify(path.resolve(this.npm.npmRoot, `man/${manSearch}/?(npm-)${arg}.[0-9]*`)) + + const [man] = await glob(f).then(r => r.sort((a, b) => { // Prefer the page with an npm prefix, if there's only one. const aHasPrefix = manNpmPrefixRegex.test(a) const bHasPrefix = manNpmPrefixRegex.test(b) if (aHasPrefix !== bHasPrefix) { + /* istanbul ignore next */ return aHasPrefix ? -1 : 1 } @@ -76,6 +78,7 @@ class Help extends BaseCommand { const aManNumberMatch = a.match(manNumberRegex) const bManNumberMatch = b.match(manNumberRegex) if (aManNumberMatch) { + /* istanbul ignore next */ if (!bManNumberMatch) { return -1 } @@ -88,14 +91,9 @@ class Help extends BaseCommand { } return localeCompare(a, b) - }) - const man = mans[0] + })) - if (man) { - await this.viewMan(man) - } else { - return this.helpSearch(args) - } + return man ? this.viewMan(man) : this.helpSearch(args) } helpSearch (args) { @@ -103,62 +101,31 @@ class Help extends BaseCommand { } async viewMan (man) { - const env = {} - Object.keys(process.env).forEach(function (i) { - env[i] = process.env[i] - }) const viewer = this.npm.config.get('viewer') - const opts = { - env, - stdio: 'inherit', + if (viewer === 'browser') { + return openUrl(this.npm, this.htmlMan(man), 'help available at the following URL', true) } - let bin = 'man' - const args = [] - switch (viewer) { - case 'woman': - bin = 'emacsclient' - args.push('-e', `(woman-find-file '${man}')`) - break - - case 'browser': - await openUrl(this.npm, this.htmlMan(man), 'help available at the following URL', true) - return - - default: - args.push(man) - break + let args = ['man', [man]] + if (viewer === 'woman') { + args = ['emacsclient', ['-e', `(woman-find-file '${man}')`]] } - const proc = spawn(bin, args, opts) - return new Promise((resolve, reject) => { - proc.on('exit', (code) => { - if (code) { - return reject(new Error(`help process exited with code: ${code}`)) - } - - return resolve() - }) + return spawn(...args, { stdio: 'inherit' }).catch(err => { + if (err.code) { + throw new Error(`help process exited with code: ${err.code}`) + } else { + throw err + } }) } // Returns the path to the html version of the man page htmlMan (man) { - let sect = man.match(manNumberRegex)[1] + const sect = manSectionNames[man.match(manNumberRegex)[1]] const f = path.basename(man).replace(manNumberRegex, '') - switch (sect) { - case '1': - sect = 'commands' - break - case '5': - sect = 'configuring-npm' - break - case '7': - sect = 'using-npm' - break - } - return 'file:///' + path.resolve(__dirname, '..', '..', 'docs', 'output', sect, f + '.html') + return 'file:///' + path.resolve(this.npm.npmRoot, `docs/output/${sect}/${f}.html`) } } module.exports = Help diff --git a/deps/npm/lib/commands/hook.js b/deps/npm/lib/commands/hook.js index 084741c0c5eeaf..b0f52a801f5717 100644 --- a/deps/npm/lib/commands/hook.js +++ b/deps/npm/lib/commands/hook.js @@ -19,12 +19,8 @@ class Hook extends BaseCommand { 'update ', ] - static ignoreImplicitWorkspace = true - async exec (args) { - return otplease(this.npm, { - ...this.npm.flatOptions, - }, (opts) => { + return otplease(this.npm, { ...this.npm.flatOptions }, (opts) => { switch (args[0]) { case 'add': return this.add(args[1], args[2], args[3], opts) @@ -49,9 +45,7 @@ class Hook extends BaseCommand { this.npm.output(Object.keys(hook).join('\t')) this.npm.output(Object.keys(hook).map(k => hook[k]).join('\t')) } else if (!this.npm.silent) { - this.npm.output(`+ ${this.hookName(hook)} ${ - opts.unicode ? ' ➜ ' : ' -> ' - } ${hook.endpoint}`) + this.npm.output(`+ ${this.hookName(hook)} ${opts.unicode ? ' ➜ ' : ' -> '} ${hook.endpoint}`) } } @@ -104,9 +98,7 @@ class Hook extends BaseCommand { this.npm.output(Object.keys(hook).join('\t')) this.npm.output(Object.keys(hook).map(k => hook[k]).join('\t')) } else if (!this.npm.silent) { - this.npm.output(`- ${this.hookName(hook)} ${ - opts.unicode ? ' ✘ ' : ' X ' - } ${hook.endpoint}`) + this.npm.output(`- ${this.hookName(hook)} ${opts.unicode ? ' ✘ ' : ' X '} ${hook.endpoint}`) } } @@ -118,9 +110,7 @@ class Hook extends BaseCommand { this.npm.output(Object.keys(hook).join('\t')) this.npm.output(Object.keys(hook).map(k => hook[k]).join('\t')) } else if (!this.npm.silent) { - this.npm.output(`+ ${this.hookName(hook)} ${ - opts.unicode ? ' ➜ ' : ' -> ' - } ${hook.endpoint}`) + this.npm.output(`+ ${this.hookName(hook)} ${opts.unicode ? ' ➜ ' : ' -> '} ${hook.endpoint}`) } } diff --git a/deps/npm/lib/commands/init.js b/deps/npm/lib/commands/init.js index 02a43b0ef0960f..16ece46589d7cb 100644 --- a/deps/npm/lib/commands/init.js +++ b/deps/npm/lib/commands/init.js @@ -10,6 +10,8 @@ const PackageJson = require('@npmcli/package-json') const log = require('../utils/log-shim.js') const updateWorkspaces = require('../workspaces/update-workspaces.js') +const posixPath = p => p.split('\\').join('/') + const BaseCommand = require('../base-command.js') class Init extends BaseCommand { @@ -26,23 +28,24 @@ class Init extends BaseCommand { static name = 'init' static usage = [ - ' (same as `npx )', + ' (same as `npx `)', '<@scope> (same as `npx <@scope>/create`)', ] + static workspaces = true static ignoreImplicitWorkspace = false async exec (args) { // npm exec style if (args.length) { - return (await this.execCreate({ args, path: process.cwd() })) + return await this.execCreate(args) } // no args, uses classic init-package-json boilerplate await this.template() } - async execWorkspaces (args, filters) { + async execWorkspaces (args) { // if the root package is uninitiated, take care of it first if (this.npm.flatOptions.includeWorkspaceRoot) { await this.exec(args) @@ -51,7 +54,16 @@ class Init extends BaseCommand { // reads package.json for the top-level folder first, by doing this we // ensure the command throw if no package.json is found before trying // to create a workspace package.json file or its folders - const pkg = await rpj(resolve(this.npm.localPrefix, 'package.json')) + const pkg = await rpj(resolve(this.npm.localPrefix, 'package.json')).catch((err) => { + if (err.code === 'ENOENT') { + log.warn('Missing package.json. Try with `--include-workspace-root`.') + } + throw err + }) + + // these are workspaces that are being created, so we cant use + // this.setWorkspaces() + const filters = this.npm.config.get('workspace') const wPath = filterArg => resolve(this.npm.localPrefix, filterArg) const workspacesPaths = [] @@ -61,8 +73,8 @@ class Init extends BaseCommand { const path = wPath(filterArg) await mkdir(path, { recursive: true }) workspacesPaths.push(path) - await this.execCreate({ args, path }) - await this.setWorkspace({ pkg, workspacePath: path }) + await this.execCreate(args, path) + await this.setWorkspace(pkg, path) } return } @@ -73,14 +85,14 @@ class Init extends BaseCommand { await mkdir(path, { recursive: true }) workspacesPaths.push(path) await this.template(path) - await this.setWorkspace({ pkg, workspacePath: path }) + await this.setWorkspace(pkg, path) } // reify packages once all workspaces have been initialized await this.update(workspacesPaths) } - async execCreate ({ args, path }) { + async execCreate (args, path = process.cwd()) { const [initerName, ...otherArgs] = args let packageName = initerName @@ -95,8 +107,7 @@ class Init extends BaseCommand { const req = npa(initerName) if (req.type === 'git' && req.hosted) { const { user, project } = req.hosted - packageName = initerName - .replace(user + '/' + project, user + '/create-' + project) + packageName = initerName.replace(`${user}/${project}`, `${user}/create-${project}`) } else if (req.registry) { packageName = `${req.name.replace(/^(@[^/]+\/)?/, '$1create-')}@${req.rawSpec}` } else { @@ -174,7 +185,7 @@ class Init extends BaseCommand { }) } - async setWorkspace ({ pkg, workspacePath }) { + async setWorkspace (pkg, workspacePath) { const workspaces = await mapWorkspaces({ cwd: this.npm.localPrefix, pkg }) // skip setting workspace if current package.json glob already satisfies it @@ -199,7 +210,7 @@ class Init extends BaseCommand { pkgJson.update({ workspaces: [ ...(pkgJson.content.workspaces || []), - relative(this.npm.localPrefix, workspacePath), + posixPath(relative(this.npm.localPrefix, workspacePath)), ], }) @@ -210,9 +221,7 @@ class Init extends BaseCommand { // translate workspaces paths into an array containing workspaces names const workspaces = [] for (const path of workspacesPaths) { - const pkgPath = resolve(path, 'package.json') - const { name } = await rpj(pkgPath) - .catch(() => ({})) + const { name } = await rpj(resolve(path, 'package.json')).catch(() => ({})) if (name) { workspaces.push(name) diff --git a/deps/npm/lib/commands/install-ci-test.js b/deps/npm/lib/commands/install-ci-test.js index 9977a2edc5641c..f7a357ba6e1246 100644 --- a/deps/npm/lib/commands/install-ci-test.js +++ b/deps/npm/lib/commands/install-ci-test.js @@ -7,7 +7,7 @@ class InstallCITest extends CI { static description = 'Install a project with a clean slate and run tests' static name = 'install-ci-test' - async exec (args, cb) { + async exec (args) { await this.npm.exec('ci', args) return this.npm.exec('test', []) } diff --git a/deps/npm/lib/commands/install-test.js b/deps/npm/lib/commands/install-test.js index 191d70909f9e75..11f22e535403cc 100644 --- a/deps/npm/lib/commands/install-test.js +++ b/deps/npm/lib/commands/install-test.js @@ -7,7 +7,7 @@ class InstallTest extends Install { static description = 'Install package(s) and run tests' static name = 'install-test' - async exec (args, cb) { + async exec (args) { await this.npm.exec('install', args) return this.npm.exec('test', []) } diff --git a/deps/npm/lib/commands/login.js b/deps/npm/lib/commands/login.js index 7f6898d00ba93d..dc4ed8a67acd97 100644 --- a/deps/npm/lib/commands/login.js +++ b/deps/npm/lib/commands/login.js @@ -13,8 +13,6 @@ class Login extends BaseCommand { 'auth-type', ] - static ignoreImplicitWorkspace = true - async exec (args) { const scope = this.npm.config.get('scope') let registry = this.npm.config.get('registry') diff --git a/deps/npm/lib/commands/logout.js b/deps/npm/lib/commands/logout.js index 7c2a7f0b2f830d..aea5e93652b0e8 100644 --- a/deps/npm/lib/commands/logout.js +++ b/deps/npm/lib/commands/logout.js @@ -11,8 +11,6 @@ class Logout extends BaseCommand { 'scope', ] - static ignoreImplicitWorkspace = true - async exec (args) { const registry = this.npm.config.get('registry') const scope = this.npm.config.get('scope') diff --git a/deps/npm/lib/commands/ls.js b/deps/npm/lib/commands/ls.js index 7eebdf691683fb..2213e7937407a9 100644 --- a/deps/npm/lib/commands/ls.js +++ b/deps/npm/lib/commands/ls.js @@ -178,11 +178,9 @@ class LS extends ArboristWorkspaceCmd { e.code === 'EJSONPARSE' && e.path === resolve(path, 'package.json')) this.npm.outputBuffer( - json - ? jsonOutput({ path, problems, result, rootError, seenItems }) - : parseable - ? parseableOutput({ seenNodes, global, long }) - : humanOutput({ color, result, seenItems, unicode }) + json ? jsonOutput({ path, problems, result, rootError, seenItems }) : + parseable ? parseableOutput({ seenNodes, global, long }) : + humanOutput({ color, result, seenItems, unicode }) ) // if filtering items, should exit with error code on no results @@ -402,7 +400,7 @@ const getJsonOutputItem = (node, { global, long }) => { return augmentItemWithIncludeMetadata(node, item) } -const filterByEdgesTypes = ({ link, omit = [] }) => (edge) => { +const filterByEdgesTypes = ({ link, omit }) => (edge) => { for (const omitType of omit) { if (edge[omitType]) { return false diff --git a/deps/npm/lib/commands/org.js b/deps/npm/lib/commands/org.js index f49556c8d6a195..575ff75e2a6cf3 100644 --- a/deps/npm/lib/commands/org.js +++ b/deps/npm/lib/commands/org.js @@ -13,7 +13,6 @@ class Org extends BaseCommand { ] static params = ['registry', 'otp', 'json', 'parseable'] - static ignoreImplicitWorkspace = true async completion (opts) { const argv = opts.conf.argv.remain @@ -32,7 +31,7 @@ class Org extends BaseCommand { } } - async exec ([cmd, orgname, username, role], cb) { + async exec ([cmd, orgname, username, role]) { return otplease(this.npm, { ...this.npm.flatOptions, }, opts => { @@ -139,15 +138,15 @@ class Org extends BaseCommand { this.npm.output(JSON.stringify(roster, null, 2)) } else if (opts.parseable) { this.npm.output(['user', 'role'].join('\t')) - Object.keys(roster).forEach(user => { - this.npm.output([user, roster[user]].join('\t')) + Object.keys(roster).forEach(u => { + this.npm.output([u, roster[u]].join('\t')) }) } else if (!this.npm.silent) { const table = new Table({ head: ['user', 'role'] }) Object.keys(roster) .sort() - .forEach(user => { - table.push([user, roster[user]]) + .forEach(u => { + table.push([u, roster[u]]) }) this.npm.output(table.toString()) } diff --git a/deps/npm/lib/commands/outdated.js b/deps/npm/lib/commands/outdated.js index 9e2060658ed72d..5e8a4e0d2168c5 100644 --- a/deps/npm/lib/commands/outdated.js +++ b/deps/npm/lib/commands/outdated.js @@ -1,5 +1,5 @@ const os = require('os') -const path = require('path') +const { resolve } = require('path') const pacote = require('pacote') const table = require('text-table') const chalk = require('chalk') @@ -26,7 +26,7 @@ class Outdated extends ArboristWorkspaceCmd { ] async exec (args) { - const global = path.resolve(this.npm.globalDir, '..') + const global = resolve(this.npm.globalDir, '..') const where = this.npm.global ? global : this.npm.prefix diff --git a/deps/npm/lib/commands/owner.js b/deps/npm/lib/commands/owner.js index 824b64e044ecf2..3a997db800db7d 100644 --- a/deps/npm/lib/commands/owner.js +++ b/deps/npm/lib/commands/owner.js @@ -32,6 +32,7 @@ class Owner extends BaseCommand { 'ls ', ] + static workspaces = true static ignoreImplicitWorkspace = false async completion (opts) { @@ -82,8 +83,8 @@ class Owner extends BaseCommand { } } - async execWorkspaces ([action, ...args], filters) { - await this.setWorkspaces(filters) + async execWorkspaces ([action, ...args]) { + await this.setWorkspaces() // ls pkg or owner add/rm package if ((action === 'ls' && args.length > 0) || args.length > 1) { const implicitWorkspaces = this.npm.config.get('workspace', 'default') @@ -119,7 +120,7 @@ class Owner extends BaseCommand { this.npm.output(maintainers.map(m => `${m.name} <${m.email}>`).join('\n')) } } catch (err) { - log.error('owner ls', "Couldn't get owner data", pkg) + log.error('owner ls', "Couldn't get owner data", npmFetch.cleanUrl(pkg)) throw err } } diff --git a/deps/npm/lib/commands/pack.js b/deps/npm/lib/commands/pack.js index c6a74804642f66..74e80e573c2e92 100644 --- a/deps/npm/lib/commands/pack.js +++ b/deps/npm/lib/commands/pack.js @@ -18,6 +18,7 @@ class Pack extends BaseCommand { ] static usage = [''] + static workspaces = true static ignoreImplicitWorkspace = false async exec (args) { @@ -64,7 +65,7 @@ class Pack extends BaseCommand { } } - async execWorkspaces (args, filters) { + async execWorkspaces (args) { // If they either ask for nothing, or explicitly include '.' in the args, // we effectively translate that into each workspace requested @@ -75,7 +76,7 @@ class Pack extends BaseCommand { return this.exec(args) } - await this.setWorkspaces(filters) + await this.setWorkspaces() return this.exec([...this.workspacePaths, ...args.filter(a => a !== '.')]) } } diff --git a/deps/npm/lib/commands/ping.js b/deps/npm/lib/commands/ping.js index 22039214689a96..c79e6a96cee405 100644 --- a/deps/npm/lib/commands/ping.js +++ b/deps/npm/lib/commands/ping.js @@ -1,3 +1,4 @@ +const { cleanUrl } = require('npm-registry-fetch') const log = require('../utils/log-shim') const pingUtil = require('../utils/ping.js') const BaseCommand = require('../base-command.js') @@ -6,17 +7,17 @@ class Ping extends BaseCommand { static description = 'Ping npm registry' static params = ['registry'] static name = 'ping' - static ignoreImplicitWorkspace = true async exec (args) { - log.notice('PING', this.npm.config.get('registry')) + const cleanRegistry = cleanUrl(this.npm.config.get('registry')) + log.notice('PING', cleanRegistry) const start = Date.now() const details = await pingUtil({ ...this.npm.flatOptions }) const time = Date.now() - start log.notice('PONG', `${time}ms`) if (this.npm.config.get('json')) { this.npm.output(JSON.stringify({ - registry: this.npm.config.get('registry'), + registry: cleanRegistry, time, details, }, null, 2)) diff --git a/deps/npm/lib/commands/pkg.js b/deps/npm/lib/commands/pkg.js index 5fac9bfb54683b..5cdcd207887c9e 100644 --- a/deps/npm/lib/commands/pkg.js +++ b/deps/npm/lib/commands/pkg.js @@ -20,6 +20,7 @@ class Pkg extends BaseCommand { 'workspaces', ] + static workspaces = true static ignoreImplicitWorkspace = false async exec (args, { prefix } = {}) { @@ -49,8 +50,8 @@ class Pkg extends BaseCommand { } } - async execWorkspaces (args, filters) { - await this.setWorkspaces(filters) + async execWorkspaces (args) { + await this.setWorkspaces() const result = {} for (const [workspaceName, workspacePath] of this.workspaces.entries()) { this.prefix = workspacePath @@ -81,7 +82,7 @@ class Pkg extends BaseCommand { // only outputs if not running with workspaces config, // in case you're retrieving info for workspaces the pkgWorkspaces // will handle the output to make sure it get keyed by ws name - if (!this.workspaces) { + if (!this.npm.config.get('workspaces')) { this.npm.output(JSON.stringify(result, null, 2)) } diff --git a/deps/npm/lib/commands/prefix.js b/deps/npm/lib/commands/prefix.js index dd0e34c3d3bd95..264b819fc7692a 100644 --- a/deps/npm/lib/commands/prefix.js +++ b/deps/npm/lib/commands/prefix.js @@ -5,7 +5,6 @@ class Prefix extends BaseCommand { static name = 'prefix' static params = ['global'] static usage = ['[-g]'] - static ignoreImplicitWorkspace = true async exec (args) { return this.npm.output(this.npm.prefix) diff --git a/deps/npm/lib/commands/profile.js b/deps/npm/lib/commands/profile.js index 27060cf73a6502..e42ebb276d202e 100644 --- a/deps/npm/lib/commands/profile.js +++ b/deps/npm/lib/commands/profile.js @@ -54,8 +54,6 @@ class Profile extends BaseCommand { 'otp', ] - static ignoreImplicitWorkspace = true - async completion (opts) { var argv = opts.conf.argv.remain @@ -221,7 +219,7 @@ class Profile extends BaseCommand { newUser[prop] = value - const result = await otplease(this.npm, conf, conf => npmProfile.set(newUser, conf)) + const result = await otplease(this.npm, conf, c => npmProfile.set(newUser, c)) if (this.npm.config.get('json')) { this.npm.output(JSON.stringify({ [prop]: result[prop] }, null, 2)) diff --git a/deps/npm/lib/commands/publish.js b/deps/npm/lib/commands/publish.js index 23323a174ed897..76faea9457f748 100644 --- a/deps/npm/lib/commands/publish.js +++ b/deps/npm/lib/commands/publish.js @@ -38,6 +38,7 @@ class Publish extends BaseCommand { ] static usage = [''] + static workspaces = true static ignoreImplicitWorkspace = false async exec (args) { @@ -123,7 +124,7 @@ class Publish extends BaseCommand { log.notice('', msg) if (!dryRun) { - await otplease(this.npm, opts, opts => libpub(manifest, tarballData, opts)) + await otplease(this.npm, opts, o => libpub(manifest, tarballData, o)) } if (spec.type === 'directory' && !ignoreScripts) { @@ -155,14 +156,14 @@ class Publish extends BaseCommand { return pkgContents } - async execWorkspaces (args, filters) { + async execWorkspaces (args) { // Suppresses JSON output in publish() so we can handle it here this.suppressOutput = true const results = {} const json = this.npm.config.get('json') const { silent } = this.npm - await this.setWorkspaces(filters) + await this.setWorkspaces() for (const [name, workspace] of this.workspaces.entries()) { let pkgContents diff --git a/deps/npm/lib/commands/query.js b/deps/npm/lib/commands/query.js index 5f05ab3164d7c5..b5f4d8e57ddf5e 100644 --- a/deps/npm/lib/commands/query.js +++ b/deps/npm/lib/commands/query.js @@ -41,6 +41,7 @@ class Query extends BaseCommand { static name = 'query' static usage = [''] + static workspaces = true static ignoreImplicitWorkspace = false static params = [ @@ -70,8 +71,8 @@ class Query extends BaseCommand { this.npm.output(this.parsedResponse) } - async execWorkspaces (args, filters) { - await this.setWorkspaces(filters) + async execWorkspaces (args) { + await this.setWorkspaces() const opts = { ...this.npm.flatOptions, path: this.npm.prefix, diff --git a/deps/npm/lib/commands/restart.js b/deps/npm/lib/commands/restart.js index 575928b2202cc8..7ca2eb323da3ca 100644 --- a/deps/npm/lib/commands/restart.js +++ b/deps/npm/lib/commands/restart.js @@ -8,7 +8,6 @@ class Restart extends LifecycleCmd { 'ignore-scripts', 'script-shell', ] - - static ignoreImplicitWorkspace = false } + module.exports = Restart diff --git a/deps/npm/lib/commands/root.js b/deps/npm/lib/commands/root.js index b814034def5ab6..7749c602456b77 100644 --- a/deps/npm/lib/commands/root.js +++ b/deps/npm/lib/commands/root.js @@ -3,7 +3,6 @@ class Root extends BaseCommand { static description = 'Display npm root' static name = 'root' static params = ['global'] - static ignoreImplicitWorkspace = true async exec () { this.npm.output(this.npm.dir) diff --git a/deps/npm/lib/commands/run-script.js b/deps/npm/lib/commands/run-script.js index 3852f7ba1820f5..51746c5e5285d9 100644 --- a/deps/npm/lib/commands/run-script.js +++ b/deps/npm/lib/commands/run-script.js @@ -41,6 +41,7 @@ class RunScript extends BaseCommand { static name = 'run-script' static usage = [' [-- ]'] + static workspaces = true static ignoreImplicitWorkspace = false static isShellout = true @@ -62,11 +63,11 @@ class RunScript extends BaseCommand { } } - async execWorkspaces (args, filters) { + async execWorkspaces (args) { if (args.length) { - return this.runWorkspaces(args, filters) + return this.runWorkspaces(args) } else { - return this.listWorkspaces(args, filters) + return this.listWorkspaces(args) } } @@ -121,11 +122,11 @@ class RunScript extends BaseCommand { banner: !this.npm.silent, } - for (const [event, args] of events) { + for (const [ev, evArgs] of events) { await runScript({ ...opts, - event, - args, + event: ev, + args: evArgs, }) } } @@ -200,7 +201,7 @@ class RunScript extends BaseCommand { async runWorkspaces (args, filters) { const res = [] - await this.setWorkspaces(filters) + await this.setWorkspaces() for (const workspacePath of this.workspacePaths) { const pkg = await rpj(`${workspacePath}/package.json`) @@ -233,7 +234,7 @@ class RunScript extends BaseCommand { } async listWorkspaces (args, filters) { - await this.setWorkspaces(filters) + await this.setWorkspaces() if (this.npm.silent) { return diff --git a/deps/npm/lib/commands/search.js b/deps/npm/lib/commands/search.js index 8751e9e7d22fd0..7419e974546888 100644 --- a/deps/npm/lib/commands/search.js +++ b/deps/npm/lib/commands/search.js @@ -51,7 +51,6 @@ class Search extends BaseCommand { ] static usage = ['[search terms ...]'] - static ignoreImplicitWorkspace = true async exec (args) { const opts = { diff --git a/deps/npm/lib/commands/start.js b/deps/npm/lib/commands/start.js index d84ad23ebafa63..a16eade24d21ed 100644 --- a/deps/npm/lib/commands/start.js +++ b/deps/npm/lib/commands/start.js @@ -8,7 +8,6 @@ class Start extends LifecycleCmd { 'ignore-scripts', 'script-shell', ] - - static ignoreImplicitWorkspace = false } + module.exports = Start diff --git a/deps/npm/lib/commands/stop.js b/deps/npm/lib/commands/stop.js index db497675a694b6..ae3031f06dd96c 100644 --- a/deps/npm/lib/commands/stop.js +++ b/deps/npm/lib/commands/stop.js @@ -8,7 +8,6 @@ class Stop extends LifecycleCmd { 'ignore-scripts', 'script-shell', ] - - static ignoreImplicitWorkspace = false } + module.exports = Stop diff --git a/deps/npm/lib/commands/test.js b/deps/npm/lib/commands/test.js index 43be934894dd7a..eccc47fc3341c7 100644 --- a/deps/npm/lib/commands/test.js +++ b/deps/npm/lib/commands/test.js @@ -8,7 +8,6 @@ class Test extends LifecycleCmd { 'ignore-scripts', 'script-shell', ] - - static ignoreImplicitWorkspace = false } + module.exports = Test diff --git a/deps/npm/lib/commands/token.js b/deps/npm/lib/commands/token.js index de8e61101d8acd..8da83118757144 100644 --- a/deps/npm/lib/commands/token.js +++ b/deps/npm/lib/commands/token.js @@ -14,7 +14,6 @@ class Token extends BaseCommand { static name = 'token' static usage = ['list', 'revoke ', 'create [--read-only] [--cidr=list]'] static params = ['read-only', 'cidr', 'registry', 'otp'] - static ignoreImplicitWorkspace = true async completion (opts) { const argv = opts.conf.argv.remain @@ -30,7 +29,7 @@ class Token extends BaseCommand { throw new Error(argv[2] + ' not recognized') } - async exec (args, cb) { + async exec (args) { log.gauge.show('token') if (args.length === 0) { return this.list() @@ -121,9 +120,7 @@ class Token extends BaseCommand { }) await Promise.all( toRemove.map(key => { - return otplease(this.npm, conf, conf => { - return profile.removeToken(key, conf) - }) + return otplease(this.npm, conf, c => profile.removeToken(key, c)) }) ) if (conf.json) { @@ -144,9 +141,7 @@ class Token extends BaseCommand { const validCIDR = this.validateCIDRList(cidr) log.info('token', 'creating') const result = await pulseTillDone.withPromise( - otplease(this.npm, conf, conf => { - return profile.createToken(password, readonly, validCIDR, conf) - }) + otplease(this.npm, conf, c => profile.createToken(password, readonly, validCIDR, c)) ) delete result.key delete result.updated @@ -216,7 +211,7 @@ class Token extends BaseCommand { } validateCIDRList (cidrs) { - const maybeList = cidrs ? (Array.isArray(cidrs) ? cidrs : [cidrs]) : [] + const maybeList = [].concat(cidrs).filter(Boolean) const list = maybeList.length === 1 ? maybeList[0].split(/,\s*/) : maybeList for (const cidr of list) { if (isCidrV6(cidr)) { diff --git a/deps/npm/lib/commands/uninstall.js b/deps/npm/lib/commands/uninstall.js index e4a193cc5ca4ed..8c44f2e32106c2 100644 --- a/deps/npm/lib/commands/uninstall.js +++ b/deps/npm/lib/commands/uninstall.js @@ -20,19 +20,13 @@ class Uninstall extends ArboristWorkspaceCmd { } async exec (args) { - // the /path/to/node_modules/.. - const path = this.npm.global - ? resolve(this.npm.globalDir, '..') - : this.npm.localPrefix - if (!args.length) { if (!this.npm.global) { throw new Error('Must provide a package name to remove') } else { - let pkg - try { - pkg = await rpj(resolve(this.npm.localPrefix, 'package.json')) + const pkg = await rpj(resolve(this.npm.localPrefix, 'package.json')) + args.push(pkg.name) } catch (er) { if (er.code !== 'ENOENT' && er.code !== 'ENOTDIR') { throw er @@ -40,11 +34,14 @@ class Uninstall extends ArboristWorkspaceCmd { throw this.usageError() } } - - args.push(pkg.name) } } + // the /path/to/node_modules/.. + const path = this.npm.global + ? resolve(this.npm.globalDir, '..') + : this.npm.localPrefix + const opts = { ...this.npm.flatOptions, path, diff --git a/deps/npm/lib/commands/unpublish.js b/deps/npm/lib/commands/unpublish.js index 268c8c3daedbbd..9985e2e39f1405 100644 --- a/deps/npm/lib/commands/unpublish.js +++ b/deps/npm/lib/commands/unpublish.js @@ -21,6 +21,7 @@ class Unpublish extends BaseCommand { static name = 'unpublish' static params = ['dry-run', 'force', 'workspace', 'workspaces'] static usage = ['[]'] + static workspaces = true static ignoreImplicitWorkspace = false async getKeysOfVersions (name, opts) { @@ -130,15 +131,15 @@ class Unpublish extends BaseCommand { } if (!dryRun) { - await otplease(this.npm, opts, opts => libunpub(spec, opts)) + await otplease(this.npm, opts, o => libunpub(spec, o)) } if (!silent) { this.npm.output(`- ${pkgName}${pkgVersion}`) } } - async execWorkspaces (args, filters) { - await this.setWorkspaces(filters) + async execWorkspaces (args) { + await this.setWorkspaces() const force = this.npm.config.get('force') if (!force) { diff --git a/deps/npm/lib/commands/update.js b/deps/npm/lib/commands/update.js index be9d35093d43bf..fd30bcb41e2b3f 100644 --- a/deps/npm/lib/commands/update.js +++ b/deps/npm/lib/commands/update.js @@ -40,9 +40,7 @@ class Update extends ArboristWorkspaceCmd { async exec (args) { const update = args.length === 0 ? true : args const global = path.resolve(this.npm.globalDir, '..') - const where = this.npm.global - ? global - : this.npm.prefix + const where = this.npm.global ? global : this.npm.prefix // In the context of `npm update` the save // config value should default to `false` diff --git a/deps/npm/lib/commands/version.js b/deps/npm/lib/commands/version.js index ab59fff5a308cc..a5232836717917 100644 --- a/deps/npm/lib/commands/version.js +++ b/deps/npm/lib/commands/version.js @@ -22,6 +22,7 @@ class Version extends BaseCommand { 'include-workspace-root', ] + static workspaces = true static ignoreImplicitWorkspace = false /* eslint-disable-next-line max-len */ @@ -60,12 +61,12 @@ class Version extends BaseCommand { } } - async execWorkspaces (args, filters) { + async execWorkspaces (args) { switch (args.length) { case 0: - return this.listWorkspaces(filters) + return this.listWorkspaces() case 1: - return this.changeWorkspaces(args, filters) + return this.changeWorkspaces(args) default: throw this.usageError() } @@ -80,9 +81,9 @@ class Version extends BaseCommand { return this.npm.output(`${prefix}${version}`) } - async changeWorkspaces (args, filters) { + async changeWorkspaces (args) { const prefix = this.npm.config.get('tag-version-prefix') - await this.setWorkspaces(filters) + await this.setWorkspaces() const updatedWorkspaces = [] for (const [name, path] of this.workspaces) { this.npm.output(name) @@ -120,9 +121,9 @@ class Version extends BaseCommand { } } - async listWorkspaces (filters) { + async listWorkspaces () { const results = {} - await this.setWorkspaces(filters) + await this.setWorkspaces() for (const path of this.workspacePaths) { const pj = resolve(path, 'package.json') // setWorkspaces has already parsed package.json so we know it won't error diff --git a/deps/npm/lib/commands/view.js b/deps/npm/lib/commands/view.js index 32b2d0f92a1a68..855b37b81d42f9 100644 --- a/deps/npm/lib/commands/view.js +++ b/deps/npm/lib/commands/view.js @@ -1,8 +1,3 @@ -/* eslint-disable no-console */ -// XXX: remove console.log later - -// npm view [pkg [pkg ...]] - const chalk = require('chalk') const columns = require('cli-columns') const fs = require('fs') @@ -31,8 +26,8 @@ class View extends BaseCommand { 'include-workspace-root', ] + static workspaces = true static ignoreImplicitWorkspace = false - static usage = ['[] [[.subfield]...]'] async completion (opts) { @@ -127,12 +122,12 @@ class View extends BaseCommand { const msg = await this.jsonData(reducedData, pckmnt._id) if (msg !== '') { - console.log(msg) + this.npm.output(msg) } } } - async execWorkspaces (args, filters) { + async execWorkspaces (args) { if (!args.length) { args = ['.'] } @@ -150,7 +145,7 @@ class View extends BaseCommand { args = [''] // getData relies on this } const results = {} - await this.setWorkspaces(filters) + await this.setWorkspaces() for (const name of this.workspaceNames) { const wsPkg = `${name}${pkg.slice(1)}` const [pckmnt, data] = await this.getData(wsPkg, args) @@ -166,10 +161,10 @@ class View extends BaseCommand { if (wholePackument) { data.map((v) => this.prettyView(pckmnt, v[Object.keys(v)[0]][''])) } else { - console.log(`${name}:`) + this.npm.output(`${name}:`) const msg = await this.jsonData(reducedData, pckmnt._id) if (msg !== '') { - console.log(msg) + this.npm.output(msg) } } } else { @@ -180,7 +175,7 @@ class View extends BaseCommand { } } if (Object.keys(results).length > 0) { - console.log(JSON.stringify(results, null, 2)) + this.npm.output(JSON.stringify(results, null, 2)) } } @@ -317,13 +312,13 @@ class View extends BaseCommand { return msg.trim() } - prettyView (packument, manifest) { + prettyView (packu, manifest) { // More modern, pretty printing of default view const unicode = this.npm.config.get('unicode') const tags = [] - Object.keys(packument['dist-tags']).forEach((t) => { - const version = packument['dist-tags'][t] + Object.keys(packu['dist-tags']).forEach((t) => { + const version = packu['dist-tags'][t] tags.push(`${chalk.bold.green(t)}: ${version}`) }) const unpackedSize = manifest.dist.unpackedSize && @@ -333,10 +328,10 @@ class View extends BaseCommand { name: chalk.green(manifest.name), version: chalk.green(manifest.version), bins: Object.keys(manifest.bin || {}), - versions: chalk.yellow(packument.versions.length + ''), + versions: chalk.yellow(packu.versions.length + ''), description: manifest.description, deprecated: manifest.deprecated, - keywords: packument.keywords || [], + keywords: packu.keywords || [], license: typeof licenseField === 'string' ? licenseField : (licenseField.type || 'Proprietary'), @@ -347,9 +342,9 @@ class View extends BaseCommand { name: chalk.yellow(manifest._npmUser.name), email: chalk.cyan(manifest._npmUser.email), }), - modified: !packument.time ? undefined - : chalk.yellow(relativeDate(packument.time[manifest.version])), - maintainers: (packument.maintainers || []).map((u) => unparsePerson({ + modified: !packu.time ? undefined + : chalk.yellow(relativeDate(packu.time[manifest.version])), + maintainers: (packu.maintainers || []).map((u) => unparsePerson({ name: chalk.yellow(u.name), email: chalk.cyan(u.email), })), @@ -376,61 +371,61 @@ class View extends BaseCommand { info.license = chalk.green(info.license) } - console.log('') - console.log( + this.npm.output('') + this.npm.output( chalk.underline.bold(`${info.name}@${info.version}`) + ' | ' + info.license + ' | deps: ' + (info.deps.length ? chalk.cyan(info.deps.length) : chalk.green('none')) + ' | versions: ' + info.versions ) - info.description && console.log(info.description) + info.description && this.npm.output(info.description) if (info.repo || info.site) { - info.site && console.log(chalk.cyan(info.site)) + info.site && this.npm.output(chalk.cyan(info.site)) } const warningSign = unicode ? ' ⚠️ ' : '!!' - info.deprecated && console.log( + info.deprecated && this.npm.output( `\n${chalk.bold.red('DEPRECATED')}${ warningSign } - ${info.deprecated}` ) if (info.keywords.length) { - console.log('') - console.log('keywords:', chalk.yellow(info.keywords.join(', '))) + this.npm.output('') + this.npm.output('keywords:', chalk.yellow(info.keywords.join(', '))) } if (info.bins.length) { - console.log('') - console.log('bin:', chalk.yellow(info.bins.join(', '))) + this.npm.output('') + this.npm.output('bin:', chalk.yellow(info.bins.join(', '))) } - console.log('') - console.log('dist') - console.log('.tarball:', info.tarball) - console.log('.shasum:', info.shasum) - info.integrity && console.log('.integrity:', info.integrity) - info.unpackedSize && console.log('.unpackedSize:', info.unpackedSize) + this.npm.output('') + this.npm.output('dist') + this.npm.output('.tarball:', info.tarball) + this.npm.output('.shasum:', info.shasum) + info.integrity && this.npm.output('.integrity:', info.integrity) + info.unpackedSize && this.npm.output('.unpackedSize:', info.unpackedSize) const maxDeps = 24 if (info.deps.length) { - console.log('') - console.log('dependencies:') - console.log(columns(info.deps.slice(0, maxDeps), { padding: 1 })) + this.npm.output('') + this.npm.output('dependencies:') + this.npm.output(columns(info.deps.slice(0, maxDeps), { padding: 1 })) if (info.deps.length > maxDeps) { - console.log(`(...and ${info.deps.length - maxDeps} more.)`) + this.npm.output(`(...and ${info.deps.length - maxDeps} more.)`) } } if (info.maintainers && info.maintainers.length) { - console.log('') - console.log('maintainers:') - info.maintainers.forEach((u) => console.log('-', u)) + this.npm.output('') + this.npm.output('maintainers:') + info.maintainers.forEach((u) => this.npm.output('-', u)) } - console.log('') - console.log('dist-tags:') - console.log(columns(info.tags)) + this.npm.output('') + this.npm.output('dist-tags:') + this.npm.output(columns(info.tags)) if (info.publisher || info.modified) { let publishInfo = 'published' @@ -440,8 +435,8 @@ class View extends BaseCommand { if (info.publisher) { publishInfo += ` by ${info.publisher}` } - console.log('') - console.log(publishInfo) + this.npm.output('') + this.npm.output(publishInfo) } } } diff --git a/deps/npm/lib/commands/whoami.js b/deps/npm/lib/commands/whoami.js index 4497f9b3a542d5..154cc870391ba1 100644 --- a/deps/npm/lib/commands/whoami.js +++ b/deps/npm/lib/commands/whoami.js @@ -5,7 +5,6 @@ class Whoami extends BaseCommand { static description = 'Display npm username' static name = 'whoami' static params = ['registry'] - static ignoreImplicitWorkspace = true async exec (args) { const username = await getIdentity(this.npm, { ...this.npm.flatOptions }) diff --git a/deps/npm/lib/lifecycle-cmd.js b/deps/npm/lib/lifecycle-cmd.js index 41633a4ba389c9..848771a38355e5 100644 --- a/deps/npm/lib/lifecycle-cmd.js +++ b/deps/npm/lib/lifecycle-cmd.js @@ -5,12 +5,14 @@ const BaseCommand = require('./base-command.js') class LifecycleCmd extends BaseCommand { static usage = ['[-- ]'] static isShellout = true + static workspaces = true + static ignoreImplicitWorkspace = false - async exec (args, cb) { + async exec (args) { return this.npm.exec('run-script', [this.constructor.name, ...args]) } - async execWorkspaces (args, filters, cb) { + async execWorkspaces (args) { return this.npm.exec('run-script', [this.constructor.name, ...args]) } } diff --git a/deps/npm/lib/npm.js b/deps/npm/lib/npm.js index 0bdbcdb9efd8ba..841d145ddcbad7 100644 --- a/deps/npm/lib/npm.js +++ b/deps/npm/lib/npm.js @@ -20,25 +20,24 @@ const updateNotifier = require('./utils/update-notifier.js') const pkg = require('../package.json') const cmdList = require('./utils/cmd-list.js') -let warnedNonDashArg = false -const _load = Symbol('_load') - class Npm extends EventEmitter { static get version () { return pkg.version } - command = null updateNotification = null loadErr = null argv = [] + #command = null #runId = new Date().toISOString().replace(/[.:]/g, '_') #loadPromise = null #tmpFolder = null #title = 'npm' #argvClean = [] #chalk = null + #npmRoot = null + #warnedNonDashArg = false #outputBuffer = [] #logFile = new LogFile() @@ -52,12 +51,30 @@ class Npm extends EventEmitter { }, }) - config = new Config({ - npmPath: dirname(__dirname), - definitions, - flatten, - shorthands, - }) + // all these options are only used by tests in order to make testing more + // closely resemble real world usage. for now, npm has no programmatic API so + // it is ok to add stuff here, but we should not rely on it more than + // necessary. XXX: make these options not necessary by refactoring @npmcli/config + // - npmRoot: this is where npm looks for docs files and the builtin config + // - argv: this allows tests to extend argv in the same way the argv would + // be passed in via a CLI arg. + // - excludeNpmCwd: this is a hack to get @npmcli/config to stop walking up + // dirs to set a local prefix when it encounters the `npmRoot`. this + // allows tests created by tap inside this repo to not set the local + // prefix to `npmRoot` since that is the first dir it would encounter when + // doing implicit detection + constructor ({ npmRoot = dirname(__dirname), argv = [], excludeNpmCwd = false } = {}) { + super() + this.#npmRoot = npmRoot + this.config = new Config({ + npmPath: this.#npmRoot, + definitions, + flatten, + shorthands, + argv: [...process.argv, ...argv], + excludeNpmCwd, + }) + } get version () { return this.constructor.version @@ -89,44 +106,31 @@ class Npm extends EventEmitter { async cmd (cmd) { await this.load() - // when location isn't set and global isn't true - // check for a package.json at the localPrefix - // and set the location to project if found - // TODO: this logic can move to the config module loadLocalPrefix to - // avoid double stat calls and consolidate logic - if (this.config.isDefault('location') && !this.config.get('global')) { - const hasPackageJson = await fs.stat(resolve(this.config.localPrefix, 'package.json')) - .then((st) => st.isFile()) - .catch(() => false) - if (hasPackageJson) { - this.config.set('location', 'project') - } - } - - const command = this.deref(cmd) - if (!command) { + const cmdId = this.deref(cmd) + if (!cmdId) { throw Object.assign(new Error(`Unknown command ${cmd}`), { code: 'EUNKNOWNCOMMAND', }) } - const Impl = require(`./commands/${command}.js`) - const impl = new Impl(this) - return impl - } - // Call an npm command - async exec (cmd, args) { - const command = await this.cmd(cmd) - const timeEnd = this.time(`command:${cmd}`) + const Impl = require(`./commands/${cmdId}.js`) + const command = new Impl(this) // since 'test', 'start', 'stop', etc. commands re-enter this function // to call the run-script command, we need to only set it one time. - if (!this.command) { - process.env.npm_command = command.name - this.command = command.name - this.commandInstance = command + if (!this.#command) { + this.#command = command + process.env.npm_command = this.command } + return command + } + + // Call an npm command + async exec (cmd, args = this.argv) { + const command = await this.cmd(cmd) + const timeEnd = this.time(`command:${cmd}`) + // this is async but we dont await it, since its ok if it doesnt // finish before the command finishes running. it uses command and argv // so it must be initiated here, after the command name is set @@ -135,72 +139,27 @@ class Npm extends EventEmitter { // Options are prefixed by a hyphen-minus (-, \u2d). // Other dash-type chars look similar but are invalid. - if (!warnedNonDashArg) { - args - .filter(arg => /^[\u2010-\u2015\u2212\uFE58\uFE63\uFF0D]/.test(arg)) - .forEach(arg => { - warnedNonDashArg = true - log.error( - 'arg', - 'Argument starts with non-ascii dash, this is probably invalid:', - arg - ) - }) - } - - const workspacesEnabled = this.config.get('workspaces') - // if cwd is a workspace, the default is set to [that workspace] - const implicitWorkspace = this.config.get('workspace', 'default').length > 0 - const workspacesFilters = this.config.get('workspace') - const includeWorkspaceRoot = this.config.get('include-workspace-root') - // only call execWorkspaces when we have workspaces explicitly set - // or when it is implicit and not in our ignore list - const hasWorkspaceFilters = workspacesFilters.length > 0 - const invalidWorkspaceConfig = workspacesEnabled === false && hasWorkspaceFilters - - // (-ws || -w foo) && (cwd is not a workspace || command is not ignoring implicit workspaces) - const filterByWorkspaces = (workspacesEnabled || hasWorkspaceFilters) && - (!implicitWorkspace || !command.ignoreImplicitWorkspace) - // normally this would go in the constructor, but our tests don't - // actually use a real npm object so this.npm.config isn't always - // populated. this is the compromise until we can make that a reality - // and then move this into the constructor. - command.workspaces = workspacesEnabled - command.workspacePaths = null - // normally this would be evaluated in base-command#setWorkspaces, see - // above for explanation - command.includeWorkspaceRoot = includeWorkspaceRoot - - let execPromise = Promise.resolve() - if (this.config.get('usage')) { - this.output(command.usage) - } else if (invalidWorkspaceConfig) { - execPromise = Promise.reject( - new Error('Can not use --no-workspaces and --workspace at the same time')) - } else if (filterByWorkspaces) { - if (this.global) { - execPromise = Promise.reject(new Error('Workspaces not supported for global packages')) - } else { - execPromise = command.execWorkspaces(args, workspacesFilters) + if (!this.#warnedNonDashArg) { + const nonDashArgs = args.filter(a => /^[\u2010-\u2015\u2212\uFE58\uFE63\uFF0D]/.test(a)) + if (nonDashArgs.length) { + this.#warnedNonDashArg = true + log.error( + 'arg', + 'Argument starts with non-ascii dash, this is probably invalid:', + nonDashArgs.join(', ') + ) } - } else { - execPromise = command.exec(args) } - return execPromise.finally(timeEnd) + return command.cmdExec(args).finally(timeEnd) } async load () { if (!this.#loadPromise) { - this.#loadPromise = this.time('npm:load', async () => { - await this[_load]().catch((er) => { - this.loadErr = er - throw er - }) - if (this.config.get('force')) { - log.warn('using --force', 'Recommended protections disabled.') - } - }) + this.#loadPromise = this.time('npm:load', () => this.#load().catch((er) => { + this.loadErr = er + throw er + })) } return this.#loadPromise } @@ -240,21 +199,17 @@ class Npm extends EventEmitter { this.#title = t } - async [_load] () { - const node = this.time('npm:load:whichnode', () => { - try { - return which.sync(process.argv[0]) - } catch { - // TODO should we throw here? + async #load () { + await this.time('npm:load:whichnode', async () => { + // TODO should we throw here? + const node = await which(process.argv[0]).catch(() => {}) + if (node && node.toUpperCase() !== process.execPath.toUpperCase()) { + log.verbose('node symlink', node) + process.execPath = node + this.config.execPath = node } }) - if (node && node.toUpperCase() !== process.execPath.toUpperCase()) { - log.verbose('node symlink', node) - process.execPath = node - this.config.execPath = node - } - await this.time('npm:load:configload', () => this.config.load()) // mkdir this separately since the logs dir can be set to @@ -323,6 +278,18 @@ class Npm extends EventEmitter { this.config.set('scope', `@${configScope}`, this.config.find('scope')) } }) + + if (this.config.get('force')) { + log.warn('using --force', 'Recommended protections disabled.') + } + } + + get isShellout () { + return this.#command?.constructor?.isShellout + } + + get command () { + return this.#command?.name } get flatOptions () { @@ -346,6 +313,10 @@ class Npm extends EventEmitter { return this.flatOptions.color } + get logColor () { + return this.flatOptions.logColor + } + get chalk () { if (!this.#chalk) { let level = chalk.level @@ -361,10 +332,6 @@ class Npm extends EventEmitter { return this.config.get('global') || this.config.get('location') === 'global' } - get logColor () { - return this.flatOptions.logColor - } - get silent () { return this.flatOptions.silent } @@ -401,6 +368,10 @@ class Npm extends EventEmitter { return this.#timers.file } + get npmRoot () { + return this.#npmRoot + } + get cache () { return this.config.get('cache') } @@ -425,6 +396,10 @@ class Npm extends EventEmitter { this.config.localPrefix = r } + get localPackage () { + return this.config.localPackage + } + get globalDir () { return process.platform !== 'win32' ? resolve(this.globalPrefix, 'lib', 'node_modules') diff --git a/deps/npm/lib/package-url-cmd.js b/deps/npm/lib/package-url-cmd.js index eac2bbe1b6d516..20e6a16fe15230 100644 --- a/deps/npm/lib/package-url-cmd.js +++ b/deps/npm/lib/package-url-cmd.js @@ -9,7 +9,6 @@ const log = require('./utils/log-shim') const BaseCommand = require('./base-command.js') class PackageUrlCommand extends BaseCommand { - static ignoreImplicitWorkspace = false static params = [ 'browser', 'registry', @@ -18,6 +17,8 @@ class PackageUrlCommand extends BaseCommand { 'include-workspace-root', ] + static workspaces = true + static ignoreImplicitWorkspace = false static usage = ['[ [ ...]]'] async exec (args) { @@ -41,11 +42,11 @@ class PackageUrlCommand extends BaseCommand { } } - async execWorkspaces (args, filters) { + async execWorkspaces (args) { if (args && args.length) { return this.exec(args) } - await this.setWorkspaces(filters) + await this.setWorkspaces() return this.exec(this.workspacePaths) } diff --git a/deps/npm/lib/utils/config/definitions.js b/deps/npm/lib/utils/config/definitions.js index 0f401d6572a59c..9ddbafd46f7bc8 100644 --- a/deps/npm/lib/utils/config/definitions.js +++ b/deps/npm/lib/utils/config/definitions.js @@ -163,7 +163,7 @@ define('access', { `, type: [null, 'restricted', 'public'], description: ` - If do not want your scoped package to be publicly viewable (and + If you do not want your scoped package to be publicly viewable (and installable) set \`--access=restricted\`. Unscoped packages can not be set to \`restricted\`. @@ -238,6 +238,7 @@ define('auth-type', { type: ['legacy', 'web'], description: ` What authentication strategy to use with \`login\`. + Note that if an \`otp\` config is given, this value will always be set to \`legacy\`. `, flatten, }) @@ -848,7 +849,7 @@ define('global-style', { type: Boolean, description: ` Only install direct dependencies in the top level \`node_modules\`, - but hoist on deeper dependendencies. + but hoist on deeper dependencies. Sets \`--install-strategy=shallow\`. `, deprecated: ` @@ -1465,7 +1466,13 @@ define('otp', { If not set, and a registry response fails with a challenge for a one-time password, npm will prompt on the command line for one. `, - flatten, + flatten (key, obj, flatOptions) { + flatten(key, obj, flatOptions) + if (obj.otp) { + obj['auth-type'] = 'legacy' + flatten('auth-type', obj, flatOptions) + } + }, }) define('package', { @@ -2021,7 +2028,7 @@ define('strict-peer-deps', { even if doing so will result in some packages receiving a peer dependency outside the range set in their package's \`peerDependencies\` object. - When such and override is performed, a warning is printed, explaining the + When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If \`--strict-peer-deps\` is set, then this warning is treated as a failure. `, @@ -2141,6 +2148,7 @@ define('unicode', { When set to true, npm uses unicode characters in the tree output. When false, it uses ascii characters instead of unicode glyphs. `, + flatten, }) define('update-notifier', { diff --git a/deps/npm/lib/utils/error-message.js b/deps/npm/lib/utils/error-message.js index aee376120ba278..72c7b9fe4553fd 100644 --- a/deps/npm/lib/utils/error-message.js +++ b/deps/npm/lib/utils/error-message.js @@ -5,7 +5,21 @@ const replaceInfo = require('./replace-info.js') const { report } = require('./explain-eresolve.js') const log = require('./log-shim') -module.exports = (er, npm) => { +const messageText = msg => msg.map(line => line.slice(1).join(' ')).join('\n') + +const jsonError = (er, npm, { summary, detail }) => { + if (npm?.config.loaded && npm.config.get('json')) { + return { + error: { + code: er.code, + summary: messageText(summary), + detail: messageText(detail), + }, + } + } +} + +const errorMessage = (er, npm) => { const short = [] const detail = [] const files = [] @@ -329,7 +343,7 @@ module.exports = (er, npm) => { 'Actual: ' + JSON.stringify({ npm: npm.version, - node: npm.config.loaded ? npm.config.get('node-version') : process.version, + node: process.version, }), ].join('\n'), ]) @@ -402,5 +416,7 @@ module.exports = (er, npm) => { break } - return { summary: short, detail, files } + return { summary: short, detail, files, json: jsonError(er, npm, { summary: short, detail }) } } + +module.exports = errorMessage diff --git a/deps/npm/lib/utils/exit-handler.js b/deps/npm/lib/utils/exit-handler.js index a9e061de7a4a53..b5fc7042bd0209 100644 --- a/deps/npm/lib/utils/exit-handler.js +++ b/deps/npm/lib/utils/exit-handler.js @@ -5,7 +5,6 @@ const log = require('./log-shim.js') const errorMessage = require('./error-message.js') const replaceInfo = require('./replace-info.js') -const messageText = msg => msg.map(line => line.slice(1).join(' ')).join('\n') const indent = (val) => Array.isArray(val) ? val.map(v => indent(v)) : ` ${val}` let npm = null // set by the cli @@ -144,7 +143,7 @@ const exitHandler = err => { // will presumably print its own errors and exit with a proper status // code if there's a problem. If we got an error with a code=0, then... // something else went wrong along the way, so maybe an npm problem? - const isShellout = npm.commandInstance && npm.commandInstance.constructor.isShellout + const isShellout = npm.isShellout const quietShellout = isShellout && typeof err.code === 'number' && err.code if (quietShellout) { exitCode = err.code @@ -181,7 +180,8 @@ const exitHandler = err => { } } - const { summary, detail, files = [] } = errorMessage(err, npm) + const { summary, detail, json, files = [] } = errorMessage(err, npm) + jsonError = json for (let [file, content] of files) { file = `${npm.logPath}${file}` @@ -189,8 +189,8 @@ const exitHandler = err => { try { fs.writeFileSync(file, content) detail.push(['', `\n\nFor a full report see:\n${file}`]) - } catch (err) { - log.warn('', `Could not write error message to ${file} due to ${err}`) + } catch (logFileErr) { + log.warn('', `Could not write error message to ${file} due to ${logFileErr}`) } } @@ -198,16 +198,6 @@ const exitHandler = err => { log.error(...errline) } - if (hasLoadedNpm && npm.config.get('json')) { - jsonError = { - error: { - code: err.code, - summary: messageText(summary), - detail: messageText(detail), - }, - } - } - if (typeof err.errno === 'number') { exitCode = err.errno } else if (typeof err.code === 'number') { diff --git a/deps/npm/lib/utils/explain-dep.js b/deps/npm/lib/utils/explain-dep.js index cd53a2269640e6..58258026491dc1 100644 --- a/deps/npm/lib/utils/explain-dep.js +++ b/deps/npm/lib/utils/explain-dep.js @@ -103,13 +103,13 @@ const explainDependents = ({ name, dependents }, depth, color) => { const maxLen = 50 const showNames = [] for (let i = max; i < dependents.length; i++) { - const { from: { name = 'the root project' } } = dependents[i] - len += name.length + const { from: { name: depName = 'the root project' } } = dependents[i] + len += depName.length if (len >= maxLen && i < dependents.length - 1) { showNames.push('...') break } - showNames.push(name) + showNames.push(depName) } const show = `(${showNames.join(', ')})` messages.push(`${dependents.length - max} more ${show}`) diff --git a/deps/npm/lib/utils/log-file.js b/deps/npm/lib/utils/log-file.js index 2935697ac98ebc..f663997308ed6b 100644 --- a/deps/npm/lib/utils/log-file.js +++ b/deps/npm/lib/utils/log-file.js @@ -1,10 +1,10 @@ const os = require('os') -const path = require('path') +const { join, dirname, basename } = require('path') const { format, promisify } = require('util') -const rimraf = promisify(require('rimraf')) const glob = promisify(require('glob')) const MiniPass = require('minipass') const fsMiniPass = require('fs-minipass') +const fs = require('fs/promises') const log = require('./log-shim') const padZero = (n, length) => n.toString().padStart(length.toString().length, '0') @@ -197,7 +197,7 @@ class LogFiles { try { const logPath = this.#getLogFilePath() - const logGlob = path.join(path.dirname(logPath), path.basename(logPath) + const logGlob = join(dirname(logPath), basename(logPath) // tell glob to only match digits .replace(/\d/g, '[0123456789]') // Handle the old (prior to 8.2.0) log file names which did not have a @@ -217,7 +217,7 @@ class LogFiles { for (const file of files.slice(0, toDelete)) { try { - await rimraf(file, { glob: false }) + await fs.rm(file, { force: true }) } catch (e) { log.silly('logfile', 'error removing log file', file, e) } diff --git a/deps/npm/lib/utils/npm-usage.js b/deps/npm/lib/utils/npm-usage.js index 947a3073bc5ffe..b04ad33f9dd79f 100644 --- a/deps/npm/lib/utils/npm-usage.js +++ b/deps/npm/lib/utils/npm-usage.js @@ -1,4 +1,3 @@ -const { dirname } = require('path') const { commands } = require('./cmd-list') const COL_MAX = 60 @@ -36,7 +35,7 @@ or on the command line via: npm --key=value More configuration info: npm help config Configuration fields: npm help 7 config -npm@${npm.version} ${dirname(dirname(__dirname))}` +npm@${npm.version} ${npm.npmRoot}` } const cmdNames = () => { diff --git a/deps/npm/lib/utils/open-url.js b/deps/npm/lib/utils/open-url.js index 379640773fa6e2..f882d0c9d39341 100644 --- a/deps/npm/lib/utils/open-url.js +++ b/deps/npm/lib/utils/open-url.js @@ -31,7 +31,7 @@ const open = async (npm, url, errMsg, isFile) => { if (!/^https?:$/.test(new URL(url).protocol)) { throw new Error() } - } catch (_) { + } catch { throw new Error('Invalid URL: ' + url) } } diff --git a/deps/npm/lib/utils/queryable.js b/deps/npm/lib/utils/queryable.js index 7c5bb7fe87baff..6acc1758ceea70 100644 --- a/deps/npm/lib/utils/queryable.js +++ b/deps/npm/lib/utils/queryable.js @@ -1,5 +1,4 @@ const util = require('util') -const _data = Symbol('data') const _delete = Symbol('delete') const _append = Symbol('append') @@ -236,6 +235,8 @@ const setter = ({ data, key, value, force }) => { } class Queryable { + #data = null + constructor (obj) { if (!obj || typeof obj !== 'object') { throw Object.assign(new Error('Queryable needs an object to query properties from.'), { @@ -243,7 +244,7 @@ class Queryable { }) } - this[_data] = obj + this.#data = obj } query (queries) { @@ -251,12 +252,12 @@ class Queryable { // with the legacy API lib/view.js is consuming, if at some point // we refactor that command then we can revisit making this nicer if (queries === '') { - return { '': this[_data] } + return { '': this.#data } } const q = query => getter({ - data: this[_data], + data: this.#data, key: query, }) @@ -283,7 +284,7 @@ class Queryable { // and assigns `value` to the last property of the query chain set (query, value, { force } = {}) { setter({ - data: this[_data], + data: this.#data, key: query, value, force, @@ -293,14 +294,14 @@ class Queryable { // deletes the value of the property found at `query` delete (query) { setter({ - data: this[_data], + data: this.#data, key: query, value: _delete, }) } toJSON () { - return this[_data] + return this.#data } [util.inspect.custom] () { diff --git a/deps/npm/lib/utils/read-user-info.js b/deps/npm/lib/utils/read-user-info.js index ac24396c6abb94..26d5b36d55b582 100644 --- a/deps/npm/lib/utils/read-user-info.js +++ b/deps/npm/lib/utils/read-user-info.js @@ -28,7 +28,7 @@ function readOTP (msg = otpPrompt, otp, isRetry) { } return read({ prompt: msg, default: otp || '' }) - .then((otp) => readOTP(msg, otp, true)) + .then((rOtp) => readOTP(msg, rOtp, true)) } function readPassword (msg = passwordPrompt, password, isRetry) { @@ -37,7 +37,7 @@ function readPassword (msg = passwordPrompt, password, isRetry) { } return read({ prompt: msg, silent: true, default: password || '' }) - .then((password) => readPassword(msg, password, true)) + .then((rPassword) => readPassword(msg, rPassword, true)) } function readUsername (msg = usernamePrompt, username, isRetry) { @@ -51,7 +51,7 @@ function readUsername (msg = usernamePrompt, username, isRetry) { } return read({ prompt: msg, default: username || '' }) - .then((username) => readUsername(msg, username, true)) + .then((rUsername) => readUsername(msg, rUsername, true)) } function readEmail (msg = emailPrompt, email, isRetry) { diff --git a/deps/npm/lib/utils/reify-output.js b/deps/npm/lib/utils/reify-output.js index b5c3a593b8db0b..5ac7fa4b01896b 100644 --- a/deps/npm/lib/utils/reify-output.js +++ b/deps/npm/lib/utils/reify-output.js @@ -12,7 +12,7 @@ const log = require('./log-shim.js') const { depth } = require('treeverse') const ms = require('ms') -const auditReport = require('npm-audit-report') +const npmAuditReport = require('npm-audit-report') const { readTree: getFundingInfo } = require('libnpmfund') const auditError = require('./audit-error.js') @@ -112,7 +112,7 @@ const getAuditReport = (npm, report) => { const defaultAuditLevel = npm.command !== 'audit' ? 'none' : 'low' const auditLevel = npm.flatOptions.auditLevel || defaultAuditLevel - const res = auditReport(report, { + const res = npmAuditReport(report, { reporter, ...npm.flatOptions, auditLevel, diff --git a/deps/npm/lib/workspaces/get-workspaces.js b/deps/npm/lib/workspaces/get-workspaces.js index 373af1d689cc31..2ac043d5f3943d 100644 --- a/deps/npm/lib/workspaces/get-workspaces.js +++ b/deps/npm/lib/workspaces/get-workspaces.js @@ -42,7 +42,7 @@ const getWorkspaces = async (filters, { path, includeWorkspaceRoot, relativeFrom let msg = '!' if (filters.length) { msg = `:\n ${filters.reduce( - (res, filterArg) => `${res} --workspace=${filterArg}`, '')}` + (acc, filterArg) => `${acc} --workspace=${filterArg}`, '')}` } throw new Error(`No workspaces found${msg}`) diff --git a/deps/npm/man/man1/npm-access.1 b/deps/npm/man/man1/npm-access.1 index 7cfb97a9bdd3f9..91381c80c2c909 100644 --- a/deps/npm/man/man1/npm-access.1 +++ b/deps/npm/man/man1/npm-access.1 @@ -1,4 +1,4 @@ -.TH "NPM-ACCESS" "1" "December 2022" "" "" +.TH "NPM-ACCESS" "1" "January 2023" "" "" .SH "NAME" \fBnpm-access\fR - Set access level on published packages .SS "Synopsis" @@ -14,6 +14,8 @@ npm access grant \[lB]\[rB] npm access revoke \[lB]\[rB] .fi .RE +.P +Note: This command is unaware of workspaces. .SS "Description" .P Used to set access controls on private packages. diff --git a/deps/npm/man/man1/npm-adduser.1 b/deps/npm/man/man1/npm-adduser.1 index e5de0dff8fb5ea..4e9a687fb6752c 100644 --- a/deps/npm/man/man1/npm-adduser.1 +++ b/deps/npm/man/man1/npm-adduser.1 @@ -1,4 +1,4 @@ -.TH "NPM-ADDUSER" "1" "December 2022" "" "" +.TH "NPM-ADDUSER" "1" "January 2023" "" "" .SH "NAME" \fBnpm-adduser\fR - Add a registry user account .SS "Synopsis" @@ -71,7 +71,7 @@ Type: "legacy" or "web" .RE 0 .P -What authentication strategy to use with \fBlogin\fR. +What authentication strategy to use with \fBlogin\fR. Note that if an \fBotp\fR config is given, this value will always be set to \fBlegacy\fR. .SS "See Also" .RS 0 .IP \(bu 4 diff --git a/deps/npm/man/man1/npm-audit.1 b/deps/npm/man/man1/npm-audit.1 index e9d4063a5cec8d..f99fa41719b110 100644 --- a/deps/npm/man/man1/npm-audit.1 +++ b/deps/npm/man/man1/npm-audit.1 @@ -1,4 +1,4 @@ -.TH "NPM-AUDIT" "1" "December 2022" "" "" +.TH "NPM-AUDIT" "1" "January 2023" "" "" .SH "NAME" \fBnpm-audit\fR - Run a security audit .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-bugs.1 b/deps/npm/man/man1/npm-bugs.1 index 7d057e965a8664..61d2835a912352 100644 --- a/deps/npm/man/man1/npm-bugs.1 +++ b/deps/npm/man/man1/npm-bugs.1 @@ -1,4 +1,4 @@ -.TH "NPM-BUGS" "1" "December 2022" "" "" +.TH "NPM-BUGS" "1" "January 2023" "" "" .SH "NAME" \fBnpm-bugs\fR - Report bugs for a package in a web browser .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-cache.1 b/deps/npm/man/man1/npm-cache.1 index 1cd91027282fd3..026f08d17d1ca2 100644 --- a/deps/npm/man/man1/npm-cache.1 +++ b/deps/npm/man/man1/npm-cache.1 @@ -1,4 +1,4 @@ -.TH "NPM-CACHE" "1" "December 2022" "" "" +.TH "NPM-CACHE" "1" "January 2023" "" "" .SH "NAME" \fBnpm-cache\fR - Manipulates packages cache .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-ci.1 b/deps/npm/man/man1/npm-ci.1 index e5fa670750432b..9335c9aec45f8c 100644 --- a/deps/npm/man/man1/npm-ci.1 +++ b/deps/npm/man/man1/npm-ci.1 @@ -1,4 +1,4 @@ -.TH "NPM-CI" "1" "December 2022" "" "" +.TH "NPM-CI" "1" "January 2023" "" "" .SH "NAME" \fBnpm-ci\fR - Clean install a project .SS "Synopsis" @@ -142,7 +142,7 @@ DEPRECATED: This option has been deprecated in favor of \fB--install-strategy=sh .RE 0 .P -Only install direct dependencies in the top level \fBnode_modules\fR, but hoist on deeper dependendencies. Sets \fB--install-strategy=shallow\fR. +Only install direct dependencies in the top level \fBnode_modules\fR, but hoist on deeper dependencies. Sets \fB--install-strategy=shallow\fR. .SS "\fBomit\fR" .RS 0 .IP \(bu 4 @@ -172,7 +172,7 @@ If set to \fBtrue\fR, and \fB--legacy-peer-deps\fR is not set, then \fIany\fR co .P By default, conflicting \fBpeerDependencies\fR deep in the dependency graph will be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's \fBpeerDependencies\fR object. .P -When such and override is performed, a warning is printed, explaining the conflict and the packages involved. If \fB--strict-peer-deps\fR is set, then this warning is treated as a failure. +When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If \fB--strict-peer-deps\fR is set, then this warning is treated as a failure. .SS "\fBpackage-lock\fR" .RS 0 .IP \(bu 4 diff --git a/deps/npm/man/man1/npm-completion.1 b/deps/npm/man/man1/npm-completion.1 index 2d66e7e042b77d..c2f5d2a2506d23 100644 --- a/deps/npm/man/man1/npm-completion.1 +++ b/deps/npm/man/man1/npm-completion.1 @@ -1,4 +1,4 @@ -.TH "NPM-COMPLETION" "1" "December 2022" "" "" +.TH "NPM-COMPLETION" "1" "January 2023" "" "" .SH "NAME" \fBnpm-completion\fR - Tab Completion for npm .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-config.1 b/deps/npm/man/man1/npm-config.1 index ea57fe94b002ee..1f4e831af8d63b 100644 --- a/deps/npm/man/man1/npm-config.1 +++ b/deps/npm/man/man1/npm-config.1 @@ -1,4 +1,4 @@ -.TH "NPM-CONFIG" "1" "December 2022" "" "" +.TH "NPM-CONFIG" "1" "January 2023" "" "" .SH "NAME" \fBnpm-config\fR - Manage the npm configuration files .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-dedupe.1 b/deps/npm/man/man1/npm-dedupe.1 index bbd1fc413d77c7..ff45a8d0fd0a43 100644 --- a/deps/npm/man/man1/npm-dedupe.1 +++ b/deps/npm/man/man1/npm-dedupe.1 @@ -1,4 +1,4 @@ -.TH "NPM-DEDUPE" "1" "December 2022" "" "" +.TH "NPM-DEDUPE" "1" "January 2023" "" "" .SH "NAME" \fBnpm-dedupe\fR - Reduce duplication in the package tree .SS "Synopsis" @@ -98,7 +98,7 @@ DEPRECATED: This option has been deprecated in favor of \fB--install-strategy=sh .RE 0 .P -Only install direct dependencies in the top level \fBnode_modules\fR, but hoist on deeper dependendencies. Sets \fB--install-strategy=shallow\fR. +Only install direct dependencies in the top level \fBnode_modules\fR, but hoist on deeper dependencies. Sets \fB--install-strategy=shallow\fR. .SS "\fBstrict-peer-deps\fR" .RS 0 .IP \(bu 4 @@ -112,7 +112,7 @@ If set to \fBtrue\fR, and \fB--legacy-peer-deps\fR is not set, then \fIany\fR co .P By default, conflicting \fBpeerDependencies\fR deep in the dependency graph will be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's \fBpeerDependencies\fR object. .P -When such and override is performed, a warning is printed, explaining the conflict and the packages involved. If \fB--strict-peer-deps\fR is set, then this warning is treated as a failure. +When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If \fB--strict-peer-deps\fR is set, then this warning is treated as a failure. .SS "\fBpackage-lock\fR" .RS 0 .IP \(bu 4 diff --git a/deps/npm/man/man1/npm-deprecate.1 b/deps/npm/man/man1/npm-deprecate.1 index e97357b5bcae1b..ad4f34b53c263e 100644 --- a/deps/npm/man/man1/npm-deprecate.1 +++ b/deps/npm/man/man1/npm-deprecate.1 @@ -1,4 +1,4 @@ -.TH "NPM-DEPRECATE" "1" "December 2022" "" "" +.TH "NPM-DEPRECATE" "1" "January 2023" "" "" .SH "NAME" \fBnpm-deprecate\fR - Deprecate a version of a package .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-diff.1 b/deps/npm/man/man1/npm-diff.1 index b9f11879b79623..410548534a6e0d 100644 --- a/deps/npm/man/man1/npm-diff.1 +++ b/deps/npm/man/man1/npm-diff.1 @@ -1,4 +1,4 @@ -.TH "NPM-DIFF" "1" "December 2022" "" "" +.TH "NPM-DIFF" "1" "January 2023" "" "" .SH "NAME" \fBnpm-diff\fR - The registry diff command .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-dist-tag.1 b/deps/npm/man/man1/npm-dist-tag.1 index bf05b601a81cd6..f87010d6019de8 100644 --- a/deps/npm/man/man1/npm-dist-tag.1 +++ b/deps/npm/man/man1/npm-dist-tag.1 @@ -1,4 +1,4 @@ -.TH "NPM-DIST-TAG" "1" "December 2022" "" "" +.TH "NPM-DIST-TAG" "1" "January 2023" "" "" .SH "NAME" \fBnpm-dist-tag\fR - Modify package distribution tags .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-docs.1 b/deps/npm/man/man1/npm-docs.1 index d5901813913f31..c3832ae6f52279 100644 --- a/deps/npm/man/man1/npm-docs.1 +++ b/deps/npm/man/man1/npm-docs.1 @@ -1,4 +1,4 @@ -.TH "NPM-DOCS" "1" "December 2022" "" "" +.TH "NPM-DOCS" "1" "January 2023" "" "" .SH "NAME" \fBnpm-docs\fR - Open documentation for a package in a web browser .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-doctor.1 b/deps/npm/man/man1/npm-doctor.1 index 776d50ea8edd6b..a33e7acf628325 100644 --- a/deps/npm/man/man1/npm-doctor.1 +++ b/deps/npm/man/man1/npm-doctor.1 @@ -1,4 +1,4 @@ -.TH "NPM-DOCTOR" "1" "December 2022" "" "" +.TH "NPM-DOCTOR" "1" "January 2023" "" "" .SH "NAME" \fBnpm-doctor\fR - Check your npm environment .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-edit.1 b/deps/npm/man/man1/npm-edit.1 index 80f7a55df5ab90..4b933ac01c88a4 100644 --- a/deps/npm/man/man1/npm-edit.1 +++ b/deps/npm/man/man1/npm-edit.1 @@ -1,4 +1,4 @@ -.TH "NPM-EDIT" "1" "December 2022" "" "" +.TH "NPM-EDIT" "1" "January 2023" "" "" .SH "NAME" \fBnpm-edit\fR - Edit an installed package .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-exec.1 b/deps/npm/man/man1/npm-exec.1 index b13c9f3d21465d..b8b6cc7e96187a 100644 --- a/deps/npm/man/man1/npm-exec.1 +++ b/deps/npm/man/man1/npm-exec.1 @@ -1,4 +1,4 @@ -.TH "NPM-EXEC" "1" "December 2022" "" "" +.TH "NPM-EXEC" "1" "January 2023" "" "" .SH "NAME" \fBnpm-exec\fR - Run a command from a local or remote npm package .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-explain.1 b/deps/npm/man/man1/npm-explain.1 index 6897f448190ff0..b1b5305d0d99e7 100644 --- a/deps/npm/man/man1/npm-explain.1 +++ b/deps/npm/man/man1/npm-explain.1 @@ -1,4 +1,4 @@ -.TH "NPM-EXPLAIN" "1" "December 2022" "" "" +.TH "NPM-EXPLAIN" "1" "January 2023" "" "" .SH "NAME" \fBnpm-explain\fR - Explain installed packages .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-explore.1 b/deps/npm/man/man1/npm-explore.1 index fed8a1b25a3538..de402db28c648e 100644 --- a/deps/npm/man/man1/npm-explore.1 +++ b/deps/npm/man/man1/npm-explore.1 @@ -1,4 +1,4 @@ -.TH "NPM-EXPLORE" "1" "December 2022" "" "" +.TH "NPM-EXPLORE" "1" "January 2023" "" "" .SH "NAME" \fBnpm-explore\fR - Browse an installed package .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-find-dupes.1 b/deps/npm/man/man1/npm-find-dupes.1 index fe29d9dd7fe311..5ec681c48c39ea 100644 --- a/deps/npm/man/man1/npm-find-dupes.1 +++ b/deps/npm/man/man1/npm-find-dupes.1 @@ -1,4 +1,4 @@ -.TH "NPM-FIND-DUPES" "1" "December 2022" "" "" +.TH "NPM-FIND-DUPES" "1" "January 2023" "" "" .SH "NAME" \fBnpm-find-dupes\fR - Find duplication in the package tree .SS "Synopsis" @@ -45,7 +45,7 @@ DEPRECATED: This option has been deprecated in favor of \fB--install-strategy=sh .RE 0 .P -Only install direct dependencies in the top level \fBnode_modules\fR, but hoist on deeper dependendencies. Sets \fB--install-strategy=shallow\fR. +Only install direct dependencies in the top level \fBnode_modules\fR, but hoist on deeper dependencies. Sets \fB--install-strategy=shallow\fR. .SS "\fBstrict-peer-deps\fR" .RS 0 .IP \(bu 4 @@ -59,7 +59,7 @@ If set to \fBtrue\fR, and \fB--legacy-peer-deps\fR is not set, then \fIany\fR co .P By default, conflicting \fBpeerDependencies\fR deep in the dependency graph will be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's \fBpeerDependencies\fR object. .P -When such and override is performed, a warning is printed, explaining the conflict and the packages involved. If \fB--strict-peer-deps\fR is set, then this warning is treated as a failure. +When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If \fB--strict-peer-deps\fR is set, then this warning is treated as a failure. .SS "\fBpackage-lock\fR" .RS 0 .IP \(bu 4 diff --git a/deps/npm/man/man1/npm-fund.1 b/deps/npm/man/man1/npm-fund.1 index b5f2cbdd58e2fb..7c1fe64f033cd1 100644 --- a/deps/npm/man/man1/npm-fund.1 +++ b/deps/npm/man/man1/npm-fund.1 @@ -1,4 +1,4 @@ -.TH "NPM-FUND" "1" "December 2022" "" "" +.TH "NPM-FUND" "1" "January 2023" "" "" .SH "NAME" \fBnpm-fund\fR - Retrieve funding information .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-help-search.1 b/deps/npm/man/man1/npm-help-search.1 index 939aa4fd343ced..5d7a40e7ca3cec 100644 --- a/deps/npm/man/man1/npm-help-search.1 +++ b/deps/npm/man/man1/npm-help-search.1 @@ -1,4 +1,4 @@ -.TH "NPM-HELP-SEARCH" "1" "December 2022" "" "" +.TH "NPM-HELP-SEARCH" "1" "January 2023" "" "" .SH "NAME" \fBnpm-help-search\fR - Search npm help documentation .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-help.1 b/deps/npm/man/man1/npm-help.1 index 15b73a5ce73164..c0e77e0b5fc83d 100644 --- a/deps/npm/man/man1/npm-help.1 +++ b/deps/npm/man/man1/npm-help.1 @@ -1,4 +1,4 @@ -.TH "NPM-HELP" "1" "December 2022" "" "" +.TH "NPM-HELP" "1" "January 2023" "" "" .SH "NAME" \fBnpm-help\fR - Get help on npm .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-hook.1 b/deps/npm/man/man1/npm-hook.1 index d38ad36171c5a6..8ba80f625cebbb 100644 --- a/deps/npm/man/man1/npm-hook.1 +++ b/deps/npm/man/man1/npm-hook.1 @@ -1,4 +1,4 @@ -.TH "NPM-HOOK" "1" "December 2022" "" "" +.TH "NPM-HOOK" "1" "January 2023" "" "" .SH "NAME" \fBnpm-hook\fR - Manage registry hooks .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-init.1 b/deps/npm/man/man1/npm-init.1 index 298bdecf3e9fab..f5fc5fbc359195 100644 --- a/deps/npm/man/man1/npm-init.1 +++ b/deps/npm/man/man1/npm-init.1 @@ -1,11 +1,11 @@ -.TH "NPM-INIT" "1" "December 2022" "" "" +.TH "NPM-INIT" "1" "January 2023" "" "" .SH "NAME" \fBnpm-init\fR - Create a package.json file .SS "Synopsis" .P .RS 2 .nf -npm init (same as `npx ) +npm init (same as `npx `) npm init <@scope> (same as `npx <@scope>/create`) aliases: create, innit diff --git a/deps/npm/man/man1/npm-install-ci-test.1 b/deps/npm/man/man1/npm-install-ci-test.1 index 33abfcad8e4630..96b0bf5acc4c55 100644 --- a/deps/npm/man/man1/npm-install-ci-test.1 +++ b/deps/npm/man/man1/npm-install-ci-test.1 @@ -1,4 +1,4 @@ -.TH "NPM-INSTALL-CI-TEST" "1" "December 2022" "" "" +.TH "NPM-INSTALL-CI-TEST" "1" "January 2023" "" "" .SH "NAME" \fBnpm-install-ci-test\fR - Install a project with a clean slate and run tests .SS "Synopsis" @@ -90,7 +90,7 @@ DEPRECATED: This option has been deprecated in favor of \fB--install-strategy=sh .RE 0 .P -Only install direct dependencies in the top level \fBnode_modules\fR, but hoist on deeper dependendencies. Sets \fB--install-strategy=shallow\fR. +Only install direct dependencies in the top level \fBnode_modules\fR, but hoist on deeper dependencies. Sets \fB--install-strategy=shallow\fR. .SS "\fBomit\fR" .RS 0 .IP \(bu 4 @@ -120,7 +120,7 @@ If set to \fBtrue\fR, and \fB--legacy-peer-deps\fR is not set, then \fIany\fR co .P By default, conflicting \fBpeerDependencies\fR deep in the dependency graph will be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's \fBpeerDependencies\fR object. .P -When such and override is performed, a warning is printed, explaining the conflict and the packages involved. If \fB--strict-peer-deps\fR is set, then this warning is treated as a failure. +When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If \fB--strict-peer-deps\fR is set, then this warning is treated as a failure. .SS "\fBpackage-lock\fR" .RS 0 .IP \(bu 4 diff --git a/deps/npm/man/man1/npm-install-test.1 b/deps/npm/man/man1/npm-install-test.1 index 9f3914208a62d7..5b5b6823cf3ca4 100644 --- a/deps/npm/man/man1/npm-install-test.1 +++ b/deps/npm/man/man1/npm-install-test.1 @@ -1,4 +1,4 @@ -.TH "NPM-INSTALL-TEST" "1" "December 2022" "" "" +.TH "NPM-INSTALL-TEST" "1" "January 2023" "" "" .SH "NAME" \fBnpm-install-test\fR - Install package(s) and run tests .SS "Synopsis" @@ -90,7 +90,7 @@ DEPRECATED: This option has been deprecated in favor of \fB--install-strategy=sh .RE 0 .P -Only install direct dependencies in the top level \fBnode_modules\fR, but hoist on deeper dependendencies. Sets \fB--install-strategy=shallow\fR. +Only install direct dependencies in the top level \fBnode_modules\fR, but hoist on deeper dependencies. Sets \fB--install-strategy=shallow\fR. .SS "\fBomit\fR" .RS 0 .IP \(bu 4 @@ -120,7 +120,7 @@ If set to \fBtrue\fR, and \fB--legacy-peer-deps\fR is not set, then \fIany\fR co .P By default, conflicting \fBpeerDependencies\fR deep in the dependency graph will be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's \fBpeerDependencies\fR object. .P -When such and override is performed, a warning is printed, explaining the conflict and the packages involved. If \fB--strict-peer-deps\fR is set, then this warning is treated as a failure. +When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If \fB--strict-peer-deps\fR is set, then this warning is treated as a failure. .SS "\fBpackage-lock\fR" .RS 0 .IP \(bu 4 diff --git a/deps/npm/man/man1/npm-install.1 b/deps/npm/man/man1/npm-install.1 index 3211b0c6f1e9d5..55e5abe3f888a9 100644 --- a/deps/npm/man/man1/npm-install.1 +++ b/deps/npm/man/man1/npm-install.1 @@ -1,4 +1,4 @@ -.TH "NPM-INSTALL" "1" "December 2022" "" "" +.TH "NPM-INSTALL" "1" "January 2023" "" "" .SH "NAME" \fBnpm-install\fR - Install a package .SS "Synopsis" @@ -452,7 +452,7 @@ DEPRECATED: This option has been deprecated in favor of \fB--install-strategy=sh .RE 0 .P -Only install direct dependencies in the top level \fBnode_modules\fR, but hoist on deeper dependendencies. Sets \fB--install-strategy=shallow\fR. +Only install direct dependencies in the top level \fBnode_modules\fR, but hoist on deeper dependencies. Sets \fB--install-strategy=shallow\fR. .SS "\fBomit\fR" .RS 0 .IP \(bu 4 @@ -482,7 +482,7 @@ If set to \fBtrue\fR, and \fB--legacy-peer-deps\fR is not set, then \fIany\fR co .P By default, conflicting \fBpeerDependencies\fR deep in the dependency graph will be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's \fBpeerDependencies\fR object. .P -When such and override is performed, a warning is printed, explaining the conflict and the packages involved. If \fB--strict-peer-deps\fR is set, then this warning is treated as a failure. +When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If \fB--strict-peer-deps\fR is set, then this warning is treated as a failure. .SS "\fBpackage-lock\fR" .RS 0 .IP \(bu 4 diff --git a/deps/npm/man/man1/npm-link.1 b/deps/npm/man/man1/npm-link.1 index adbc8b4db5d81d..42ecdee92aa522 100644 --- a/deps/npm/man/man1/npm-link.1 +++ b/deps/npm/man/man1/npm-link.1 @@ -1,4 +1,4 @@ -.TH "NPM-LINK" "1" "December 2022" "" "" +.TH "NPM-LINK" "1" "January 2023" "" "" .SH "NAME" \fBnpm-link\fR - Symlink a package folder .SS "Synopsis" @@ -157,7 +157,7 @@ DEPRECATED: This option has been deprecated in favor of \fB--install-strategy=sh .RE 0 .P -Only install direct dependencies in the top level \fBnode_modules\fR, but hoist on deeper dependendencies. Sets \fB--install-strategy=shallow\fR. +Only install direct dependencies in the top level \fBnode_modules\fR, but hoist on deeper dependencies. Sets \fB--install-strategy=shallow\fR. .SS "\fBstrict-peer-deps\fR" .RS 0 .IP \(bu 4 @@ -171,7 +171,7 @@ If set to \fBtrue\fR, and \fB--legacy-peer-deps\fR is not set, then \fIany\fR co .P By default, conflicting \fBpeerDependencies\fR deep in the dependency graph will be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's \fBpeerDependencies\fR object. .P -When such and override is performed, a warning is printed, explaining the conflict and the packages involved. If \fB--strict-peer-deps\fR is set, then this warning is treated as a failure. +When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If \fB--strict-peer-deps\fR is set, then this warning is treated as a failure. .SS "\fBpackage-lock\fR" .RS 0 .IP \(bu 4 diff --git a/deps/npm/man/man1/npm-login.1 b/deps/npm/man/man1/npm-login.1 index 1a10ce18cdac9c..3b99aefeecf75a 100644 --- a/deps/npm/man/man1/npm-login.1 +++ b/deps/npm/man/man1/npm-login.1 @@ -1,4 +1,4 @@ -.TH "NPM-LOGIN" "1" "December 2022" "" "" +.TH "NPM-LOGIN" "1" "January 2023" "" "" .SH "NAME" \fBnpm-login\fR - Login to a registry user account .SS "Synopsis" @@ -75,7 +75,7 @@ Type: "legacy" or "web" .RE 0 .P -What authentication strategy to use with \fBlogin\fR. +What authentication strategy to use with \fBlogin\fR. Note that if an \fBotp\fR config is given, this value will always be set to \fBlegacy\fR. .SS "See Also" .RS 0 .IP \(bu 4 diff --git a/deps/npm/man/man1/npm-logout.1 b/deps/npm/man/man1/npm-logout.1 index 00201c97807783..3bb5aa671422ed 100644 --- a/deps/npm/man/man1/npm-logout.1 +++ b/deps/npm/man/man1/npm-logout.1 @@ -1,4 +1,4 @@ -.TH "NPM-LOGOUT" "1" "December 2022" "" "" +.TH "NPM-LOGOUT" "1" "January 2023" "" "" .SH "NAME" \fBnpm-logout\fR - Log out of the registry .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-ls.1 b/deps/npm/man/man1/npm-ls.1 index 114cd16526d327..2458a585b79269 100644 --- a/deps/npm/man/man1/npm-ls.1 +++ b/deps/npm/man/man1/npm-ls.1 @@ -1,4 +1,4 @@ -.TH "NPM-LS" "1" "December 2022" "" "" +.TH "NPM-LS" "1" "January 2023" "" "" .SH "NAME" \fBnpm-ls\fR - List installed packages .SS "Synopsis" @@ -20,7 +20,7 @@ Positional arguments are \fBname@version-range\fR identifiers, which will limit .P .RS 2 .nf -npm@9.2.0 /path/to/npm +npm@9.3.0 /path/to/npm └─┬ init-package-json@0.0.4 └── promzard@0.1.5 .fi diff --git a/deps/npm/man/man1/npm-org.1 b/deps/npm/man/man1/npm-org.1 index d070b6a94181d2..ba4ee6c72a5ebc 100644 --- a/deps/npm/man/man1/npm-org.1 +++ b/deps/npm/man/man1/npm-org.1 @@ -1,4 +1,4 @@ -.TH "NPM-ORG" "1" "December 2022" "" "" +.TH "NPM-ORG" "1" "January 2023" "" "" .SH "NAME" \fBnpm-org\fR - Manage orgs .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-outdated.1 b/deps/npm/man/man1/npm-outdated.1 index 0893d2d7cc7924..0cd7762886c959 100644 --- a/deps/npm/man/man1/npm-outdated.1 +++ b/deps/npm/man/man1/npm-outdated.1 @@ -1,4 +1,4 @@ -.TH "NPM-OUTDATED" "1" "December 2022" "" "" +.TH "NPM-OUTDATED" "1" "January 2023" "" "" .SH "NAME" \fBnpm-outdated\fR - Check for outdated packages .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-owner.1 b/deps/npm/man/man1/npm-owner.1 index eb30d26fa6c1be..f2015740b02cd9 100644 --- a/deps/npm/man/man1/npm-owner.1 +++ b/deps/npm/man/man1/npm-owner.1 @@ -1,4 +1,4 @@ -.TH "NPM-OWNER" "1" "December 2022" "" "" +.TH "NPM-OWNER" "1" "January 2023" "" "" .SH "NAME" \fBnpm-owner\fR - Manage package owners .SS "Synopsis" @@ -12,8 +12,6 @@ npm owner ls alias: author .fi .RE -.P -Note: This command is unaware of workspaces. .SS "Description" .P Manage ownership of published packages. diff --git a/deps/npm/man/man1/npm-pack.1 b/deps/npm/man/man1/npm-pack.1 index ccb49505cdc9e3..934bc9cf4ec176 100644 --- a/deps/npm/man/man1/npm-pack.1 +++ b/deps/npm/man/man1/npm-pack.1 @@ -1,4 +1,4 @@ -.TH "NPM-PACK" "1" "December 2022" "" "" +.TH "NPM-PACK" "1" "January 2023" "" "" .SH "NAME" \fBnpm-pack\fR - Create a tarball from a package .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-ping.1 b/deps/npm/man/man1/npm-ping.1 index 79b3258e337928..59c5191676dba1 100644 --- a/deps/npm/man/man1/npm-ping.1 +++ b/deps/npm/man/man1/npm-ping.1 @@ -1,4 +1,4 @@ -.TH "NPM-PING" "1" "December 2022" "" "" +.TH "NPM-PING" "1" "January 2023" "" "" .SH "NAME" \fBnpm-ping\fR - Ping npm registry .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-pkg.1 b/deps/npm/man/man1/npm-pkg.1 index ea1233faeaa44a..4f3437fb2fedb1 100644 --- a/deps/npm/man/man1/npm-pkg.1 +++ b/deps/npm/man/man1/npm-pkg.1 @@ -1,4 +1,4 @@ -.TH "NPM-PKG" "1" "December 2022" "" "" +.TH "NPM-PKG" "1" "January 2023" "" "" .SH "NAME" \fBnpm-pkg\fR - Manages your package.json .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-prefix.1 b/deps/npm/man/man1/npm-prefix.1 index 0d1fcab353d15c..c51646626a4982 100644 --- a/deps/npm/man/man1/npm-prefix.1 +++ b/deps/npm/man/man1/npm-prefix.1 @@ -1,4 +1,4 @@ -.TH "NPM-PREFIX" "1" "December 2022" "" "" +.TH "NPM-PREFIX" "1" "January 2023" "" "" .SH "NAME" \fBnpm-prefix\fR - Display prefix .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-profile.1 b/deps/npm/man/man1/npm-profile.1 index 4a03f77be08a2e..cd5cba95150b22 100644 --- a/deps/npm/man/man1/npm-profile.1 +++ b/deps/npm/man/man1/npm-profile.1 @@ -1,4 +1,4 @@ -.TH "NPM-PROFILE" "1" "December 2022" "" "" +.TH "NPM-PROFILE" "1" "January 2023" "" "" .SH "NAME" \fBnpm-profile\fR - Change settings on your registry profile .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-prune.1 b/deps/npm/man/man1/npm-prune.1 index 958505dee0e08a..928ccd5d806082 100644 --- a/deps/npm/man/man1/npm-prune.1 +++ b/deps/npm/man/man1/npm-prune.1 @@ -1,4 +1,4 @@ -.TH "NPM-PRUNE" "1" "December 2022" "" "" +.TH "NPM-PRUNE" "1" "January 2023" "" "" .SH "NAME" \fBnpm-prune\fR - Remove extraneous packages .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-publish.1 b/deps/npm/man/man1/npm-publish.1 index e191b644e053ca..d75c7b39eb60aa 100644 --- a/deps/npm/man/man1/npm-publish.1 +++ b/deps/npm/man/man1/npm-publish.1 @@ -1,4 +1,4 @@ -.TH "NPM-PUBLISH" "1" "December 2022" "" "" +.TH "NPM-PUBLISH" "1" "January 2023" "" "" .SH "NAME" \fBnpm-publish\fR - Publish a package .SS "Synopsis" @@ -84,7 +84,7 @@ Type: null, "restricted", or "public" .RE 0 .P -If do not want your scoped package to be publicly viewable (and installable) set \fB--access=restricted\fR. +If you do not want your scoped package to be publicly viewable (and installable) set \fB--access=restricted\fR. .P Unscoped packages can not be set to \fBrestricted\fR. .P diff --git a/deps/npm/man/man1/npm-query.1 b/deps/npm/man/man1/npm-query.1 index 657b6a6a37d704..0e6d444e39948b 100644 --- a/deps/npm/man/man1/npm-query.1 +++ b/deps/npm/man/man1/npm-query.1 @@ -1,4 +1,4 @@ -.TH "NPM-QUERY" "1" "December 2022" "" "" +.TH "NPM-QUERY" "1" "January 2023" "" "" .SH "NAME" \fBnpm-query\fR - Dependency selector query .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-rebuild.1 b/deps/npm/man/man1/npm-rebuild.1 index 6a5f20689fc3c1..ce56c880b634af 100644 --- a/deps/npm/man/man1/npm-rebuild.1 +++ b/deps/npm/man/man1/npm-rebuild.1 @@ -1,4 +1,4 @@ -.TH "NPM-REBUILD" "1" "December 2022" "" "" +.TH "NPM-REBUILD" "1" "January 2023" "" "" .SH "NAME" \fBnpm-rebuild\fR - Rebuild a package .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-repo.1 b/deps/npm/man/man1/npm-repo.1 index 6a7b57ed671f6a..836ae8de258883 100644 --- a/deps/npm/man/man1/npm-repo.1 +++ b/deps/npm/man/man1/npm-repo.1 @@ -1,4 +1,4 @@ -.TH "NPM-REPO" "1" "December 2022" "" "" +.TH "NPM-REPO" "1" "January 2023" "" "" .SH "NAME" \fBnpm-repo\fR - Open package repository page in the browser .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-restart.1 b/deps/npm/man/man1/npm-restart.1 index e9e300ebff712a..00b83e280b5cfd 100644 --- a/deps/npm/man/man1/npm-restart.1 +++ b/deps/npm/man/man1/npm-restart.1 @@ -1,4 +1,4 @@ -.TH "NPM-RESTART" "1" "December 2022" "" "" +.TH "NPM-RESTART" "1" "January 2023" "" "" .SH "NAME" \fBnpm-restart\fR - Restart a package .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-root.1 b/deps/npm/man/man1/npm-root.1 index 5157948d2316da..9333aa4545235b 100644 --- a/deps/npm/man/man1/npm-root.1 +++ b/deps/npm/man/man1/npm-root.1 @@ -1,4 +1,4 @@ -.TH "NPM-ROOT" "1" "December 2022" "" "" +.TH "NPM-ROOT" "1" "January 2023" "" "" .SH "NAME" \fBnpm-root\fR - Display npm root .SS "Synopsis" @@ -8,6 +8,8 @@ npm root .fi .RE +.P +Note: This command is unaware of workspaces. .SS "Description" .P Print the effective \fBnode_modules\fR folder to standard out. diff --git a/deps/npm/man/man1/npm-run-script.1 b/deps/npm/man/man1/npm-run-script.1 index c4f97ca3287bac..44a6a76a8b3844 100644 --- a/deps/npm/man/man1/npm-run-script.1 +++ b/deps/npm/man/man1/npm-run-script.1 @@ -1,4 +1,4 @@ -.TH "NPM-RUN-SCRIPT" "1" "December 2022" "" "" +.TH "NPM-RUN-SCRIPT" "1" "January 2023" "" "" .SH "NAME" \fBnpm-run-script\fR - Run arbitrary package scripts .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-search.1 b/deps/npm/man/man1/npm-search.1 index 6a7f6aa9827bdf..3fe6f69992ed6a 100644 --- a/deps/npm/man/man1/npm-search.1 +++ b/deps/npm/man/man1/npm-search.1 @@ -1,4 +1,4 @@ -.TH "NPM-SEARCH" "1" "December 2022" "" "" +.TH "NPM-SEARCH" "1" "January 2023" "" "" .SH "NAME" \fBnpm-search\fR - Search for packages .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-shrinkwrap.1 b/deps/npm/man/man1/npm-shrinkwrap.1 index f158ea070f774b..875f0b58bad501 100644 --- a/deps/npm/man/man1/npm-shrinkwrap.1 +++ b/deps/npm/man/man1/npm-shrinkwrap.1 @@ -1,4 +1,4 @@ -.TH "NPM-SHRINKWRAP" "1" "December 2022" "" "" +.TH "NPM-SHRINKWRAP" "1" "January 2023" "" "" .SH "NAME" \fBnpm-shrinkwrap\fR - Lock down dependency versions for publication .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-star.1 b/deps/npm/man/man1/npm-star.1 index 28fa89780d8950..627d11b3667df7 100644 --- a/deps/npm/man/man1/npm-star.1 +++ b/deps/npm/man/man1/npm-star.1 @@ -1,4 +1,4 @@ -.TH "NPM-STAR" "1" "December 2022" "" "" +.TH "NPM-STAR" "1" "January 2023" "" "" .SH "NAME" \fBnpm-star\fR - Mark your favorite packages .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-stars.1 b/deps/npm/man/man1/npm-stars.1 index 60619f979edb96..6660429c892b48 100644 --- a/deps/npm/man/man1/npm-stars.1 +++ b/deps/npm/man/man1/npm-stars.1 @@ -1,4 +1,4 @@ -.TH "NPM-STARS" "1" "December 2022" "" "" +.TH "NPM-STARS" "1" "January 2023" "" "" .SH "NAME" \fBnpm-stars\fR - View packages marked as favorites .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-start.1 b/deps/npm/man/man1/npm-start.1 index c9f72e52d15233..abdc41d8c5194d 100644 --- a/deps/npm/man/man1/npm-start.1 +++ b/deps/npm/man/man1/npm-start.1 @@ -1,4 +1,4 @@ -.TH "NPM-START" "1" "December 2022" "" "" +.TH "NPM-START" "1" "January 2023" "" "" .SH "NAME" \fBnpm-start\fR - Start a package .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-stop.1 b/deps/npm/man/man1/npm-stop.1 index 8c2a7e4456d090..9c9437aafe6543 100644 --- a/deps/npm/man/man1/npm-stop.1 +++ b/deps/npm/man/man1/npm-stop.1 @@ -1,4 +1,4 @@ -.TH "NPM-STOP" "1" "December 2022" "" "" +.TH "NPM-STOP" "1" "January 2023" "" "" .SH "NAME" \fBnpm-stop\fR - Stop a package .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-team.1 b/deps/npm/man/man1/npm-team.1 index 35e18f7cdda049..917dbce667b9a3 100644 --- a/deps/npm/man/man1/npm-team.1 +++ b/deps/npm/man/man1/npm-team.1 @@ -1,4 +1,4 @@ -.TH "NPM-TEAM" "1" "December 2022" "" "" +.TH "NPM-TEAM" "1" "January 2023" "" "" .SH "NAME" \fBnpm-team\fR - Manage organization teams and team memberships .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-test.1 b/deps/npm/man/man1/npm-test.1 index dde7dfdbffb4a0..5863931a62e8fa 100644 --- a/deps/npm/man/man1/npm-test.1 +++ b/deps/npm/man/man1/npm-test.1 @@ -1,4 +1,4 @@ -.TH "NPM-TEST" "1" "December 2022" "" "" +.TH "NPM-TEST" "1" "January 2023" "" "" .SH "NAME" \fBnpm-test\fR - Test a package .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-token.1 b/deps/npm/man/man1/npm-token.1 index 868de1e51d7ce5..1c7f976201283e 100644 --- a/deps/npm/man/man1/npm-token.1 +++ b/deps/npm/man/man1/npm-token.1 @@ -1,4 +1,4 @@ -.TH "NPM-TOKEN" "1" "December 2022" "" "" +.TH "NPM-TOKEN" "1" "January 2023" "" "" .SH "NAME" \fBnpm-token\fR - Manage your authentication tokens .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-uninstall.1 b/deps/npm/man/man1/npm-uninstall.1 index 952dac51cb2b04..231b203955aa63 100644 --- a/deps/npm/man/man1/npm-uninstall.1 +++ b/deps/npm/man/man1/npm-uninstall.1 @@ -1,4 +1,4 @@ -.TH "NPM-UNINSTALL" "1" "December 2022" "" "" +.TH "NPM-UNINSTALL" "1" "January 2023" "" "" .SH "NAME" \fBnpm-uninstall\fR - Remove a package .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-unpublish.1 b/deps/npm/man/man1/npm-unpublish.1 index b2c8ca2f2c8257..99024be559c3c3 100644 --- a/deps/npm/man/man1/npm-unpublish.1 +++ b/deps/npm/man/man1/npm-unpublish.1 @@ -1,4 +1,4 @@ -.TH "NPM-UNPUBLISH" "1" "December 2022" "" "" +.TH "NPM-UNPUBLISH" "1" "January 2023" "" "" .SH "NAME" \fBnpm-unpublish\fR - Remove a package from the registry .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-unstar.1 b/deps/npm/man/man1/npm-unstar.1 index b05159a0e53804..8263c1aad3f280 100644 --- a/deps/npm/man/man1/npm-unstar.1 +++ b/deps/npm/man/man1/npm-unstar.1 @@ -1,4 +1,4 @@ -.TH "NPM-UNSTAR" "1" "December 2022" "" "" +.TH "NPM-UNSTAR" "1" "January 2023" "" "" .SH "NAME" \fBnpm-unstar\fR - Remove an item from your favorite packages .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-update.1 b/deps/npm/man/man1/npm-update.1 index 9f00dfb01a30c3..644a6787de55a5 100644 --- a/deps/npm/man/man1/npm-update.1 +++ b/deps/npm/man/man1/npm-update.1 @@ -1,4 +1,4 @@ -.TH "NPM-UPDATE" "1" "December 2022" "" "" +.TH "NPM-UPDATE" "1" "January 2023" "" "" .SH "NAME" \fBnpm-update\fR - Update packages .SS "Synopsis" @@ -198,7 +198,7 @@ DEPRECATED: This option has been deprecated in favor of \fB--install-strategy=sh .RE 0 .P -Only install direct dependencies in the top level \fBnode_modules\fR, but hoist on deeper dependendencies. Sets \fB--install-strategy=shallow\fR. +Only install direct dependencies in the top level \fBnode_modules\fR, but hoist on deeper dependencies. Sets \fB--install-strategy=shallow\fR. .SS "\fBomit\fR" .RS 0 .IP \(bu 4 @@ -228,7 +228,7 @@ If set to \fBtrue\fR, and \fB--legacy-peer-deps\fR is not set, then \fIany\fR co .P By default, conflicting \fBpeerDependencies\fR deep in the dependency graph will be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's \fBpeerDependencies\fR object. .P -When such and override is performed, a warning is printed, explaining the conflict and the packages involved. If \fB--strict-peer-deps\fR is set, then this warning is treated as a failure. +When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If \fB--strict-peer-deps\fR is set, then this warning is treated as a failure. .SS "\fBpackage-lock\fR" .RS 0 .IP \(bu 4 diff --git a/deps/npm/man/man1/npm-version.1 b/deps/npm/man/man1/npm-version.1 index d76672560cd893..59248f1a4ef769 100644 --- a/deps/npm/man/man1/npm-version.1 +++ b/deps/npm/man/man1/npm-version.1 @@ -1,4 +1,4 @@ -.TH "NPM-VERSION" "1" "December 2022" "" "" +.TH "NPM-VERSION" "1" "January 2023" "" "" .SH "NAME" \fBnpm-version\fR - Bump a package version .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-view.1 b/deps/npm/man/man1/npm-view.1 index f4784653a79259..8de0a2d9f7df87 100644 --- a/deps/npm/man/man1/npm-view.1 +++ b/deps/npm/man/man1/npm-view.1 @@ -1,4 +1,4 @@ -.TH "NPM-VIEW" "1" "December 2022" "" "" +.TH "NPM-VIEW" "1" "January 2023" "" "" .SH "NAME" \fBnpm-view\fR - View registry info .SS "Synopsis" diff --git a/deps/npm/man/man1/npm-whoami.1 b/deps/npm/man/man1/npm-whoami.1 index 89db7bcf33a584..a609e66bf52059 100644 --- a/deps/npm/man/man1/npm-whoami.1 +++ b/deps/npm/man/man1/npm-whoami.1 @@ -1,4 +1,4 @@ -.TH "NPM-WHOAMI" "1" "December 2022" "" "" +.TH "NPM-WHOAMI" "1" "January 2023" "" "" .SH "NAME" \fBnpm-whoami\fR - Display npm username .SS "Synopsis" diff --git a/deps/npm/man/man1/npm.1 b/deps/npm/man/man1/npm.1 index b759c6a58efc85..e29df213a0402e 100644 --- a/deps/npm/man/man1/npm.1 +++ b/deps/npm/man/man1/npm.1 @@ -1,4 +1,4 @@ -.TH "NPM" "1" "December 2022" "" "" +.TH "NPM" "1" "January 2023" "" "" .SH "NAME" \fBnpm\fR - javascript package manager .SS "Synopsis" @@ -8,9 +8,11 @@ npm .fi .RE +.P +Note: This command is unaware of workspaces. .SS "Version" .P -9.2.0 +9.3.0 .SS "Description" .P npm is the package manager for the Node JavaScript platform. It puts modules in place so that node can find them, and manages dependency conflicts intelligently. @@ -80,7 +82,7 @@ User Configs: The file at \fB$HOME/.npmrc\fR is an ini-formatted list of configs .IP \(bu 4 Global Configs: The file found at \fB./etc/npmrc\fR (relative to the global prefix will be parsed if it is found. See npm help prefix for more info on the global prefix. If the \fBglobalconfig\fR option is set in the cli, env, or user config, then that file is parsed instead. .IP \(bu 4 -Defaults: npm's default configuration options are defined in lib/utils/config-defs.js. These must not be changed. +Defaults: npm's default configuration options are defined in \fBlib/utils/config/definitions.js\fR. These must not be changed. .RE 0 .P diff --git a/deps/npm/man/man1/npx.1 b/deps/npm/man/man1/npx.1 index f718ed321d7e15..ab3a83236bfcd1 100644 --- a/deps/npm/man/man1/npx.1 +++ b/deps/npm/man/man1/npx.1 @@ -1,4 +1,4 @@ -.TH "NPX" "1" "December 2022" "" "" +.TH "NPX" "1" "January 2023" "" "" .SH "NAME" \fBnpx\fR - Run a command from a local or remote npm package .SS "Synopsis" diff --git a/deps/npm/man/man5/folders.5 b/deps/npm/man/man5/folders.5 index ea0acabd334c84..09870f292aee49 100644 --- a/deps/npm/man/man5/folders.5 +++ b/deps/npm/man/man5/folders.5 @@ -1,4 +1,4 @@ -.TH "FOLDERS" "5" "December 2022" "" "" +.TH "FOLDERS" "5" "January 2023" "" "" .SH "NAME" \fBfolders\fR - Folder Structures Used by npm .SS "Description" diff --git a/deps/npm/man/man5/install.5 b/deps/npm/man/man5/install.5 index a6758e93d728f4..ecc6a9b72379ca 100644 --- a/deps/npm/man/man5/install.5 +++ b/deps/npm/man/man5/install.5 @@ -1,4 +1,4 @@ -.TH "INSTALL" "5" "December 2022" "" "" +.TH "INSTALL" "5" "January 2023" "" "" .SH "NAME" \fBinstall\fR - Download and install node and npm .SS "Description" @@ -7,11 +7,11 @@ To publish and install packages to and from the public npm registry, you must in .SS "Overview" .RS 0 .IP \(bu 4 -\fBChecking your version of npm and Node.js\fR \fI\(la#checking-your-version-of-npm-and-node-js\(ra\fR +\fBChecking your version of npm and Node.js\fR \fI(Checking your version of npm and Node.js)\fR .IP \(bu 4 -\fBUsing a Node version manager to install Node.js and npm\fR \fI\(la#using-a-node-version-manager-to-install-node-js-and-npm\(ra\fR +\fBUsing a Node version manager to install Node.js and npm\fR \fI(Using a Node version manager to install Node.js and npm)\fR .IP \(bu 4 -\fBUsing a Node installer to install Node.js and npm\fR \fI\(la#using-a-node-installer-to-install-node-js-and-npm\(ra\fR +\fBUsing a Node installer to install Node.js and npm\fR \fI(Using a Node installer to install Node.js and npm)\fR .RE 0 .SS "Checking your version of npm and Node.js" diff --git a/deps/npm/man/man5/npm-global.5 b/deps/npm/man/man5/npm-global.5 index ea0acabd334c84..09870f292aee49 100644 --- a/deps/npm/man/man5/npm-global.5 +++ b/deps/npm/man/man5/npm-global.5 @@ -1,4 +1,4 @@ -.TH "FOLDERS" "5" "December 2022" "" "" +.TH "FOLDERS" "5" "January 2023" "" "" .SH "NAME" \fBfolders\fR - Folder Structures Used by npm .SS "Description" diff --git a/deps/npm/man/man5/npm-json.5 b/deps/npm/man/man5/npm-json.5 index 8c6781b6a7703e..6d7c946a06110d 100644 --- a/deps/npm/man/man5/npm-json.5 +++ b/deps/npm/man/man5/npm-json.5 @@ -1,4 +1,4 @@ -.TH "PACKAGE.JSON" "5" "December 2022" "" "" +.TH "PACKAGE.JSON" "5" "January 2023" "" "" .SH "NAME" \fBpackage.json\fR - Specifics of npm's package.json handling .SS "Description" diff --git a/deps/npm/man/man5/npm-shrinkwrap-json.5 b/deps/npm/man/man5/npm-shrinkwrap-json.5 index dd6eba1ea3431d..2e498029e420b6 100644 --- a/deps/npm/man/man5/npm-shrinkwrap-json.5 +++ b/deps/npm/man/man5/npm-shrinkwrap-json.5 @@ -1,4 +1,4 @@ -.TH "NPM-SHRINKWRAP.JSON" "5" "December 2022" "" "" +.TH "NPM-SHRINKWRAP.JSON" "5" "January 2023" "" "" .SH "NAME" \fBnpm-shrinkwrap.json\fR - A publishable lockfile .SS "Description" diff --git a/deps/npm/man/man5/npmrc.5 b/deps/npm/man/man5/npmrc.5 index 4846826ebbe975..0828d2ea7ba317 100644 --- a/deps/npm/man/man5/npmrc.5 +++ b/deps/npm/man/man5/npmrc.5 @@ -1,4 +1,4 @@ -.TH "NPMRC" "5" "December 2022" "" "" +.TH "NPMRC" "5" "January 2023" "" "" .SH "NAME" \fBnpmrc\fR - The npm config files .SS "Description" diff --git a/deps/npm/man/man5/package-json.5 b/deps/npm/man/man5/package-json.5 index 8c6781b6a7703e..6d7c946a06110d 100644 --- a/deps/npm/man/man5/package-json.5 +++ b/deps/npm/man/man5/package-json.5 @@ -1,4 +1,4 @@ -.TH "PACKAGE.JSON" "5" "December 2022" "" "" +.TH "PACKAGE.JSON" "5" "January 2023" "" "" .SH "NAME" \fBpackage.json\fR - Specifics of npm's package.json handling .SS "Description" diff --git a/deps/npm/man/man5/package-lock-json.5 b/deps/npm/man/man5/package-lock-json.5 index 4170a9cd3972f0..d10a93bc31ab82 100644 --- a/deps/npm/man/man5/package-lock-json.5 +++ b/deps/npm/man/man5/package-lock-json.5 @@ -1,4 +1,4 @@ -.TH "PACKAGE-LOCK.JSON" "5" "December 2022" "" "" +.TH "PACKAGE-LOCK.JSON" "5" "January 2023" "" "" .SH "NAME" \fBpackage-lock.json\fR - A manifestation of the manifest .SS "Description" diff --git a/deps/npm/man/man7/config.7 b/deps/npm/man/man7/config.7 index 9a0d98c4d5e0c2..6f8d20d6efc965 100644 --- a/deps/npm/man/man7/config.7 +++ b/deps/npm/man/man7/config.7 @@ -1,4 +1,4 @@ -.TH "CONFIG" "7" "December 2022" "" "" +.TH "CONFIG" "7" "January 2023" "" "" .SH "NAME" \fBconfig\fR - More than you probably want to know about npm configuration .SS "Description" @@ -161,7 +161,7 @@ Type: null, "restricted", or "public" .RE 0 .P -If do not want your scoped package to be publicly viewable (and installable) set \fB--access=restricted\fR. +If you do not want your scoped package to be publicly viewable (and installable) set \fB--access=restricted\fR. .P Unscoped packages can not be set to \fBrestricted\fR. .P @@ -216,7 +216,7 @@ Type: "legacy" or "web" .RE 0 .P -What authentication strategy to use with \fBlogin\fR. +What authentication strategy to use with \fBlogin\fR. Note that if an \fBotp\fR config is given, this value will always be set to \fBlegacy\fR. .SS "\fBbefore\fR" .RS 0 .IP \(bu 4 @@ -1445,7 +1445,7 @@ If set to \fBtrue\fR, and \fB--legacy-peer-deps\fR is not set, then \fIany\fR co .P By default, conflicting \fBpeerDependencies\fR deep in the dependency graph will be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's \fBpeerDependencies\fR object. .P -When such and override is performed, a warning is printed, explaining the conflict and the packages involved. If \fB--strict-peer-deps\fR is set, then this warning is treated as a failure. +When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If \fB--strict-peer-deps\fR is set, then this warning is treated as a failure. .SS "\fBstrict-ssl\fR" .RS 0 .IP \(bu 4 @@ -1770,7 +1770,7 @@ DEPRECATED: This option has been deprecated in favor of \fB--install-strategy=sh .RE 0 .P -Only install direct dependencies in the top level \fBnode_modules\fR, but hoist on deeper dependendencies. Sets \fB--install-strategy=shallow\fR. +Only install direct dependencies in the top level \fBnode_modules\fR, but hoist on deeper dependencies. Sets \fB--install-strategy=shallow\fR. .SS "\fBinit.author.email\fR" .RS 0 .IP \(bu 4 diff --git a/deps/npm/man/man7/dependency-selectors.7 b/deps/npm/man/man7/dependency-selectors.7 index d10fc0e4cffeec..e3b0271a2601f7 100644 --- a/deps/npm/man/man7/dependency-selectors.7 +++ b/deps/npm/man/man7/dependency-selectors.7 @@ -1,4 +1,4 @@ -.TH "QUERYING" "7" "December 2022" "" "" +.TH "QUERYING" "7" "January 2023" "" "" .SH "NAME" \fBQuerying\fR - Dependency Selector Syntax & Querying .SS "Description" diff --git a/deps/npm/man/man7/developers.7 b/deps/npm/man/man7/developers.7 index 2614a67657f15e..8b5184dcb662dc 100644 --- a/deps/npm/man/man7/developers.7 +++ b/deps/npm/man/man7/developers.7 @@ -1,4 +1,4 @@ -.TH "DEVELOPERS" "7" "December 2022" "" "" +.TH "DEVELOPERS" "7" "January 2023" "" "" .SH "NAME" \fBdevelopers\fR - Developer Guide .SS "Description" diff --git a/deps/npm/man/man7/logging.7 b/deps/npm/man/man7/logging.7 index c605c3a69c9250..f894a4b36fdfd8 100644 --- a/deps/npm/man/man7/logging.7 +++ b/deps/npm/man/man7/logging.7 @@ -1,4 +1,4 @@ -.TH "LOGGING" "7" "December 2022" "" "" +.TH "LOGGING" "7" "January 2023" "" "" .SH "NAME" \fBLogging\fR - Why, What & How We Log .SS "Description" diff --git a/deps/npm/man/man7/orgs.7 b/deps/npm/man/man7/orgs.7 index a87c11222e377f..1aefdbb4145658 100644 --- a/deps/npm/man/man7/orgs.7 +++ b/deps/npm/man/man7/orgs.7 @@ -1,4 +1,4 @@ -.TH "ORGS" "7" "December 2022" "" "" +.TH "ORGS" "7" "January 2023" "" "" .SH "NAME" \fBorgs\fR - Working with Teams & Orgs .SS "Description" diff --git a/deps/npm/man/man7/package-spec.7 b/deps/npm/man/man7/package-spec.7 index f9da11f2c0d14d..9c376719ce9c53 100644 --- a/deps/npm/man/man7/package-spec.7 +++ b/deps/npm/man/man7/package-spec.7 @@ -1,4 +1,4 @@ -.TH "PACKAGE-SPEC" "7" "December 2022" "" "" +.TH "PACKAGE-SPEC" "7" "January 2023" "" "" .SH "NAME" \fBpackage-spec\fR - Package name specifier .SS "Description" diff --git a/deps/npm/man/man7/registry.7 b/deps/npm/man/man7/registry.7 index a3368a441ac0da..da418a424014e8 100644 --- a/deps/npm/man/man7/registry.7 +++ b/deps/npm/man/man7/registry.7 @@ -1,4 +1,4 @@ -.TH "REGISTRY" "7" "December 2022" "" "" +.TH "REGISTRY" "7" "January 2023" "" "" .SH "NAME" \fBregistry\fR - The JavaScript Package Registry .SS "Description" @@ -15,7 +15,7 @@ The npm public registry is powered by a CouchDB database, of which there is a pu .P The registry URL used is determined by the scope of the package (see npm help scope. If no scope is specified, the default registry is used, which is supplied by the \fB\fBregistry\fR config\fR \fI\(la/using-npm/config#registry\(ra\fR parameter. See npm help config, npm help npmrc, and npm help config for more on managing npm's configuration. Authentication configuration such as auth tokens and certificates are configured specifically scoped to an individual registry. See \fBAuth Related Configuration\fR \fI\(la/configuring-npm/npmrc#auth-related-configuration\(ra\fR .P -When the default registry is used in a package-lock or shrinkwrap is has the special meaning of "the currently configured registry". If you create a lock file while using the default registry you can switch to another registry and npm will install packages from the new registry, but if you create a lock file while using a custom registry packages will be installed from that registry even after you change to another registry. +When the default registry is used in a package-lock or shrinkwrap it has the special meaning of "the currently configured registry". If you create a lock file while using the default registry you can switch to another registry and npm will install packages from the new registry, but if you create a lock file while using a custom registry packages will be installed from that registry even after you change to another registry. .SS "Does npm send any information about me back to the registry?" .P Yes. diff --git a/deps/npm/man/man7/removal.7 b/deps/npm/man/man7/removal.7 index dbbeddaecad012..aea330f2f6260e 100644 --- a/deps/npm/man/man7/removal.7 +++ b/deps/npm/man/man7/removal.7 @@ -1,4 +1,4 @@ -.TH "REMOVAL" "7" "December 2022" "" "" +.TH "REMOVAL" "7" "January 2023" "" "" .SH "NAME" \fBremoval\fR - Cleaning the Slate .SS "Synopsis" @@ -24,7 +24,7 @@ Usually, the above instructions are sufficient. That will remove npm, but leave .P If that doesn't work, or if you require more drastic measures, continue reading. .P -Note that this is only necessary for globally-installed packages. Local installs are completely contained within a project's \fBnode_modules\fR folder. Delete that folder, and everything is gone less a package's install script is particularly ill-behaved). +Note that this is only necessary for globally-installed packages. Local installs are completely contained within a project's \fBnode_modules\fR folder. Delete that folder, and everything is gone unless a package's install script is particularly ill-behaved. .P This assumes that you installed node and npm in the default place. If you configured node with a different \fB--prefix\fR, or installed npm with a different prefix setting, then adjust the paths accordingly, replacing \fB/usr/local\fR with your install prefix. .P diff --git a/deps/npm/man/man7/scope.7 b/deps/npm/man/man7/scope.7 index 7edbff22b6ab5e..9b892290e9b5cd 100644 --- a/deps/npm/man/man7/scope.7 +++ b/deps/npm/man/man7/scope.7 @@ -1,4 +1,4 @@ -.TH "SCOPE" "7" "December 2022" "" "" +.TH "SCOPE" "7" "January 2023" "" "" .SH "NAME" \fBscope\fR - Scoped packages .SS "Description" diff --git a/deps/npm/man/man7/scripts.7 b/deps/npm/man/man7/scripts.7 index 78756bf6d2dbe8..443d9430e76016 100644 --- a/deps/npm/man/man7/scripts.7 +++ b/deps/npm/man/man7/scripts.7 @@ -1,4 +1,4 @@ -.TH "SCRIPTS" "7" "December 2022" "" "" +.TH "SCRIPTS" "7" "January 2023" "" "" .SH "NAME" \fBscripts\fR - How npm handles the "scripts" field .SS "Description" @@ -62,7 +62,7 @@ Runs BEFORE the package is prepared and packed, ONLY on \fBnpm publish\fR. \fBprepack\fR .RS 0 .IP \(bu 4 -Runs BEFORE a tarball is packed (on "\fBnpm pack\fR", "\fBnpm publish\fR", and when installing a git dependencies). +Runs BEFORE a tarball is packed (on "\fBnpm pack\fR", "\fBnpm publish\fR", and when installing a git dependency). .IP \(bu 4 NOTE: "\fBnpm run pack\fR" is NOT the same as "\fBnpm pack\fR". "\fBnpm run pack\fR" is an arbitrary user defined script name, where as, "\fBnpm pack\fR" is a CLI defined command. .RE 0 diff --git a/deps/npm/man/man7/workspaces.7 b/deps/npm/man/man7/workspaces.7 index 427e3eeb8469be..e0ec139dd3429c 100644 --- a/deps/npm/man/man7/workspaces.7 +++ b/deps/npm/man/man7/workspaces.7 @@ -1,4 +1,4 @@ -.TH "WORKSPACES" "7" "December 2022" "" "" +.TH "WORKSPACES" "7" "January 2023" "" "" .SH "NAME" \fBworkspaces\fR - Working with workspaces .SS "Description" 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 89584e5814784b..a9c4b4bc0bb6df 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 @@ -12,6 +12,7 @@ const { readdirScoped } = require('@npmcli/fs') const { lstat, readlink } = require('fs/promises') const { depth } = require('treeverse') const log = require('proc-log') +const { cleanUrl } = require('npm-registry-fetch') const { OK, @@ -1210,7 +1211,8 @@ This is a one-time fix-up, please be patient... if (this[_manifests].has(spec.raw)) { return this[_manifests].get(spec.raw) } else { - log.silly('fetch manifest', spec.raw) + const cleanRawSpec = cleanUrl(spec.rawSpec) + log.silly('fetch manifest', spec.raw.replace(spec.rawSpec, cleanRawSpec)) const p = pacote.manifest(spec, options) .then(mani => { this[_manifests].set(spec.raw, mani) 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 947659f177eefe..b2a6ec2315a4f1 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 @@ -1,5 +1,6 @@ // mixin providing the loadVirtual method const localeCompare = require('@isaacs/string-locale-compare')('en') +const mapWorkspaces = require('@npmcli/map-workspaces') const { resolve } = require('path') @@ -21,7 +22,6 @@ const loadRoot = Symbol('loadRoot') const loadNode = Symbol('loadVirtualNode') const loadLink = Symbol('loadVirtualLink') const loadWorkspaces = Symbol.for('loadWorkspaces') -const loadWorkspacesVirtual = Symbol.for('loadWorkspacesVirtual') const flagsSuspect = Symbol.for('flagsSuspect') const reCalcDepFlags = Symbol('reCalcDepFlags') const checkRootEdges = Symbol('checkRootEdges') @@ -157,7 +157,7 @@ module.exports = cls => class VirtualLoader extends cls { } const lockWS = [] - const workspaces = this[loadWorkspacesVirtual]({ + const workspaces = mapWorkspaces.virtual({ cwd: this.path, lockfile: s.data, }) diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/arborist/load-workspaces.js b/deps/npm/node_modules/@npmcli/arborist/lib/arborist/load-workspaces.js index 0a7965ae30ca1e..effa5a0cda24fa 100644 --- a/deps/npm/node_modules/@npmcli/arborist/lib/arborist/load-workspaces.js +++ b/deps/npm/node_modules/@npmcli/arborist/lib/arborist/load-workspaces.js @@ -1,33 +1,19 @@ const mapWorkspaces = require('@npmcli/map-workspaces') -const _appendWorkspaces = Symbol('appendWorkspaces') // shared ref used by other mixins/Arborist const _loadWorkspaces = Symbol.for('loadWorkspaces') -const _loadWorkspacesVirtual = Symbol.for('loadWorkspacesVirtual') module.exports = cls => class MapWorkspaces extends cls { - [_appendWorkspaces] (node, workspaces) { - if (node && workspaces.size) { - node.workspaces = workspaces - } - - return node - } - async [_loadWorkspaces] (node) { - if (node.workspaces) { - return node - } - const workspaces = await mapWorkspaces({ cwd: node.path, pkg: node.package, }) - return this[_appendWorkspaces](node, workspaces) - } + if (node && workspaces.size) { + node.workspaces = workspaces + } - [_loadWorkspacesVirtual] (opts) { - return mapWorkspaces.virtual(opts) + return node } } diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/override-resolves.js b/deps/npm/node_modules/@npmcli/arborist/lib/override-resolves.js index 794b2c335dc628..c061cbce186786 100644 --- a/deps/npm/node_modules/@npmcli/arborist/lib/override-resolves.js +++ b/deps/npm/node_modules/@npmcli/arborist/lib/override-resolves.js @@ -1,4 +1,4 @@ -function overrideResolves (resolved, opts = {}) { +function overrideResolves (resolved, opts) { const { omitLockfileRegistryResolved = false } = opts if (omitLockfileRegistryResolved) { diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/override-set.js b/deps/npm/node_modules/@npmcli/arborist/lib/override-set.js index 742e3f08ec5345..bfc5a5d7906ee5 100644 --- a/deps/npm/node_modules/@npmcli/arborist/lib/override-set.js +++ b/deps/npm/node_modules/@npmcli/arborist/lib/override-set.js @@ -50,9 +50,36 @@ class OverrideSet { continue } - if (semver.intersects(edge.spec, rule.keySpec)) { + // if keySpec is * we found our override + if (rule.keySpec === '*') { return rule } + + let spec = npa(`${edge.name}@${edge.spec}`) + if (spec.type === 'alias') { + spec = spec.subSpec + } + + if (spec.type === 'git') { + if (spec.gitRange && semver.intersects(spec.gitRange, rule.keySpec)) { + return rule + } + + continue + } + + if (spec.type === 'range' || spec.type === 'version') { + if (semver.intersects(spec.fetchSpec, rule.keySpec)) { + return rule + } + + continue + } + + // if we got this far, the spec type is one of tag, directory or file + // which means we have no real way to make version comparisons, so we + // just accept the override + return rule } return this diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/place-dep.js b/deps/npm/node_modules/@npmcli/arborist/lib/place-dep.js index 16a0095fa09631..e757d0c38a6d70 100644 --- a/deps/npm/node_modules/@npmcli/arborist/lib/place-dep.js +++ b/deps/npm/node_modules/@npmcli/arborist/lib/place-dep.js @@ -9,6 +9,7 @@ const localeCompare = require('@isaacs/string-locale-compare')('en') const log = require('proc-log') +const { cleanUrl } = require('npm-registry-fetch') const deepestNestingTarget = require('./deepest-nesting-target.js') const CanPlaceDep = require('./can-place-dep.js') const { @@ -187,7 +188,7 @@ class PlaceDep { `${this.dep.name}@${this.dep.version}`, this.canPlace.description, `for: ${this.edge.from.package._id || this.edge.from.location}`, - `want: ${this.edge.spec || '*'}` + `want: ${cleanUrl(this.edge.spec || '*')}` ) const placementType = this.canPlace.canPlace === CONFLICT diff --git a/deps/npm/node_modules/@npmcli/arborist/package.json b/deps/npm/node_modules/@npmcli/arborist/package.json index 075fb93b916b08..a7e8132123fba0 100644 --- a/deps/npm/node_modules/@npmcli/arborist/package.json +++ b/deps/npm/node_modules/@npmcli/arborist/package.json @@ -1,6 +1,6 @@ { "name": "@npmcli/arborist", - "version": "6.1.5", + "version": "6.1.6", "description": "Manage node_modules trees", "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", @@ -42,9 +42,9 @@ "@npmcli/template-oss": "4.11.0", "benchmark": "^2.1.4", "chalk": "^4.1.0", - "minify-registry-metadata": "^2.1.0", + "minify-registry-metadata": "^3.0.0", "nock": "^13.2.0", - "tap": "^16.0.1", + "tap": "^16.3.2", "tcompare": "^5.0.6" }, "scripts": { @@ -81,7 +81,6 @@ "tap": { "color": true, "after": "test/fixtures/cleanup.js", - "coverage-map": "map.js", "test-env": [ "NODE_OPTIONS=--no-warnings", "LC_ALL=sk" diff --git a/deps/npm/node_modules/@npmcli/config/lib/index.js b/deps/npm/node_modules/@npmcli/config/lib/index.js index e1d47ffcd37362..1ddf2678391959 100644 --- a/deps/npm/node_modules/@npmcli/config/lib/index.js +++ b/deps/npm/node_modules/@npmcli/config/lib/index.js @@ -17,6 +17,14 @@ const { mkdir, } = require('fs/promises') +const fileExists = (...p) => stat(resolve(...p)) + .then((st) => st.isFile()) + .catch(() => false) + +const dirExists = (...p) => stat(resolve(...p)) + .then((st) => st.isDirectory()) + .catch(() => false) + const hasOwnProperty = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key) @@ -90,6 +98,7 @@ class Config { platform = process.platform, execPath = process.execPath, cwd = process.cwd(), + excludeNpmCwd = false, }) { // turn the definitions into nopt's weirdo syntax this.definitions = definitions @@ -117,10 +126,12 @@ class Config { this.execPath = execPath this.platform = platform this.cwd = cwd + this.excludeNpmCwd = excludeNpmCwd // set when we load configs this.globalPrefix = null this.localPrefix = null + this.localPackage = null // defaults to env.HOME, but will always be *something* this.home = null @@ -311,15 +322,11 @@ class Config { // default the globalconfig file to that location, instead of the default // global prefix. It's weird that `npm get globalconfig --prefix=/foo` // returns `/foo/etc/npmrc`, but better to not change it at this point. - settableGetter(data, 'globalconfig', () => - resolve(this[_get]('prefix'), 'etc/npmrc')) + settableGetter(data, 'globalconfig', () => resolve(this[_get]('prefix'), 'etc/npmrc')) } loadHome () { - if (this.env.HOME) { - return this.home = this.env.HOME - } - this.home = homedir() + this.home = this.env.HOME || homedir() } loadGlobalPrefix () { @@ -330,7 +337,7 @@ class Config { if (this.env.PREFIX) { this.globalPrefix = this.env.PREFIX } else if (this.platform === 'win32') { - // c:\node\node.exe --> prefix=c:\node\ + // c:\node\node.exe --> prefix=c:\node\ this.globalPrefix = dirname(this.execPath) } else { // /usr/local/bin/node --> prefix=/usr/local @@ -599,6 +606,12 @@ class Config { // we return to make sure localPrefix is set await this.loadLocalPrefix() + // if we have not detected a local package json yet, try now that we + // have a local prefix + if (this.localPackage == null) { + this.localPackage = await fileExists(this.localPrefix, 'package.json') + } + if (this[_get]('global') === true || this[_get]('location') === 'global') { this.data.get('project').source = '(global mode enabled, ignored)' this.sources.set(this.data.get('project').source, 'project') @@ -630,16 +643,17 @@ class Config { const isGlobal = this[_get]('global') || this[_get]('location') === 'global' for (const p of walkUp(this.cwd)) { - const hasNodeModules = await stat(resolve(p, 'node_modules')) - .then((st) => st.isDirectory()) - .catch(() => false) + // HACK: this is an option set in tests to stop the local prefix from being set + // on tests that are created inside the npm repo + if (this.excludeNpmCwd && p === this.npmPath) { + break + } - const hasPackageJson = await stat(resolve(p, 'package.json')) - .then((st) => st.isFile()) - .catch(() => false) + const hasPackageJson = await fileExists(p, 'package.json') - if (!this.localPrefix && (hasNodeModules || hasPackageJson)) { + if (!this.localPrefix && (hasPackageJson || await dirExists(p, 'node_modules'))) { this.localPrefix = p + this.localPackage = hasPackageJson // if workspaces are disabled, or we're in global mode, return now if (cliWorkspaces === false || isGlobal) { @@ -663,11 +677,7 @@ class Config { for (const w of workspaces.values()) { if (w === this.localPrefix) { // see if there's a .npmrc file in the workspace, if so log a warning - const hasNpmrc = await stat(resolve(this.localPrefix, '.npmrc')) - .then((st) => st.isFile()) - .catch(() => false) - - if (hasNpmrc) { + if (await fileExists(this.localPrefix, '.npmrc')) { log.warn(`ignoring workspace config at ${this.localPrefix}/.npmrc`) } @@ -675,6 +685,7 @@ class Config { const { data } = this.data.get('default') data.workspace = [this.localPrefix] this.localPrefix = p + this.localPackage = hasPackageJson log.info(`found workspace root at ${this.localPrefix}`) // we found a root, so we return now return diff --git a/deps/npm/node_modules/@npmcli/config/package.json b/deps/npm/node_modules/@npmcli/config/package.json index 28074afe686bf5..50d860c1c941e9 100644 --- a/deps/npm/node_modules/@npmcli/config/package.json +++ b/deps/npm/node_modules/@npmcli/config/package.json @@ -1,6 +1,6 @@ { "name": "@npmcli/config", - "version": "6.1.0", + "version": "6.1.1", "files": [ "bin/", "lib/" @@ -34,7 +34,7 @@ "devDependencies": { "@npmcli/eslint-config": "^4.0.0", "@npmcli/template-oss": "4.11.0", - "tap": "^16.0.1" + "tap": "^16.3.2" }, "dependencies": { "@npmcli/map-workspaces": "^3.0.0", diff --git a/deps/npm/node_modules/libnpmaccess/package.json b/deps/npm/node_modules/libnpmaccess/package.json index 8f89d4b2711b94..1e27f79597c021 100644 --- a/deps/npm/node_modules/libnpmaccess/package.json +++ b/deps/npm/node_modules/libnpmaccess/package.json @@ -19,7 +19,7 @@ "@npmcli/mock-registry": "^1.0.0", "@npmcli/template-oss": "4.11.0", "nock": "^13.2.4", - "tap": "^16.0.1" + "tap": "^16.3.2" }, "repository": { "type": "git", diff --git a/deps/npm/node_modules/libnpmdiff/package.json b/deps/npm/node_modules/libnpmdiff/package.json index 8979bc919919ad..9e7e3bdb41fc5c 100644 --- a/deps/npm/node_modules/libnpmdiff/package.json +++ b/deps/npm/node_modules/libnpmdiff/package.json @@ -1,6 +1,6 @@ { "name": "libnpmdiff", - "version": "5.0.6", + "version": "5.0.7", "description": "The registry diff", "repository": { "type": "git", @@ -44,10 +44,10 @@ "devDependencies": { "@npmcli/eslint-config": "^4.0.0", "@npmcli/template-oss": "4.11.0", - "tap": "^16.0.1" + "tap": "^16.3.2" }, "dependencies": { - "@npmcli/arborist": "^6.1.5", + "@npmcli/arborist": "^6.1.6", "@npmcli/disparity-colors": "^3.0.0", "@npmcli/installed-package-contents": "^2.0.0", "binary-extensions": "^2.2.0", diff --git a/deps/npm/node_modules/libnpmexec/package.json b/deps/npm/node_modules/libnpmexec/package.json index cc77321caa160a..c0092d4c8767b4 100644 --- a/deps/npm/node_modules/libnpmexec/package.json +++ b/deps/npm/node_modules/libnpmexec/package.json @@ -1,6 +1,6 @@ { "name": "libnpmexec", - "version": "5.0.6", + "version": "5.0.7", "files": [ "bin/", "lib/" @@ -56,12 +56,12 @@ "bin-links": "^4.0.1", "just-extend": "^6.1.1", "just-safe-set": "^4.1.1", - "minify-registry-metadata": "^2.2.0", + "minify-registry-metadata": "^3.0.0", "mkdirp": "^1.0.4", - "tap": "^16.0.1" + "tap": "^16.3.2" }, "dependencies": { - "@npmcli/arborist": "^6.1.5", + "@npmcli/arborist": "^6.1.6", "@npmcli/run-script": "^6.0.0", "chalk": "^4.1.0", "ci-info": "^3.7.0", diff --git a/deps/npm/node_modules/libnpmfund/package.json b/deps/npm/node_modules/libnpmfund/package.json index f7fca06d4fc68a..c0de224fba7ef1 100644 --- a/deps/npm/node_modules/libnpmfund/package.json +++ b/deps/npm/node_modules/libnpmfund/package.json @@ -1,6 +1,6 @@ { "name": "libnpmfund", - "version": "4.0.6", + "version": "4.0.7", "main": "lib/index.js", "files": [ "bin/", @@ -43,10 +43,10 @@ "devDependencies": { "@npmcli/eslint-config": "^4.0.0", "@npmcli/template-oss": "4.11.0", - "tap": "^16.0.1" + "tap": "^16.3.2" }, "dependencies": { - "@npmcli/arborist": "^6.1.5" + "@npmcli/arborist": "^6.1.6" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" diff --git a/deps/npm/node_modules/libnpmhook/package.json b/deps/npm/node_modules/libnpmhook/package.json index 606dfc7d9e3e98..b157f97e685b47 100644 --- a/deps/npm/node_modules/libnpmhook/package.json +++ b/deps/npm/node_modules/libnpmhook/package.json @@ -39,7 +39,7 @@ "@npmcli/eslint-config": "^4.0.0", "@npmcli/template-oss": "4.11.0", "nock": "^13.2.4", - "tap": "^16.0.1" + "tap": "^16.3.2" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" diff --git a/deps/npm/node_modules/libnpmorg/package.json b/deps/npm/node_modules/libnpmorg/package.json index c0b1a09ee24018..529a7ff9d2c97f 100644 --- a/deps/npm/node_modules/libnpmorg/package.json +++ b/deps/npm/node_modules/libnpmorg/package.json @@ -31,7 +31,7 @@ "@npmcli/template-oss": "4.11.0", "minipass": "^4.0.0", "nock": "^13.2.4", - "tap": "^16.0.1" + "tap": "^16.3.2" }, "repository": { "type": "git", diff --git a/deps/npm/node_modules/libnpmpack/package.json b/deps/npm/node_modules/libnpmpack/package.json index 5ad21875fd61eb..035edaa9808d5a 100644 --- a/deps/npm/node_modules/libnpmpack/package.json +++ b/deps/npm/node_modules/libnpmpack/package.json @@ -1,6 +1,6 @@ { "name": "libnpmpack", - "version": "5.0.6", + "version": "5.0.7", "description": "Programmatic API for the bits behind npm pack", "author": "GitHub Inc.", "main": "lib/index.js", @@ -26,7 +26,7 @@ "@npmcli/template-oss": "4.11.0", "nock": "^13.0.7", "spawk": "^1.7.1", - "tap": "^16.0.1" + "tap": "^16.3.2" }, "repository": { "type": "git", @@ -36,7 +36,7 @@ "bugs": "https://github.com/npm/libnpmpack/issues", "homepage": "https://npmjs.com/package/libnpmpack", "dependencies": { - "@npmcli/arborist": "^6.1.5", + "@npmcli/arborist": "^6.1.6", "@npmcli/run-script": "^6.0.0", "npm-package-arg": "^10.1.0", "pacote": "^15.0.7" diff --git a/deps/npm/node_modules/libnpmpublish/package.json b/deps/npm/node_modules/libnpmpublish/package.json index eece07bee2341b..c293d566d1dc28 100644 --- a/deps/npm/node_modules/libnpmpublish/package.json +++ b/deps/npm/node_modules/libnpmpublish/package.json @@ -25,11 +25,11 @@ }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", + "@npmcli/mock-registry": "^1.0.0", "@npmcli/template-oss": "4.11.0", - "libnpmpack": "^5.0.6", "lodash.clonedeep": "^4.5.0", "nock": "^13.2.4", - "tap": "^16.0.1" + "tap": "^16.3.2" }, "repository": { "type": "git", diff --git a/deps/npm/node_modules/libnpmsearch/package.json b/deps/npm/node_modules/libnpmsearch/package.json index 6d22ce3568409f..e0d67afbbf66dc 100644 --- a/deps/npm/node_modules/libnpmsearch/package.json +++ b/deps/npm/node_modules/libnpmsearch/package.json @@ -28,7 +28,7 @@ "@npmcli/eslint-config": "^4.0.0", "@npmcli/template-oss": "4.11.0", "nock": "^13.2.4", - "tap": "^16.0.1" + "tap": "^16.3.2" }, "repository": { "type": "git", diff --git a/deps/npm/node_modules/libnpmteam/package.json b/deps/npm/node_modules/libnpmteam/package.json index 9154a1299157df..b3444c77b8dcfb 100644 --- a/deps/npm/node_modules/libnpmteam/package.json +++ b/deps/npm/node_modules/libnpmteam/package.json @@ -18,7 +18,7 @@ "@npmcli/eslint-config": "^4.0.0", "@npmcli/template-oss": "4.11.0", "nock": "^13.2.4", - "tap": "^16.0.1" + "tap": "^16.3.2" }, "repository": { "type": "git", diff --git a/deps/npm/node_modules/libnpmversion/package.json b/deps/npm/node_modules/libnpmversion/package.json index d77bf51e1ba7a0..ff3855ae6c1a32 100644 --- a/deps/npm/node_modules/libnpmversion/package.json +++ b/deps/npm/node_modules/libnpmversion/package.json @@ -34,7 +34,7 @@ "@npmcli/eslint-config": "^4.0.0", "@npmcli/template-oss": "4.11.0", "require-inject": "^1.4.4", - "tap": "^16.0.1" + "tap": "^16.3.2" }, "dependencies": { "@npmcli/git": "^4.0.1", diff --git a/deps/npm/node_modules/minipass-fetch/node_modules/minipass/LICENSE b/deps/npm/node_modules/minipass-fetch/node_modules/minipass/LICENSE deleted file mode 100644 index bf1dece2e1f122..00000000000000 --- a/deps/npm/node_modules/minipass-fetch/node_modules/minipass/LICENSE +++ /dev/null @@ -1,15 +0,0 @@ -The ISC License - -Copyright (c) 2017-2022 npm, Inc., Isaac Z. Schlueter, and Contributors - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR -IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/deps/npm/node_modules/minipass-fetch/node_modules/minipass/index.d.ts b/deps/npm/node_modules/minipass-fetch/node_modules/minipass/index.d.ts deleted file mode 100644 index 65faf63686c213..00000000000000 --- a/deps/npm/node_modules/minipass-fetch/node_modules/minipass/index.d.ts +++ /dev/null @@ -1,155 +0,0 @@ -/// -import { EventEmitter } from 'events' -import { Stream } from 'stream' - -declare namespace Minipass { - type Encoding = BufferEncoding | 'buffer' | null - - interface Writable extends EventEmitter { - end(): any - write(chunk: any, ...args: any[]): any - } - - interface Readable extends EventEmitter { - pause(): any - resume(): any - pipe(): any - } - - interface Pipe { - src: Minipass - dest: Writable - opts: PipeOptions - } - - type DualIterable = Iterable & AsyncIterable - - type ContiguousData = Buffer | ArrayBufferLike | ArrayBufferView | string - - type BufferOrString = Buffer | string - - interface StringOptions { - encoding: BufferEncoding - objectMode?: boolean - async?: boolean - } - - interface BufferOptions { - encoding?: null | 'buffer' - objectMode?: boolean - async?: boolean - } - - interface ObjectModeOptions { - objectMode: true - async?: boolean - } - - interface PipeOptions { - end?: boolean - proxyErrors?: boolean - } - - type Options = T extends string - ? StringOptions - : T extends Buffer - ? BufferOptions - : ObjectModeOptions -} - -declare class Minipass< - RType extends any = Buffer, - WType extends any = RType extends Minipass.BufferOrString - ? Minipass.ContiguousData - : RType - > - extends Stream - implements Minipass.DualIterable -{ - static isStream(stream: any): stream is Minipass.Readable | Minipass.Writable - - readonly bufferLength: number - readonly flowing: boolean - readonly writable: boolean - readonly readable: boolean - readonly paused: boolean - readonly emittedEnd: boolean - readonly destroyed: boolean - - /** - * Not technically private or readonly, but not safe to mutate. - */ - private readonly buffer: RType[] - private readonly pipes: Minipass.Pipe[] - - /** - * Technically writable, but mutating it can change the type, - * so is not safe to do in TypeScript. - */ - readonly objectMode: boolean - async: boolean - - /** - * Note: encoding is not actually read-only, and setEncoding(enc) - * exists. However, this type definition will insist that TypeScript - * programs declare the type of a Minipass stream up front, and if - * that type is string, then an encoding MUST be set in the ctor. If - * the type is Buffer, then the encoding must be missing, or set to - * 'buffer' or null. If the type is anything else, then objectMode - * must be set in the constructor options. So there is effectively - * no allowed way that a TS program can set the encoding after - * construction, as doing so will destroy any hope of type safety. - * TypeScript does not provide many options for changing the type of - * an object at run-time, which is what changing the encoding does. - */ - readonly encoding: Minipass.Encoding - // setEncoding(encoding: Encoding): void - - // Options required if not reading buffers - constructor( - ...args: RType extends Buffer - ? [] | [Minipass.Options] - : [Minipass.Options] - ) - - write(chunk: WType, cb?: () => void): boolean - write(chunk: WType, encoding?: Minipass.Encoding, cb?: () => void): boolean - read(size?: number): RType - end(cb?: () => void): this - end(chunk: any, cb?: () => void): this - end(chunk: any, encoding?: Minipass.Encoding, cb?: () => void): this - pause(): void - resume(): void - promise(): Promise - collect(): Promise - - concat(): RType extends Minipass.BufferOrString ? Promise : never - destroy(er?: any): void - pipe(dest: W, opts?: Minipass.PipeOptions): W - unpipe(dest: W): void - - /** - * alias for on() - */ - addEventHandler(event: string, listener: (...args: any[]) => any): this - - on(event: string, listener: (...args: any[]) => any): this - on(event: 'data', listener: (chunk: RType) => any): this - on(event: 'error', listener: (error: any) => any): this - on( - event: - | 'readable' - | 'drain' - | 'resume' - | 'end' - | 'prefinish' - | 'finish' - | 'close', - listener: () => any - ): this - - [Symbol.iterator](): Iterator - [Symbol.asyncIterator](): AsyncIterator -} - -export = Minipass diff --git a/deps/npm/node_modules/minipass-fetch/node_modules/minipass/index.js b/deps/npm/node_modules/minipass-fetch/node_modules/minipass/index.js deleted file mode 100644 index e8797aab6cc276..00000000000000 --- a/deps/npm/node_modules/minipass-fetch/node_modules/minipass/index.js +++ /dev/null @@ -1,649 +0,0 @@ -'use strict' -const proc = typeof process === 'object' && process ? process : { - stdout: null, - stderr: null, -} -const EE = require('events') -const Stream = require('stream') -const SD = require('string_decoder').StringDecoder - -const EOF = Symbol('EOF') -const MAYBE_EMIT_END = Symbol('maybeEmitEnd') -const EMITTED_END = Symbol('emittedEnd') -const EMITTING_END = Symbol('emittingEnd') -const EMITTED_ERROR = Symbol('emittedError') -const CLOSED = Symbol('closed') -const READ = Symbol('read') -const FLUSH = Symbol('flush') -const FLUSHCHUNK = Symbol('flushChunk') -const ENCODING = Symbol('encoding') -const DECODER = Symbol('decoder') -const FLOWING = Symbol('flowing') -const PAUSED = Symbol('paused') -const RESUME = Symbol('resume') -const BUFFERLENGTH = Symbol('bufferLength') -const BUFFERPUSH = Symbol('bufferPush') -const BUFFERSHIFT = Symbol('bufferShift') -const OBJECTMODE = Symbol('objectMode') -const DESTROYED = Symbol('destroyed') -const EMITDATA = Symbol('emitData') -const EMITEND = Symbol('emitEnd') -const EMITEND2 = Symbol('emitEnd2') -const ASYNC = Symbol('async') - -const defer = fn => Promise.resolve().then(fn) - -// TODO remove when Node v8 support drops -const doIter = global._MP_NO_ITERATOR_SYMBOLS_ !== '1' -const ASYNCITERATOR = doIter && Symbol.asyncIterator - || Symbol('asyncIterator not implemented') -const ITERATOR = doIter && Symbol.iterator - || Symbol('iterator not implemented') - -// events that mean 'the stream is over' -// these are treated specially, and re-emitted -// if they are listened for after emitting. -const isEndish = ev => - ev === 'end' || - ev === 'finish' || - ev === 'prefinish' - -const isArrayBuffer = b => b instanceof ArrayBuffer || - typeof b === 'object' && - b.constructor && - b.constructor.name === 'ArrayBuffer' && - b.byteLength >= 0 - -const isArrayBufferView = b => !Buffer.isBuffer(b) && ArrayBuffer.isView(b) - -class Pipe { - constructor (src, dest, opts) { - this.src = src - this.dest = dest - this.opts = opts - this.ondrain = () => src[RESUME]() - dest.on('drain', this.ondrain) - } - unpipe () { - this.dest.removeListener('drain', this.ondrain) - } - // istanbul ignore next - only here for the prototype - proxyErrors () {} - end () { - this.unpipe() - if (this.opts.end) - this.dest.end() - } -} - -class PipeProxyErrors extends Pipe { - unpipe () { - this.src.removeListener('error', this.proxyErrors) - super.unpipe() - } - constructor (src, dest, opts) { - super(src, dest, opts) - this.proxyErrors = er => dest.emit('error', er) - src.on('error', this.proxyErrors) - } -} - -module.exports = class Minipass extends Stream { - constructor (options) { - super() - this[FLOWING] = false - // whether we're explicitly paused - this[PAUSED] = false - this.pipes = [] - this.buffer = [] - this[OBJECTMODE] = options && options.objectMode || false - if (this[OBJECTMODE]) - this[ENCODING] = null - else - this[ENCODING] = options && options.encoding || null - if (this[ENCODING] === 'buffer') - this[ENCODING] = null - this[ASYNC] = options && !!options.async || false - this[DECODER] = this[ENCODING] ? new SD(this[ENCODING]) : null - this[EOF] = false - this[EMITTED_END] = false - this[EMITTING_END] = false - this[CLOSED] = false - this[EMITTED_ERROR] = null - this.writable = true - this.readable = true - this[BUFFERLENGTH] = 0 - this[DESTROYED] = false - } - - get bufferLength () { return this[BUFFERLENGTH] } - - get encoding () { return this[ENCODING] } - set encoding (enc) { - if (this[OBJECTMODE]) - throw new Error('cannot set encoding in objectMode') - - if (this[ENCODING] && enc !== this[ENCODING] && - (this[DECODER] && this[DECODER].lastNeed || this[BUFFERLENGTH])) - throw new Error('cannot change encoding') - - if (this[ENCODING] !== enc) { - this[DECODER] = enc ? new SD(enc) : null - if (this.buffer.length) - this.buffer = this.buffer.map(chunk => this[DECODER].write(chunk)) - } - - this[ENCODING] = enc - } - - setEncoding (enc) { - this.encoding = enc - } - - get objectMode () { return this[OBJECTMODE] } - set objectMode (om) { this[OBJECTMODE] = this[OBJECTMODE] || !!om } - - get ['async'] () { return this[ASYNC] } - set ['async'] (a) { this[ASYNC] = this[ASYNC] || !!a } - - write (chunk, encoding, cb) { - if (this[EOF]) - throw new Error('write after end') - - if (this[DESTROYED]) { - this.emit('error', Object.assign( - new Error('Cannot call write after a stream was destroyed'), - { code: 'ERR_STREAM_DESTROYED' } - )) - return true - } - - if (typeof encoding === 'function') - cb = encoding, encoding = 'utf8' - - if (!encoding) - encoding = 'utf8' - - const fn = this[ASYNC] ? defer : f => f() - - // convert array buffers and typed array views into buffers - // at some point in the future, we may want to do the opposite! - // leave strings and buffers as-is - // anything else switches us into object mode - if (!this[OBJECTMODE] && !Buffer.isBuffer(chunk)) { - if (isArrayBufferView(chunk)) - chunk = Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength) - else if (isArrayBuffer(chunk)) - chunk = Buffer.from(chunk) - else if (typeof chunk !== 'string') - // use the setter so we throw if we have encoding set - this.objectMode = true - } - - // handle object mode up front, since it's simpler - // this yields better performance, fewer checks later. - if (this[OBJECTMODE]) { - /* istanbul ignore if - maybe impossible? */ - if (this.flowing && this[BUFFERLENGTH] !== 0) - this[FLUSH](true) - - if (this.flowing) - this.emit('data', chunk) - else - this[BUFFERPUSH](chunk) - - if (this[BUFFERLENGTH] !== 0) - this.emit('readable') - - if (cb) - fn(cb) - - return this.flowing - } - - // at this point the chunk is a buffer or string - // don't buffer it up or send it to the decoder - if (!chunk.length) { - if (this[BUFFERLENGTH] !== 0) - this.emit('readable') - if (cb) - fn(cb) - return this.flowing - } - - // fast-path writing strings of same encoding to a stream with - // an empty buffer, skipping the buffer/decoder dance - if (typeof chunk === 'string' && - // unless it is a string already ready for us to use - !(encoding === this[ENCODING] && !this[DECODER].lastNeed)) { - chunk = Buffer.from(chunk, encoding) - } - - if (Buffer.isBuffer(chunk) && this[ENCODING]) - chunk = this[DECODER].write(chunk) - - // Note: flushing CAN potentially switch us into not-flowing mode - if (this.flowing && this[BUFFERLENGTH] !== 0) - this[FLUSH](true) - - if (this.flowing) - this.emit('data', chunk) - else - this[BUFFERPUSH](chunk) - - if (this[BUFFERLENGTH] !== 0) - this.emit('readable') - - if (cb) - fn(cb) - - return this.flowing - } - - read (n) { - if (this[DESTROYED]) - return null - - if (this[BUFFERLENGTH] === 0 || n === 0 || n > this[BUFFERLENGTH]) { - this[MAYBE_EMIT_END]() - return null - } - - if (this[OBJECTMODE]) - n = null - - if (this.buffer.length > 1 && !this[OBJECTMODE]) { - if (this.encoding) - this.buffer = [this.buffer.join('')] - else - this.buffer = [Buffer.concat(this.buffer, this[BUFFERLENGTH])] - } - - const ret = this[READ](n || null, this.buffer[0]) - this[MAYBE_EMIT_END]() - return ret - } - - [READ] (n, chunk) { - if (n === chunk.length || n === null) - this[BUFFERSHIFT]() - else { - this.buffer[0] = chunk.slice(n) - chunk = chunk.slice(0, n) - this[BUFFERLENGTH] -= n - } - - this.emit('data', chunk) - - if (!this.buffer.length && !this[EOF]) - this.emit('drain') - - return chunk - } - - end (chunk, encoding, cb) { - if (typeof chunk === 'function') - cb = chunk, chunk = null - if (typeof encoding === 'function') - cb = encoding, encoding = 'utf8' - if (chunk) - this.write(chunk, encoding) - if (cb) - this.once('end', cb) - this[EOF] = true - this.writable = false - - // if we haven't written anything, then go ahead and emit, - // even if we're not reading. - // we'll re-emit if a new 'end' listener is added anyway. - // This makes MP more suitable to write-only use cases. - if (this.flowing || !this[PAUSED]) - this[MAYBE_EMIT_END]() - return this - } - - // don't let the internal resume be overwritten - [RESUME] () { - if (this[DESTROYED]) - return - - this[PAUSED] = false - this[FLOWING] = true - this.emit('resume') - if (this.buffer.length) - this[FLUSH]() - else if (this[EOF]) - this[MAYBE_EMIT_END]() - else - this.emit('drain') - } - - resume () { - return this[RESUME]() - } - - pause () { - this[FLOWING] = false - this[PAUSED] = true - } - - get destroyed () { - return this[DESTROYED] - } - - get flowing () { - return this[FLOWING] - } - - get paused () { - return this[PAUSED] - } - - [BUFFERPUSH] (chunk) { - if (this[OBJECTMODE]) - this[BUFFERLENGTH] += 1 - else - this[BUFFERLENGTH] += chunk.length - this.buffer.push(chunk) - } - - [BUFFERSHIFT] () { - if (this.buffer.length) { - if (this[OBJECTMODE]) - this[BUFFERLENGTH] -= 1 - else - this[BUFFERLENGTH] -= this.buffer[0].length - } - return this.buffer.shift() - } - - [FLUSH] (noDrain) { - do {} while (this[FLUSHCHUNK](this[BUFFERSHIFT]())) - - if (!noDrain && !this.buffer.length && !this[EOF]) - this.emit('drain') - } - - [FLUSHCHUNK] (chunk) { - return chunk ? (this.emit('data', chunk), this.flowing) : false - } - - pipe (dest, opts) { - if (this[DESTROYED]) - return - - const ended = this[EMITTED_END] - opts = opts || {} - if (dest === proc.stdout || dest === proc.stderr) - opts.end = false - else - opts.end = opts.end !== false - opts.proxyErrors = !!opts.proxyErrors - - // piping an ended stream ends immediately - if (ended) { - if (opts.end) - dest.end() - } else { - this.pipes.push(!opts.proxyErrors ? new Pipe(this, dest, opts) - : new PipeProxyErrors(this, dest, opts)) - if (this[ASYNC]) - defer(() => this[RESUME]()) - else - this[RESUME]() - } - - return dest - } - - unpipe (dest) { - const p = this.pipes.find(p => p.dest === dest) - if (p) { - this.pipes.splice(this.pipes.indexOf(p), 1) - p.unpipe() - } - } - - addListener (ev, fn) { - return this.on(ev, fn) - } - - on (ev, fn) { - const ret = super.on(ev, fn) - if (ev === 'data' && !this.pipes.length && !this.flowing) - this[RESUME]() - else if (ev === 'readable' && this[BUFFERLENGTH] !== 0) - super.emit('readable') - else if (isEndish(ev) && this[EMITTED_END]) { - super.emit(ev) - this.removeAllListeners(ev) - } else if (ev === 'error' && this[EMITTED_ERROR]) { - if (this[ASYNC]) - defer(() => fn.call(this, this[EMITTED_ERROR])) - else - fn.call(this, this[EMITTED_ERROR]) - } - return ret - } - - get emittedEnd () { - return this[EMITTED_END] - } - - [MAYBE_EMIT_END] () { - if (!this[EMITTING_END] && - !this[EMITTED_END] && - !this[DESTROYED] && - this.buffer.length === 0 && - this[EOF]) { - this[EMITTING_END] = true - this.emit('end') - this.emit('prefinish') - this.emit('finish') - if (this[CLOSED]) - this.emit('close') - this[EMITTING_END] = false - } - } - - emit (ev, data, ...extra) { - // error and close are only events allowed after calling destroy() - if (ev !== 'error' && ev !== 'close' && ev !== DESTROYED && this[DESTROYED]) - return - else if (ev === 'data') { - return !data ? false - : this[ASYNC] ? defer(() => this[EMITDATA](data)) - : this[EMITDATA](data) - } else if (ev === 'end') { - return this[EMITEND]() - } else if (ev === 'close') { - this[CLOSED] = true - // don't emit close before 'end' and 'finish' - if (!this[EMITTED_END] && !this[DESTROYED]) - return - const ret = super.emit('close') - this.removeAllListeners('close') - return ret - } else if (ev === 'error') { - this[EMITTED_ERROR] = data - const ret = super.emit('error', data) - this[MAYBE_EMIT_END]() - return ret - } else if (ev === 'resume') { - const ret = super.emit('resume') - this[MAYBE_EMIT_END]() - return ret - } else if (ev === 'finish' || ev === 'prefinish') { - const ret = super.emit(ev) - this.removeAllListeners(ev) - return ret - } - - // Some other unknown event - const ret = super.emit(ev, data, ...extra) - this[MAYBE_EMIT_END]() - return ret - } - - [EMITDATA] (data) { - for (const p of this.pipes) { - if (p.dest.write(data) === false) - this.pause() - } - const ret = super.emit('data', data) - this[MAYBE_EMIT_END]() - return ret - } - - [EMITEND] () { - if (this[EMITTED_END]) - return - - this[EMITTED_END] = true - this.readable = false - if (this[ASYNC]) - defer(() => this[EMITEND2]()) - else - this[EMITEND2]() - } - - [EMITEND2] () { - if (this[DECODER]) { - const data = this[DECODER].end() - if (data) { - for (const p of this.pipes) { - p.dest.write(data) - } - super.emit('data', data) - } - } - - for (const p of this.pipes) { - p.end() - } - const ret = super.emit('end') - this.removeAllListeners('end') - return ret - } - - // const all = await stream.collect() - collect () { - const buf = [] - if (!this[OBJECTMODE]) - buf.dataLength = 0 - // set the promise first, in case an error is raised - // by triggering the flow here. - const p = this.promise() - this.on('data', c => { - buf.push(c) - if (!this[OBJECTMODE]) - buf.dataLength += c.length - }) - return p.then(() => buf) - } - - // const data = await stream.concat() - concat () { - return this[OBJECTMODE] - ? Promise.reject(new Error('cannot concat in objectMode')) - : this.collect().then(buf => - this[OBJECTMODE] - ? Promise.reject(new Error('cannot concat in objectMode')) - : this[ENCODING] ? buf.join('') : Buffer.concat(buf, buf.dataLength)) - } - - // stream.promise().then(() => done, er => emitted error) - promise () { - return new Promise((resolve, reject) => { - this.on(DESTROYED, () => reject(new Error('stream destroyed'))) - this.on('error', er => reject(er)) - this.on('end', () => resolve()) - }) - } - - // for await (let chunk of stream) - [ASYNCITERATOR] () { - const next = () => { - const res = this.read() - if (res !== null) - return Promise.resolve({ done: false, value: res }) - - if (this[EOF]) - return Promise.resolve({ done: true }) - - let resolve = null - let reject = null - const onerr = er => { - this.removeListener('data', ondata) - this.removeListener('end', onend) - reject(er) - } - const ondata = value => { - this.removeListener('error', onerr) - this.removeListener('end', onend) - this.pause() - resolve({ value: value, done: !!this[EOF] }) - } - const onend = () => { - this.removeListener('error', onerr) - this.removeListener('data', ondata) - resolve({ done: true }) - } - const ondestroy = () => onerr(new Error('stream destroyed')) - return new Promise((res, rej) => { - reject = rej - resolve = res - this.once(DESTROYED, ondestroy) - this.once('error', onerr) - this.once('end', onend) - this.once('data', ondata) - }) - } - - return { next } - } - - // for (let chunk of stream) - [ITERATOR] () { - const next = () => { - const value = this.read() - const done = value === null - return { value, done } - } - return { next } - } - - destroy (er) { - if (this[DESTROYED]) { - if (er) - this.emit('error', er) - else - this.emit(DESTROYED) - return this - } - - this[DESTROYED] = true - - // throw away all buffered data, it's never coming out - this.buffer.length = 0 - this[BUFFERLENGTH] = 0 - - if (typeof this.close === 'function' && !this[CLOSED]) - this.close() - - if (er) - this.emit('error', er) - else // if no error to emit, still reject pending promises - this.emit(DESTROYED) - - return this - } - - static isStream (s) { - return !!s && (s instanceof Minipass || s instanceof Stream || - s instanceof EE && ( - typeof s.pipe === 'function' || // readable - (typeof s.write === 'function' && typeof s.end === 'function') // writable - )) - } -} diff --git a/deps/npm/node_modules/minipass-fetch/node_modules/minipass/package.json b/deps/npm/node_modules/minipass-fetch/node_modules/minipass/package.json deleted file mode 100644 index 548d03fa6d5d4b..00000000000000 --- a/deps/npm/node_modules/minipass-fetch/node_modules/minipass/package.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "name": "minipass", - "version": "3.3.6", - "description": "minimal implementation of a PassThrough stream", - "main": "index.js", - "types": "index.d.ts", - "dependencies": { - "yallist": "^4.0.0" - }, - "devDependencies": { - "@types/node": "^17.0.41", - "end-of-stream": "^1.4.0", - "prettier": "^2.6.2", - "tap": "^16.2.0", - "through2": "^2.0.3", - "ts-node": "^10.8.1", - "typescript": "^4.7.3" - }, - "scripts": { - "test": "tap", - "preversion": "npm test", - "postversion": "npm publish", - "postpublish": "git push origin --follow-tags" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/isaacs/minipass.git" - }, - "keywords": [ - "passthrough", - "stream" - ], - "author": "Isaac Z. Schlueter (http://blog.izs.me/)", - "license": "ISC", - "files": [ - "index.d.ts", - "index.js" - ], - "tap": { - "check-coverage": true - }, - "engines": { - "node": ">=8" - }, - "prettier": { - "semi": false, - "printWidth": 80, - "tabWidth": 2, - "useTabs": false, - "singleQuote": true, - "jsxSingleQuote": false, - "bracketSameLine": true, - "arrowParens": "avoid", - "endOfLine": "lf" - } -} diff --git a/deps/npm/node_modules/minipass-fetch/package.json b/deps/npm/node_modules/minipass-fetch/package.json index 45bd36ae719fb9..fc6f88473317a9 100644 --- a/deps/npm/node_modules/minipass-fetch/package.json +++ b/deps/npm/node_modules/minipass-fetch/package.json @@ -1,10 +1,11 @@ { "name": "minipass-fetch", - "version": "3.0.0", + "version": "3.0.1", "description": "An implementation of window.fetch in Node.js using Minipass streams", "license": "MIT", "main": "lib/index.js", "scripts": { + "test:tls-fixtures": "./test/fixtures/tls/setup.sh", "test": "tap", "snap": "tap", "lint": "eslint \"**/*.js\"", @@ -22,8 +23,8 @@ ] }, "devDependencies": { - "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.5.1", + "@npmcli/eslint-config": "^4.0.0", + "@npmcli/template-oss": "4.10.0", "@ungap/url-search-params": "^0.2.2", "abort-controller": "^3.0.0", "abortcontroller-polyfill": "~1.7.3", @@ -35,7 +36,7 @@ "tap": "^16.0.0" }, "dependencies": { - "minipass": "^3.1.6", + "minipass": "^4.0.0", "minipass-sized": "^1.0.3", "minizlib": "^2.1.2" }, @@ -62,6 +63,6 @@ "author": "GitHub Inc.", "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.5.1" + "version": "4.10.0" } } diff --git a/deps/npm/package.json b/deps/npm/package.json index ebfcc0eec29ed3..73c41bc2b4fd29 100644 --- a/deps/npm/package.json +++ b/deps/npm/package.json @@ -1,5 +1,5 @@ { - "version": "9.2.0", + "version": "9.3.0", "name": "npm", "description": "a package manager for JavaScript", "workspaces": [ @@ -53,8 +53,8 @@ }, "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^6.1.5", - "@npmcli/config": "^6.1.0", + "@npmcli/arborist": "^6.1.6", + "@npmcli/config": "^6.1.1", "@npmcli/map-workspaces": "^3.0.0", "@npmcli/package-json": "^3.0.0", "@npmcli/run-script": "^6.0.0", @@ -76,12 +76,12 @@ "is-cidr": "^4.0.2", "json-parse-even-better-errors": "^3.0.0", "libnpmaccess": "^7.0.1", - "libnpmdiff": "^5.0.6", - "libnpmexec": "^5.0.6", - "libnpmfund": "^4.0.6", + "libnpmdiff": "^5.0.7", + "libnpmexec": "^5.0.7", + "libnpmfund": "^4.0.7", "libnpmhook": "^9.0.1", "libnpmorg": "^5.0.1", - "libnpmpack": "^5.0.6", + "libnpmpack": "^5.0.7", "libnpmpublish": "^7.0.6", "libnpmsearch": "^6.0.1", "libnpmteam": "^5.0.1", @@ -110,7 +110,6 @@ "read": "~1.0.7", "read-package-json": "^6.0.0", "read-package-json-fast": "^3.0.1", - "rimraf": "^3.0.2", "semver": "^7.3.8", "ssri": "^10.0.1", "tar": "^6.1.13", @@ -180,7 +179,6 @@ "read", "read-package-json", "read-package-json-fast", - "rimraf", "semver", "ssri", "tar", @@ -199,14 +197,14 @@ "@npmcli/mock-registry": "^1.0.0", "@npmcli/promise-spawn": "^6.0.1", "@npmcli/template-oss": "4.11.0", - "licensee": "^9.0.0", + "licensee": "^10.0.0", "nock": "^13.2.4", "npm-packlist": "^7.0.4", "remark": "^14.0.2", "remark-gfm": "^3.0.1", "remark-github": "^11.2.4", "spawk": "^1.7.1", - "tap": "^16.0.1" + "tap": "^16.3.2" }, "scripts": { "dependencies": "node scripts/bundle-and-gitignore-deps.js && node scripts/dependency-graph.js", diff --git a/deps/npm/tap-snapshots/test/lib/commands/audit.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/audit.js.test.cjs index 3e7658c14bb195..9262e0b51aa2dd 100644 --- a/deps/npm/tap-snapshots/test/lib/commands/audit.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/audit.js.test.cjs @@ -123,7 +123,7 @@ audited 1 package in xxx 1 package has an invalid registry signature: -@npmcli/arborist@1.0.14 (https://verdaccio-clone.org) +@npmcli/arborist@1.0.14 (https://verdaccio-clone.org/) Someone might have tampered with this package since it was published on the registry! @@ -134,7 +134,7 @@ audited 1 package in xxx 1 package has a missing registry signature but the registry is providing signing keys: -@npmcli/arborist@1.0.14 (https://verdaccio-clone.org) +@npmcli/arborist@1.0.14 (https://verdaccio-clone.org/) ` exports[`test/lib/commands/audit.js TAP audit signatures third-party registry with keys and signatures > must match snapshot 1`] = ` diff --git a/deps/npm/tap-snapshots/test/lib/commands/config.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/config.js.test.cjs index 2c2646bb299dca..667a7c78b385dc 100644 --- a/deps/npm/tap-snapshots/test/lib/commands/config.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/config.js.test.cjs @@ -354,7 +354,6 @@ exports[`test/lib/commands/config.js TAP config list with publishConfig > output ; "cli" config from command line options cache = "{NPMDIR}/test/lib/commands/tap-testdir-config-config-list-with-publishConfig-sandbox/cache" -location = "project" prefix = "{LOCALPREFIX}" userconfig = "{HOME}/.npmrc" diff --git a/deps/npm/tap-snapshots/test/lib/commands/diff.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/diff.js.test.cjs new file mode 100644 index 00000000000000..533b4f196e6616 --- /dev/null +++ b/deps/npm/tap-snapshots/test/lib/commands/diff.js.test.cjs @@ -0,0 +1,88 @@ +/* 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/commands/diff.js TAP no args in a project dir > must match snapshot 1`] = ` +diff --git a/a.js b/a.js +index v0.1.0..v1.0.0 100644 +--- a/a.js ++++ b/a.js +@@ -1,1 +1,1 @@ +-const a = "a@0.1.0" ++const a = "a@1.0.0" +diff --git a/b.js b/b.js +index v0.1.0..v1.0.0 100644 +--- a/b.js ++++ b/b.js +@@ -1,1 +1,1 @@ +-const b = "b@0.1.0" ++const b = "b@1.0.0" +diff --git a/index.js b/index.js +index v0.1.0..v1.0.0 100644 +--- a/index.js ++++ b/index.js +@@ -1,1 +1,1 @@ +-const version = "0.1.0" ++const version = "1.0.0" +diff --git a/package.json b/package.json +index v0.1.0..v1.0.0 100644 +--- a/package.json ++++ b/package.json +@@ -1,4 +1,4 @@ + { + "name": "foo", +- "version": "0.1.0" ++ "version": "1.0.0" + } +` + +exports[`test/lib/commands/diff.js TAP single arg version, filtering by files > must match snapshot 1`] = ` +diff --git a/a.js b/a.js +index v0.1.0..v1.0.0 100644 +--- a/a.js ++++ b/a.js +@@ -1,1 +1,1 @@ +-const a = "a@0.1.0" ++const a = "a@1.0.0" +diff --git a/b.js b/b.js +index v0.1.0..v1.0.0 100644 +--- a/b.js ++++ b/b.js +@@ -1,1 +1,1 @@ +-const b = "b@0.1.0" ++const b = "b@1.0.0" +` + +exports[`test/lib/commands/diff.js TAP various options using --name-only option > must match snapshot 1`] = ` +index.js +package.json +` + +exports[`test/lib/commands/diff.js TAP various options using diff option > must match snapshot 1`] = ` +diff --git a/index.js b/index.js +index v2.0.0..v3.0.0 100644 +--- a/index.js ++++ b/index.js +@@ -18,7 +18,7 @@ + 17 + 18 + 19 +-202.0.0 ++203.0.0 + 21 + 22 + 23 +diff --git a/package.json b/package.json +index v2.0.0..v3.0.0 100644 +--- a/package.json ++++ b/package.json +@@ -1,4 +1,4 @@ + { + "name": "bar", +- "version": "2.0.0" ++ "version": "3.0.0" + } +` diff --git a/deps/npm/tap-snapshots/test/lib/commands/dist-tag.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/dist-tag.js.test.cjs index 2b75899e4e3a6f..ebc823e7e06bbd 100644 --- a/deps/npm/tap-snapshots/test/lib/commands/dist-tag.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/dist-tag.js.test.cjs @@ -11,7 +11,6 @@ exports[`test/lib/commands/dist-tag.js TAP add new tag > should return success m exports[`test/lib/commands/dist-tag.js TAP add using valid semver range as name > should return success msg 1`] = ` dist-tag add 1.0.0 to @scoped/another@7.7.7 - ` exports[`test/lib/commands/dist-tag.js TAP ls in current package > should list available tags for current package 1`] = ` @@ -22,7 +21,6 @@ latest: 1.0.0 exports[`test/lib/commands/dist-tag.js TAP ls on missing package > should log no dist-tag found msg 1`] = ` dist-tag ls Couldn't get dist-tag data for foo@* - ` exports[`test/lib/commands/dist-tag.js TAP ls on named package > should list tags for the specified package 1`] = ` @@ -45,7 +43,6 @@ latest: 2.0.0 exports[`test/lib/commands/dist-tag.js TAP remove existing tag > should log remove info 1`] = ` dist-tag del c from @scoped/another - ` exports[`test/lib/commands/dist-tag.js TAP remove existing tag > should return success msg 1`] = ` @@ -55,13 +52,11 @@ exports[`test/lib/commands/dist-tag.js TAP remove existing tag > should return s exports[`test/lib/commands/dist-tag.js TAP remove non-existing tag > should log error msg 1`] = ` dist-tag del nonexistent from @scoped/another dist-tag del nonexistent is not a dist-tag on @scoped/another - ` exports[`test/lib/commands/dist-tag.js TAP set existing version > should log warn msg 1`] = ` dist-tag add b to @scoped/another@0.6.0 dist-tag add b is already set to version 0.6.0 - ` exports[`test/lib/commands/dist-tag.js TAP workspaces no args > printed the expected output 1`] = ` @@ -95,7 +90,7 @@ latest-a: 1.0.0 latest: 1.0.0 ` -exports[`test/lib/commands/dist-tag.js TAP workspaces one arg -- . > printed the expected output 1`] = ` +exports[`test/lib/commands/dist-tag.js TAP workspaces one arg -- .@1, ignores version spec > printed the expected output 1`] = ` workspace-a: latest-a: 1.0.0 latest: 1.0.0 @@ -107,7 +102,7 @@ latest-c: 3.0.0 latest: 3.0.0 ` -exports[`test/lib/commands/dist-tag.js TAP workspaces one arg -- .@1, ignores version spec > printed the expected output 1`] = ` +exports[`test/lib/commands/dist-tag.js TAP workspaces one arg -- cwd > printed the expected output 1`] = ` workspace-a: latest-a: 1.0.0 latest: 1.0.0 @@ -131,7 +126,7 @@ latest-c: 3.0.0 latest: 3.0.0 ` -exports[`test/lib/commands/dist-tag.js TAP workspaces two args -- list, . > printed the expected output 1`] = ` +exports[`test/lib/commands/dist-tag.js TAP workspaces two args -- list, .@1, ignores version spec > printed the expected output 1`] = ` workspace-a: latest-a: 1.0.0 latest: 1.0.0 @@ -143,7 +138,13 @@ latest-c: 3.0.0 latest: 3.0.0 ` -exports[`test/lib/commands/dist-tag.js TAP workspaces two args -- list, .@1, ignores version spec > printed the expected output 1`] = ` +exports[`test/lib/commands/dist-tag.js TAP workspaces two args -- list, @scoped/pkg, logs a warning and ignores workspaces > printed the expected output 1`] = ` +a: 0.0.1 +b: 0.5.0 +latest: 1.0.0 +` + +exports[`test/lib/commands/dist-tag.js TAP workspaces two args -- list, cwd > printed the expected output 1`] = ` workspace-a: latest-a: 1.0.0 latest: 1.0.0 @@ -154,9 +155,3 @@ workspace-c: latest-c: 3.0.0 latest: 3.0.0 ` - -exports[`test/lib/commands/dist-tag.js TAP workspaces two args -- list, @scoped/pkg, logs a warning and ignores workspaces > printed the expected output 1`] = ` -a: 0.0.1 -b: 0.5.0 -latest: 1.0.0 -` diff --git a/deps/npm/tap-snapshots/test/lib/commands/doctor.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/doctor.js.test.cjs index 861aad3e255017..2cf8dca12bc66a 100644 --- a/deps/npm/tap-snapshots/test/lib/commands/doctor.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/doctor.js.test.cjs @@ -59,7 +59,7 @@ npm -v  ok  current: v1.0.0, node -v  ok  current: v1.0.0, recommended: v1.0.0 npm config get registry  ok  using default registry (https://registry.npmjs.org/) git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/test/lib/commands/tap-testdir-doctor-all-clear/global/bin +global bin folder in PATH  ok  {CWD}/global/bin Perms check on cached files  ok   Perms check on local node_modules  ok   Perms check on global node_modules ok   @@ -75,7 +75,7 @@ npm -v  ok  curren node -v  ok  current: v1.0.0, recommended: v1.0.0 npm config get registry  ok  using default registry (https://registry.npmjs.org/) git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/test/lib/commands/tap-testdir-doctor-all-clear-in-color/global/bin +global bin folder in PATH  ok  {CWD}/global/bin Perms check on cached files  ok   Perms check on local node_modules  ok   Perms check on global node_modules ok   @@ -185,7 +185,7 @@ npm -v  not ok Error: unsupport node -v  not ok Error: unsupported proxy protocol: 'ssh:' npm config get registry  ok  using default registry (https://registry.npmjs.org/) git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/test/lib/commands/tap-testdir-doctor-bad-proxy/global/bin +global bin folder in PATH  ok  {CWD}/global/bin Perms check on cached files  ok   Perms check on local node_modules  ok   Perms check on global node_modules ok   @@ -201,7 +201,7 @@ npm -v  ok  current: v1.0.0, node -v  ok  current: v1.0.0, recommended: v1.0.0 npm config get registry  ok  using default registry (https://registry.npmjs.org/) git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/test/lib/commands/tap-testdir-doctor-cacache-badContent/global/bin +global bin folder in PATH  ok  {CWD}/global/bin Perms check on cached files  ok   Perms check on local node_modules  ok   Perms check on global node_modules ok   @@ -329,7 +329,7 @@ npm -v  ok  current: v1.0.0, node -v  ok  current: v1.0.0, recommended: v1.0.0 npm config get registry  ok  using default registry (https://registry.npmjs.org/) git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/test/lib/commands/tap-testdir-doctor-cacache-missingContent/global/bin +global bin folder in PATH  ok  {CWD}/global/bin Perms check on cached files  ok   Perms check on local node_modules  ok   Perms check on global node_modules ok   @@ -345,7 +345,7 @@ npm -v  ok  current: v1.0.0, node -v  ok  current: v1.0.0, recommended: v1.0.0 npm config get registry  ok  using default registry (https://registry.npmjs.org/) git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/test/lib/commands/tap-testdir-doctor-cacache-reclaimedCount/global/bin +global bin folder in PATH  ok  {CWD}/global/bin Perms check on cached files  ok   Perms check on local node_modules  ok   Perms check on global node_modules ok   @@ -482,7 +482,7 @@ Object { exports[`test/lib/commands/doctor.js TAP discrete checks invalid environment > output 1`] = ` Check  Value  Recommendation/Notes git executable in PATH  ok  /path/to/git -global bin folder in PATH not ok Error: Add {CWD}/test/lib/commands/tap-testdir-doctor-discrete-checks-invalid-environment/global/bin to your $PATH +global bin folder in PATH not ok Error: Add {CWD}/global/bin to your $PATH ` exports[`test/lib/commands/doctor.js TAP discrete checks permissions - not windows > logs 1`] = ` @@ -637,23 +637,23 @@ Object { "warn": Array [ Array [ "checkFilesPermission", - "error reading directory {CWD}/test/lib/commands/tap-testdir-doctor-error-reading-directory/cache", + "error reading directory {CWD}/cache", ], Array [ "checkFilesPermission", - "error reading directory {CWD}/test/lib/commands/tap-testdir-doctor-error-reading-directory/prefix/node_modules", + "error reading directory {CWD}/prefix/node_modules", ], Array [ "checkFilesPermission", - "error reading directory {CWD}/test/lib/commands/tap-testdir-doctor-error-reading-directory/global/lib/node_modules", + "error reading directory {CWD}/global/node_modules", ], Array [ "checkFilesPermission", - "error reading directory {CWD}/test/lib/commands/tap-testdir-doctor-error-reading-directory/prefix/node_modules/.bin", + "error reading directory {CWD}/prefix/node_modules/.bin", ], Array [ "checkFilesPermission", - "error reading directory {CWD}/test/lib/commands/tap-testdir-doctor-error-reading-directory/global/bin", + "error reading directory {CWD}/global/bin", ], ], } @@ -666,12 +666,12 @@ npm -v  ok  current: v1.0.0, node -v  ok  current: v1.0.0, recommended: v1.0.0 npm config get registry  ok  using default registry (https://registry.npmjs.org/) git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/test/lib/commands/tap-testdir-doctor-error-reading-directory/global/bin -Perms check on cached files  not ok Check the permissions of files in {CWD}/test/lib/commands/tap-testdir-doctor-error-reading-directory/cache (should be owned by current user) -Perms check on local node_modules  not ok Check the permissions of files in {CWD}/test/lib/commands/tap-testdir-doctor-error-reading-directory/prefix/node_modules (should be owned by current user) -Perms check on global node_modules not ok Check the permissions of files in {CWD}/test/lib/commands/tap-testdir-doctor-error-reading-directory/global/lib/node_modules -Perms check on local bin folder  not ok Check the permissions of files in {CWD}/test/lib/commands/tap-testdir-doctor-error-reading-directory/prefix/node_modules/.bin -Perms check on global bin folder  not ok Check the permissions of files in {CWD}/test/lib/commands/tap-testdir-doctor-error-reading-directory/global/bin +global bin folder in PATH  ok  {CWD}/global/bin +Perms check on cached files  not ok Check the permissions of files in {CWD}/cache (should be owned by current user) +Perms check on local node_modules  not ok Check the permissions of files in {CWD}/prefix/node_modules (should be owned by current user) +Perms check on global node_modules not ok Check the permissions of files in {CWD}/global/node_modules +Perms check on local bin folder  not ok Check the permissions of files in {CWD}/prefix/node_modules/.bin +Perms check on global bin folder  not ok Check the permissions of files in {CWD}/global/bin Verify cache contents  ok  verified 0 tarballs ` @@ -682,8 +682,8 @@ npm -v  ok  current: v1.0.0, node -v  ok  current: v1.0.0, recommended: v1.0.0 npm config get registry  ok  using default registry (https://registry.npmjs.org/) git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/global/bin -Perms check on cached files  not ok Check the permissions of files in {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/cache (should be owned by current user) +global bin folder in PATH  ok  {CWD}/global/bin +Perms check on cached files  not ok Check the permissions of files in {CWD}/cache (should be owned by current user) Perms check on local node_modules  ok   Perms check on global node_modules ok   Perms check on local bin folder  ok   @@ -737,7 +737,7 @@ Object { "warn": Array [ Array [ "checkFilesPermission", - "should be owner of {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/cache/_cacache", + "should be owner of {CWD}/cache/_cacache", ], ], } @@ -750,12 +750,12 @@ npm -v  ok  current: v1.0.0, node -v  ok  current: v1.0.0, recommended: v1.0.0 npm config get registry  ok  using default registry (https://registry.npmjs.org/) git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-permissions/global/bin -Perms check on cached files  not ok Check the permissions of files in {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-permissions/cache (should be owned by current user) -Perms check on local node_modules  not ok Check the permissions of files in {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-permissions/prefix/node_modules (should be owned by current user) -Perms check on global node_modules not ok Check the permissions of files in {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-permissions/global/lib/node_modules -Perms check on local bin folder  not ok Check the permissions of files in {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-permissions/prefix/node_modules/.bin -Perms check on global bin folder  not ok Check the permissions of files in {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-permissions/global/bin +global bin folder in PATH  ok  {CWD}/global/bin +Perms check on cached files  not ok Check the permissions of files in {CWD}/cache (should be owned by current user) +Perms check on local node_modules  not ok Check the permissions of files in {CWD}/prefix/node_modules (should be owned by current user) +Perms check on global node_modules not ok Check the permissions of files in {CWD}/global/node_modules +Perms check on local bin folder  not ok Check the permissions of files in {CWD}/prefix/node_modules/.bin +Perms check on global bin folder  not ok Check the permissions of files in {CWD}/global/bin Verify cache contents  ok  verified 0 tarballs ` @@ -764,23 +764,23 @@ Object { "error": Array [ Array [ "checkFilesPermission", - "Missing permissions on {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-permissions/cache (expect: readable)", + "Missing permissions on {CWD}/cache (expect: readable)", ], Array [ "checkFilesPermission", - "Missing permissions on {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-permissions/prefix/node_modules (expect: readable, writable)", + "Missing permissions on {CWD}/prefix/node_modules (expect: readable, writable)", ], Array [ "checkFilesPermission", - "Missing permissions on {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-permissions/global/lib/node_modules (expect: readable)", + "Missing permissions on {CWD}/global/node_modules (expect: readable)", ], Array [ "checkFilesPermission", - "Missing permissions on {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-permissions/prefix/node_modules/.bin (expect: readable, writable, executable)", + "Missing permissions on {CWD}/prefix/node_modules/.bin (expect: readable, writable, executable)", ], Array [ "checkFilesPermission", - "Missing permissions on {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-permissions/global/bin (expect: executable)", + "Missing permissions on {CWD}/global/bin (expect: executable)", ], ], "info": Array [ @@ -885,7 +885,7 @@ npm -v  ok  current: v1.0.0, node -v  ok  current: v1.0.0, recommended: v1.0.0 npm config get registry  ok  using default registry (https://registry.npmjs.org/) git executable in PATH  not ok Error: Install git and ensure it's in your PATH. -global bin folder in PATH  ok  {CWD}/test/lib/commands/tap-testdir-doctor-missing-git/global/bin +global bin folder in PATH  ok  {CWD}/global/bin Perms check on cached files  ok   Perms check on local node_modules  ok   Perms check on global node_modules ok   @@ -940,11 +940,11 @@ Object { "warn": Array [ Array [ "checkFilesPermission", - "error getting info for {CWD}/test/lib/commands/tap-testdir-doctor-missing-global-directories/global/lib/node_modules", + "error getting info for {CWD}/global/node_modules", ], Array [ "checkFilesPermission", - "error getting info for {CWD}/test/lib/commands/tap-testdir-doctor-missing-global-directories/global/bin", + "error getting info for {CWD}/global/bin", ], ], } @@ -957,12 +957,12 @@ npm -v  ok  current: v1.0.0, node -v  ok  current: v1.0.0, recommended: v1.0.0 npm config get registry  ok  using default registry (https://registry.npmjs.org/) git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/test/lib/commands/tap-testdir-doctor-missing-global-directories/global/bin +global bin folder in PATH  ok  {CWD}/global/bin Perms check on cached files  ok   Perms check on local node_modules  ok   -Perms check on global node_modules not ok Check the permissions of files in {CWD}/test/lib/commands/tap-testdir-doctor-missing-global-directories/global/lib/node_modules +Perms check on global node_modules not ok Check the permissions of files in {CWD}/global/node_modules Perms check on local bin folder  ok   -Perms check on global bin folder  not ok Check the permissions of files in {CWD}/test/lib/commands/tap-testdir-doctor-missing-global-directories/global/bin +Perms check on global bin folder  not ok Check the permissions of files in {CWD}/global/bin Verify cache contents  ok  verified 0 tarballs ` @@ -1020,7 +1020,7 @@ npm -v  ok  current: v1.0.0, node -v  ok  current: v1.0.0, recommended: v1.0.0 npm config get registry  ok  using default registry (https://registry.npmjs.org/) git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/test/lib/commands/tap-testdir-doctor-missing-local-node_modules/global/bin +global bin folder in PATH  ok  {CWD}/global/bin Perms check on cached files  ok   Perms check on local node_modules  ok   Perms check on global node_modules ok   @@ -1083,7 +1083,7 @@ npm -v  ok  current: v1.0.0, node -v  not ok Use node v2.0.1 (current: v2.0.0) npm config get registry  ok  using default registry (https://registry.npmjs.org/) git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/test/lib/commands/tap-testdir-doctor-node-out-of-date---current/global/bin +global bin folder in PATH  ok  {CWD}/global/bin Perms check on cached files  ok   Perms check on local node_modules  ok   Perms check on global node_modules ok   @@ -1146,7 +1146,7 @@ npm -v  ok  current: v1.0.0, node -v  not ok Use node v1.0.0 (current: v0.0.1) npm config get registry  ok  using default registry (https://registry.npmjs.org/) git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/test/lib/commands/tap-testdir-doctor-node-out-of-date---lts/global/bin +global bin folder in PATH  ok  {CWD}/global/bin Perms check on cached files  ok   Perms check on local node_modules  ok   Perms check on global node_modules ok   @@ -1209,7 +1209,7 @@ npm -v  ok  current: v1.0.0, node -v  ok  current: v1.0.0, recommended: v1.0.0 npm config get registry  not ok Try \`npm config set registry=https://registry.npmjs.org/\` git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/test/lib/commands/tap-testdir-doctor-non-default-registry/global/bin +global bin folder in PATH  ok  {CWD}/global/bin Perms check on cached files  ok   Perms check on local node_modules  ok   Perms check on global node_modules ok   @@ -1272,7 +1272,7 @@ npm -v  not ok Use npm v2.0.0 node -v  ok  current: v1.0.0, recommended: v1.0.0 npm config get registry  ok  using default registry (https://registry.npmjs.org/) git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/test/lib/commands/tap-testdir-doctor-npm-out-of-date/global/bin +global bin folder in PATH  ok  {CWD}/global/bin Perms check on cached files  ok   Perms check on local node_modules  ok   Perms check on global node_modules ok   @@ -1335,7 +1335,7 @@ npm -v  ok  current: v1.0.0, node -v  ok  current: v1.0.0, recommended: v1.0.0 npm config get registry  ok  using default registry (https://registry.npmjs.org/) git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/test/lib/commands/tap-testdir-doctor-ping-404/global/bin +global bin folder in PATH  ok  {CWD}/global/bin Perms check on cached files  ok   Perms check on local node_modules  ok   Perms check on global node_modules ok   @@ -1398,7 +1398,7 @@ npm -v  ok  curren node -v  ok  current: v1.0.0, recommended: v1.0.0 npm config get registry  ok  using default registry (https://registry.npmjs.org/) git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/test/lib/commands/tap-testdir-doctor-ping-404-in-color/global/bin +global bin folder in PATH  ok  {CWD}/global/bin Perms check on cached files  ok   Perms check on local node_modules  ok   Perms check on global node_modules ok   @@ -1461,7 +1461,7 @@ npm -v  ok  current: v1.0.0, node -v  ok  current: v1.0.0, recommended: v1.0.0 npm config get registry  ok  using default registry (https://registry.npmjs.org/) git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/test/lib/commands/tap-testdir-doctor-ping-exception-with-code/global/bin +global bin folder in PATH  ok  {CWD}/global/bin Perms check on cached files  ok   Perms check on local node_modules  ok   Perms check on global node_modules ok   @@ -1524,7 +1524,7 @@ npm -v  ok  current: v1.0.0, node -v  ok  current: v1.0.0, recommended: v1.0.0 npm config get registry  ok  using default registry (https://registry.npmjs.org/) git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/test/lib/commands/tap-testdir-doctor-ping-exception-without-code/global/bin +global bin folder in PATH  ok  {CWD}/global/bin Perms check on cached files  ok   Perms check on local node_modules  ok   Perms check on global node_modules ok   @@ -1643,5 +1643,5 @@ npm -v  ok  current: v1.0.0, latest: node -v  ok  current: v1.0.0, recommended: v1.0.0 npm config get registry  ok  using default registry (https://registry.npmjs.org/) git executable in PATH  ok  /path/to/git -global bin folder in PATH ok  {CWD}/test/lib/commands/tap-testdir-doctor-windows-skips-permissions-checks/global +global bin folder in PATH ok  {CWD}/global ` diff --git a/deps/npm/tap-snapshots/test/lib/commands/fund.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/fund.js.test.cjs index f0df1e1c58ad46..011315a9211ef0 100644 --- a/deps/npm/tap-snapshots/test/lib/commands/fund.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/fund.js.test.cjs @@ -8,8 +8,7 @@ exports[`test/lib/commands/fund.js TAP fund a package with type and multiple sources > should print prompt select message 1`] = ` 1: Foo funding available at the following URL: http://example.com/foo 2: Lorem funding available at the following URL: http://example.com/foo-lorem -Run \`npm fund [<@scope>/] --which=1\`, for example, to open the first funding URL listed in that package - +Run \`npm fund [] --which=1\`, for example, to open the first funding URL listed in that package ` exports[`test/lib/commands/fund.js TAP fund colors > should print output with color info 1`] = ` @@ -23,7 +22,6 @@ exports[`test/lib/commands/fund.js TAP fund colors > should print output with co  \`-- http://example.com/e  \`-- e@1.0.0  - ` exports[`test/lib/commands/fund.js TAP fund containing multi-level nested deps with no funding > should omit dependencies with no funding declared 1`] = ` @@ -33,54 +31,37 @@ nested-no-funding-packages@1.0.0 \`-- http://example.com/donate \`-- bar@1.0.0 - ` exports[`test/lib/commands/fund.js TAP fund in which same maintainer owns all its deps > should print stack packages together 1`] = ` http://example.com/donate \`-- maintainer-owns-all-deps@1.0.0, dep-foo@1.0.0, dep-sub-foo@1.0.0, dep-bar@1.0.0 - ` exports[`test/lib/commands/fund.js TAP fund pkg missing version number > should print name only 1`] = ` http://example.com/foo \`-- foo +` +exports[`test/lib/commands/fund.js TAP fund using bad which value: index too high > should print message about invalid which 1`] = ` +--which=100 is not a valid index +1: Funding available at the following URL: http://example.com +2: Funding available at the following URL: http://sponsors.example.com/me +3: Funding available at the following URL: http://collective.example.com +Run \`npm fund [] --which=1\`, for example, to open the first funding URL listed in that package ` exports[`test/lib/commands/fund.js TAP fund using nested packages with multiple sources > should prompt with all available URLs 1`] = ` 1: Funding available at the following URL: https://one.example.com 2: Funding available at the following URL: https://two.example.com -Run \`npm fund [<@scope>/] --which=1\`, for example, to open the first funding URL listed in that package - -` - -exports[`test/lib/commands/fund.js TAP fund using nested packages with multiple sources, with a source number > should open the numbered URL 1`] = ` -Funding available at the following URL: - https://one.example.com -` - -exports[`test/lib/commands/fund.js TAP fund using package argument > should open funding url 1`] = ` -individual funding available at the following URL: - http://example.com/donate -` - -exports[`test/lib/commands/fund.js TAP fund using pkg name while having conflicting versions > should open greatest version 1`] = ` -Funding available at the following URL: - http://example.com/2 -` - -exports[`test/lib/commands/fund.js TAP fund using string shorthand > should open string-only url 1`] = ` -Funding available at the following URL: - https://example.com/sponsor +Run \`npm fund [] --which=1\`, for example, to open the first funding URL listed in that package ` exports[`test/lib/commands/fund.js TAP fund with no package containing funding > should print empty funding info 1`] = ` no-funding-package@0.0.0 - ` exports[`test/lib/commands/fund.js TAP sub dep with fund info and a parent with no funding info > should nest sub dep as child of root 1`] = ` @@ -90,25 +71,22 @@ test-multiple-funding-sources@1.0.0 \`-- http://example.com/c \`-- c@1.0.0 - ` -exports[`test/lib/commands/fund.js TAP workspaces filter funding info by a specific workspace > should display only filtered workspace name and its deps 1`] = ` +exports[`test/lib/commands/fund.js TAP workspaces filter funding info by a specific workspace name > should display only filtered workspace name and its deps 1`] = ` workspaces-support@1.0.0 \`-- https://example.com/a | \`-- a@1.0.0 \`-- http://example.com/c \`-- c@1.0.0 - ` -exports[`test/lib/commands/fund.js TAP workspaces filter funding info by a specific workspace > should display only filtered workspace path and its deps 1`] = ` +exports[`test/lib/commands/fund.js TAP workspaces filter funding info by a specific workspace path > should display only filtered workspace name and its deps 1`] = ` workspaces-support@1.0.0 \`-- https://example.com/a | \`-- a@1.0.0 \`-- http://example.com/c \`-- c@1.0.0 - ` diff --git a/deps/npm/tap-snapshots/test/lib/commands/init.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/init.js.test.cjs index 677f29a1ab52b0..821193a55e1a98 100644 --- a/deps/npm/tap-snapshots/test/lib/commands/init.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/init.js.test.cjs @@ -5,55 +5,20 @@ * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' -exports[`test/lib/commands/init.js TAP npm init workspces with root > does not print helper info 1`] = ` -Array [] -` - -exports[`test/lib/commands/init.js TAP workspaces no args > should print helper info 1`] = ` -Array [] -` +exports[`test/lib/commands/init.js TAP displays output > displays 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. -exports[`test/lib/commands/init.js TAP workspaces no args, existing folder > should print helper info 1`] = ` -Array [] -` +See \`npm help init\` for definitive documentation on these fields +and exactly what they do. -exports[`test/lib/commands/init.js TAP workspaces post workspace-init reify > should print helper info 1`] = ` -Array [ - Array [ - String( +Use \`npm install \` afterwards to install a package and +save it as a dependency in the package.json file. - added 1 package in 100ms - ), - ], -] +Press ^C at any time to quit. ` -exports[`test/lib/commands/init.js TAP workspaces post workspace-init reify > should reify tree on init ws complete 1`] = ` -{ - "name": "top-level", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "top-level", - "workspaces": [ - "a" - ] - }, - "a": { - "version": "1.0.0", - "license": "ISC", - "devDependencies": {} - }, - "node_modules/a": { - "resolved": "a", - "link": true - } - } -} - -` +exports[`test/lib/commands/init.js TAP workspaces no args -- yes > should print helper info 1`] = ` -exports[`test/lib/commands/init.js TAP workspaces with arg but missing workspace folder > should print helper info 1`] = ` -Array [] +added 1 package in {TIME} ` diff --git a/deps/npm/tap-snapshots/test/lib/commands/link.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/link.js.test.cjs index 0c34bd972dcf93..c26e30da1ef625 100644 --- a/deps/npm/tap-snapshots/test/lib/commands/link.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/link.js.test.cjs @@ -6,50 +6,50 @@ */ 'use strict' exports[`test/lib/commands/link.js TAP hash character in working directory path > should create a global link to current pkg, even within path with hash 1`] = ` -{CWD}/test/lib/commands/tap-testdir-link-hash-character-in-working-directory-path/global-prefix/lib/node_modules/test-pkg-link -> {CWD}/test/lib/commands/tap-testdir-link-hash-character-in-working-directory-path/i_like_#_in_my_paths/test-pkg-link +{CWD}/global/node_modules/test-pkg-link -> {CWD}/other/i_like_#_in_my_paths/test-pkg-link ` exports[`test/lib/commands/link.js TAP link global linked pkg to local nm when using args > should create a local symlink to global pkg 1`] = ` -{CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/my-project/node_modules/@myscope/bar -> {CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/global-prefix/lib/node_modules/@myscope/bar -{CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/my-project/node_modules/@myscope/linked -> {CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/scoped-linked -{CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/my-project/node_modules/a -> {CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/global-prefix/lib/node_modules/a -{CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/my-project/node_modules/link-me-too -> {CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/link-me-too -{CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/my-project/node_modules/test-pkg-link -> {CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/test-pkg-link +{CWD}/prefix/node_modules/@myscope/bar -> {CWD}/global/node_modules/@myscope/bar +{CWD}/prefix/node_modules/@myscope/linked -> {CWD}/other/scoped-linked +{CWD}/prefix/node_modules/a -> {CWD}/global/node_modules/a +{CWD}/prefix/node_modules/link-me-too -> {CWD}/other/link-me-too +{CWD}/prefix/node_modules/test-pkg-link -> {CWD}/other/test-pkg-link ` exports[`test/lib/commands/link.js TAP link global linked pkg to local workspace using args > should create a local symlink to global pkg 1`] = ` -{CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/my-project/node_modules/@myscope/bar -> {CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/global-prefix/lib/node_modules/@myscope/bar -{CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/my-project/node_modules/@myscope/linked -> {CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/scoped-linked -{CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/my-project/node_modules/a -> {CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/global-prefix/lib/node_modules/a -{CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/my-project/node_modules/link-me-too -> {CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/link-me-too -{CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/my-project/node_modules/test-pkg-link -> {CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/test-pkg-link -{CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/my-project/node_modules/x -> {CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/my-project/packages/x +{CWD}/prefix/node_modules/@myscope/bar -> {CWD}/global/node_modules/@myscope/bar +{CWD}/prefix/node_modules/@myscope/linked -> {CWD}/other/scoped-linked +{CWD}/prefix/node_modules/a -> {CWD}/global/node_modules/a +{CWD}/prefix/node_modules/link-me-too -> {CWD}/other/link-me-too +{CWD}/prefix/node_modules/test-pkg-link -> {CWD}/other/test-pkg-link +{CWD}/prefix/node_modules/x -> {CWD}/prefix/packages/x ` exports[`test/lib/commands/link.js TAP link pkg already in global space > should create a local symlink to global pkg 1`] = ` -{CWD}/test/lib/commands/tap-testdir-link-link-pkg-already-in-global-space/my-project/node_modules/@myscope/linked -> {CWD}/test/lib/commands/tap-testdir-link-link-pkg-already-in-global-space/scoped-linked +{CWD}/prefix/node_modules/@myscope/linked -> {CWD}/other/scoped-linked ` exports[`test/lib/commands/link.js TAP link pkg already in global space when prefix is a symlink > should create a local symlink to global pkg 1`] = ` -{CWD}/test/lib/commands/tap-testdir-link-link-pkg-already-in-global-space-when-prefix-is-a-symlink/my-project/node_modules/@myscope/linked -> {CWD}/test/lib/commands/tap-testdir-link-link-pkg-already-in-global-space-when-prefix-is-a-symlink/scoped-linked +{CWD}/prefix/node_modules/@myscope/linked -> {CWD}/other/scoped-linked ` exports[`test/lib/commands/link.js TAP link to globalDir when in current working dir of pkg and no args > should create a global link to current pkg 1`] = ` -{CWD}/test/lib/commands/tap-testdir-link-link-to-globalDir-when-in-current-working-dir-of-pkg-and-no-args/global-prefix/lib/node_modules/test-pkg-link -> {CWD}/test/lib/commands/tap-testdir-link-link-to-globalDir-when-in-current-working-dir-of-pkg-and-no-args/test-pkg-link +{CWD}/global/node_modules/test-pkg-link -> {CWD}/prefix ` exports[`test/lib/commands/link.js TAP link ws to globalDir when workspace specified and no args > should create a global link to current pkg 1`] = ` -{CWD}/test/lib/commands/tap-testdir-link-link-ws-to-globalDir-when-workspace-specified-and-no-args/global-prefix/lib/node_modules/a -> {CWD}/test/lib/commands/tap-testdir-link-link-ws-to-globalDir-when-workspace-specified-and-no-args/test-pkg-link/packages/a +{CWD}/global/node_modules/a -> {CWD}/prefix/packages/a ` exports[`test/lib/commands/link.js TAP test linked installed as symlinks > linked package should not be installed 1`] = ` -{CWD}/test/lib/commands/tap-testdir-link-test-linked-installed-as-symlinks/prefix/node_modules/mylink -> {CWD}/test/lib/commands/tap-testdir-link-test-linked-installed-as-symlinks/other/mylink +{CWD}/prefix/node_modules/mylink -> {CWD}/other/mylink ` diff --git a/deps/npm/tap-snapshots/test/lib/commands/ls.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/ls.js.test.cjs index 84bfed4c91500d..a6e4472cae95a1 100644 --- a/deps/npm/tap-snapshots/test/lib/commands/ls.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/ls.js.test.cjs @@ -7,53 +7,53 @@ 'use strict' exports[`test/lib/commands/ls.js TAP ignore missing optional deps --json > ls --json problems 1`] = ` Array [ - "invalid: optional-wrong@3.2.1 {project}/node_modules/optional-wrong", + "invalid: optional-wrong@3.2.1 {CWD}/prefix/node_modules/optional-wrong", "missing: peer-missing@1, required by test-npm-ls-ignore-missing-optional@1.2.3", - "invalid: peer-optional-wrong@3.2.1 {project}/node_modules/peer-optional-wrong", - "invalid: peer-wrong@3.2.1 {project}/node_modules/peer-wrong", + "invalid: peer-optional-wrong@3.2.1 {CWD}/prefix/node_modules/peer-optional-wrong", + "invalid: peer-wrong@3.2.1 {CWD}/prefix/node_modules/peer-wrong", "missing: prod-missing@1, required by test-npm-ls-ignore-missing-optional@1.2.3", - "invalid: prod-wrong@3.2.1 {project}/node_modules/prod-wrong", + "invalid: prod-wrong@3.2.1 {CWD}/prefix/node_modules/prod-wrong", ] ` exports[`test/lib/commands/ls.js TAP ignore missing optional deps --parseable > ls --parseable result 1`] = ` -{project} -{project}/node_modules/optional-ok -{project}/node_modules/optional-wrong -{project}/node_modules/peer-ok -{project}/node_modules/peer-optional-ok -{project}/node_modules/peer-optional-wrong -{project}/node_modules/peer-wrong -{project}/node_modules/prod-ok -{project}/node_modules/prod-wrong +{CWD}/prefix +{CWD}/prefix/node_modules/optional-ok +{CWD}/prefix/node_modules/optional-wrong +{CWD}/prefix/node_modules/peer-ok +{CWD}/prefix/node_modules/peer-optional-ok +{CWD}/prefix/node_modules/peer-optional-wrong +{CWD}/prefix/node_modules/peer-wrong +{CWD}/prefix/node_modules/prod-ok +{CWD}/prefix/node_modules/prod-wrong ` exports[`test/lib/commands/ls.js TAP ignore missing optional deps human output > ls result 1`] = ` -test-npm-ls-ignore-missing-optional@1.2.3 {project} -+-- unmet optional dependency optional-missing@1 +test-npm-ls-ignore-missing-optional@1.2.3 {CWD}/prefix ++-- UNMET OPTIONAL DEPENDENCY optional-missing@1 +-- optional-ok@1.2.3 +-- optional-wrong@3.2.1 invalid: "1" from the root project -+-- unmet dependency peer-missing@1 ++-- UNMET DEPENDENCY peer-missing@1 +-- peer-ok@1.2.3 -+-- unmet optional dependency peer-optional-missing@1 ++-- UNMET OPTIONAL DEPENDENCY peer-optional-missing@1 +-- peer-optional-ok@1.2.3 +-- peer-optional-wrong@3.2.1 invalid: "1" from the root project +-- peer-wrong@3.2.1 invalid: "1" from the root project -+-- unmet dependency prod-missing@1 ++-- UNMET DEPENDENCY prod-missing@1 +-- prod-ok@1.2.3 \`-- prod-wrong@3.2.1 invalid: "1" from the root project ` exports[`test/lib/commands/ls.js TAP ls --depth=0 > should output tree containing only top-level dependencies 1`] = ` -test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls---depth-0 +test-npm-ls@1.0.0 {CWD}/prefix +-- chai@1.0.0 \`-- foo@1.0.0 ` exports[`test/lib/commands/ls.js TAP ls --depth=1 > should output tree containing top-level deps and their deps only 1`] = ` -test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls---depth-1 +test-npm-ls@1.0.0 {CWD}/prefix +-- a@1.0.0 | \`-- b@1.0.0 \`-- e@1.0.0 @@ -61,7 +61,7 @@ test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls---depth-1 ` exports[`test/lib/commands/ls.js TAP ls --dev > should output tree containing dev deps 1`] = ` -test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls---dev +test-npm-ls@1.0.0 {CWD}/prefix \`-- dev-dep@1.0.0 \`-- foo@1.0.0 \`-- dog@1.0.0 @@ -69,14 +69,14 @@ test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls---dev ` exports[`test/lib/commands/ls.js TAP ls --link > should output tree containing linked deps 1`] = ` -test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls---link +test-npm-ls@1.0.0 {CWD}/prefix \`-- linked-dep@1.0.0 -> ./linked-dep ` exports[`test/lib/commands/ls.js TAP ls --long --depth=0 > should output tree containing top-level deps with descriptions 1`] = ` test-npm-ls@1.0.0 -| {CWD}/tap-testdir-ls-ls---long---depth-0 +| {CWD}/prefix | +-- chai@1.0.0 | @@ -93,7 +93,7 @@ test-npm-ls@1.0.0 exports[`test/lib/commands/ls.js TAP ls --long > should output tree info with descriptions 1`] = ` test-npm-ls@1.0.0 -| {CWD}/tap-testdir-ls-ls---long +| {CWD}/prefix | +-- chai@1.0.0 | @@ -115,192 +115,192 @@ test-npm-ls@1.0.0 ` exports[`test/lib/commands/ls.js TAP ls --parseable --depth=0 > should output tree containing only top-level dependencies 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable---depth-0 -{CWD}/tap-testdir-ls-ls---parseable---depth-0/node_modules/chai -{CWD}/tap-testdir-ls-ls---parseable---depth-0/node_modules/foo +{CWD}/prefix +{CWD}/prefix/node_modules/chai +{CWD}/prefix/node_modules/foo ` exports[`test/lib/commands/ls.js TAP ls --parseable --depth=1 > should output parseable containing top-level deps and their deps only 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable---depth-1 -{CWD}/tap-testdir-ls-ls---parseable---depth-1/node_modules/chai -{CWD}/tap-testdir-ls-ls---parseable---depth-1/node_modules/foo -{CWD}/tap-testdir-ls-ls---parseable---depth-1/node_modules/dog +{CWD}/prefix +{CWD}/prefix/node_modules/chai +{CWD}/prefix/node_modules/foo +{CWD}/prefix/node_modules/dog ` exports[`test/lib/commands/ls.js TAP ls --parseable --dev > should output tree containing dev deps 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable---dev -{CWD}/tap-testdir-ls-ls---parseable---dev/node_modules/dev-dep -{CWD}/tap-testdir-ls-ls---parseable---dev/node_modules/foo -{CWD}/tap-testdir-ls-ls---parseable---dev/node_modules/dog +{CWD}/prefix +{CWD}/prefix/node_modules/dev-dep +{CWD}/prefix/node_modules/foo +{CWD}/prefix/node_modules/dog ` exports[`test/lib/commands/ls.js TAP ls --parseable --link > should output tree containing linked deps 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable---link -{CWD}/tap-testdir-ls-ls---parseable---link/node_modules/linked-dep +{CWD}/prefix +{CWD}/prefix/node_modules/linked-dep ` exports[`test/lib/commands/ls.js TAP ls --parseable --long --depth=0 > should output tree containing top-level deps with descriptions 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable---long---depth-0:test-npm-ls@1.0.0 -{CWD}/tap-testdir-ls-ls---parseable---long---depth-0/node_modules/chai:chai@1.0.0 -{CWD}/tap-testdir-ls-ls---parseable---long---depth-0/node_modules/dev-dep:dev-dep@1.0.0 -{CWD}/tap-testdir-ls-ls---parseable---long---depth-0/node_modules/optional-dep:optional-dep@1.0.0 -{CWD}/tap-testdir-ls-ls---parseable---long---depth-0/node_modules/peer-dep:peer-dep@1.0.0 -{CWD}/tap-testdir-ls-ls---parseable---long---depth-0/node_modules/prod-dep:prod-dep@1.0.0 +{CWD}/prefix:test-npm-ls@1.0.0 +{CWD}/prefix/node_modules/chai:chai@1.0.0 +{CWD}/prefix/node_modules/dev-dep:dev-dep@1.0.0 +{CWD}/prefix/node_modules/optional-dep:optional-dep@1.0.0 +{CWD}/prefix/node_modules/peer-dep:peer-dep@1.0.0 +{CWD}/prefix/node_modules/prod-dep:prod-dep@1.0.0 ` exports[`test/lib/commands/ls.js TAP ls --parseable --long > should output tree info with descriptions 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable---long:test-npm-ls@1.0.0 -{CWD}/tap-testdir-ls-ls---parseable---long/node_modules/chai:chai@1.0.0 -{CWD}/tap-testdir-ls-ls---parseable---long/node_modules/dev-dep:dev-dep@1.0.0 -{CWD}/tap-testdir-ls-ls---parseable---long/node_modules/optional-dep:optional-dep@1.0.0 -{CWD}/tap-testdir-ls-ls---parseable---long/node_modules/peer-dep:peer-dep@1.0.0 -{CWD}/tap-testdir-ls-ls---parseable---long/node_modules/prod-dep:prod-dep@1.0.0 -{CWD}/tap-testdir-ls-ls---parseable---long/node_modules/foo:foo@1.0.0 -{CWD}/tap-testdir-ls-ls---parseable---long/node_modules/prod-dep/node_modules/dog:dog@2.0.0 -{CWD}/tap-testdir-ls-ls---parseable---long/node_modules/dog:dog@1.0.0 +{CWD}/prefix:test-npm-ls@1.0.0 +{CWD}/prefix/node_modules/chai:chai@1.0.0 +{CWD}/prefix/node_modules/dev-dep:dev-dep@1.0.0 +{CWD}/prefix/node_modules/optional-dep:optional-dep@1.0.0 +{CWD}/prefix/node_modules/peer-dep:peer-dep@1.0.0 +{CWD}/prefix/node_modules/prod-dep:prod-dep@1.0.0 +{CWD}/prefix/node_modules/foo:foo@1.0.0 +{CWD}/prefix/node_modules/prod-dep/node_modules/dog:dog@2.0.0 +{CWD}/prefix/node_modules/dog:dog@1.0.0 ` exports[`test/lib/commands/ls.js TAP ls --parseable --long missing/invalid/extraneous > should output parseable result containing EXTRANEOUS/INVALID labels 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable---long-missing-invalid-extraneous:test-npm-ls@1.0.0 -{CWD}/tap-testdir-ls-ls---parseable---long-missing-invalid-extraneous/node_modules/chai:chai@1.0.0:EXTRANEOUS -{CWD}/tap-testdir-ls-ls---parseable---long-missing-invalid-extraneous/node_modules/foo:foo@1.0.0:INVALID -{CWD}/tap-testdir-ls-ls---parseable---long-missing-invalid-extraneous/node_modules/dog:dog@1.0.0 +{CWD}/prefix:test-npm-ls@1.0.0 +{CWD}/prefix/node_modules/chai:chai@1.0.0:EXTRANEOUS +{CWD}/prefix/node_modules/foo:foo@1.0.0:INVALID +{CWD}/prefix/node_modules/dog:dog@1.0.0 ` exports[`test/lib/commands/ls.js TAP ls --parseable --long print symlink target location > should output parseable results with symlink targets 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable---long-print-symlink-target-location:test-npm-ls@1.0.0 -{CWD}/tap-testdir-ls-ls---parseable---long-print-symlink-target-location/node_modules/chai:chai@1.0.0 -{CWD}/tap-testdir-ls-ls---parseable---long-print-symlink-target-location/node_modules/dev-dep:dev-dep@1.0.0 -{CWD}/tap-testdir-ls-ls---parseable---long-print-symlink-target-location/node_modules/linked-dep:linked-dep@1.0.0:{CWD}/tap-testdir-ls-ls---parseable---long-print-symlink-target-location/linked-dep -{CWD}/tap-testdir-ls-ls---parseable---long-print-symlink-target-location/node_modules/optional-dep:optional-dep@1.0.0 -{CWD}/tap-testdir-ls-ls---parseable---long-print-symlink-target-location/node_modules/peer-dep:peer-dep@1.0.0 -{CWD}/tap-testdir-ls-ls---parseable---long-print-symlink-target-location/node_modules/prod-dep:prod-dep@1.0.0 -{CWD}/tap-testdir-ls-ls---parseable---long-print-symlink-target-location/node_modules/foo:foo@1.0.0 -{CWD}/tap-testdir-ls-ls---parseable---long-print-symlink-target-location/node_modules/prod-dep/node_modules/dog:dog@2.0.0 -{CWD}/tap-testdir-ls-ls---parseable---long-print-symlink-target-location/node_modules/dog:dog@1.0.0 +{CWD}/prefix:test-npm-ls@1.0.0 +{CWD}/prefix/node_modules/chai:chai@1.0.0 +{CWD}/prefix/node_modules/dev-dep:dev-dep@1.0.0 +{CWD}/prefix/node_modules/linked-dep:linked-dep@1.0.0:{CWD}/prefix/linked-dep +{CWD}/prefix/node_modules/optional-dep:optional-dep@1.0.0 +{CWD}/prefix/node_modules/peer-dep:peer-dep@1.0.0 +{CWD}/prefix/node_modules/prod-dep:prod-dep@1.0.0 +{CWD}/prefix/node_modules/foo:foo@1.0.0 +{CWD}/prefix/node_modules/prod-dep/node_modules/dog:dog@2.0.0 +{CWD}/prefix/node_modules/dog:dog@1.0.0 ` exports[`test/lib/commands/ls.js TAP ls --parseable --long with extraneous deps > should output long parseable output with extraneous info 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable---long-with-extraneous-deps:test-npm-ls@1.0.0 -{CWD}/tap-testdir-ls-ls---parseable---long-with-extraneous-deps/node_modules/chai:chai@1.0.0:EXTRANEOUS -{CWD}/tap-testdir-ls-ls---parseable---long-with-extraneous-deps/node_modules/foo:foo@1.0.0 -{CWD}/tap-testdir-ls-ls---parseable---long-with-extraneous-deps/node_modules/dog:dog@1.0.0 +{CWD}/prefix:test-npm-ls@1.0.0 +{CWD}/prefix/node_modules/chai:chai@1.0.0:EXTRANEOUS +{CWD}/prefix/node_modules/foo:foo@1.0.0 +{CWD}/prefix/node_modules/dog:dog@1.0.0 ` exports[`test/lib/commands/ls.js TAP ls --parseable --production > should output tree containing production deps 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable---production -{CWD}/tap-testdir-ls-ls---parseable---production/node_modules/chai -{CWD}/tap-testdir-ls-ls---parseable---production/node_modules/optional-dep -{CWD}/tap-testdir-ls-ls---parseable---production/node_modules/prod-dep -{CWD}/tap-testdir-ls-ls---parseable---production/node_modules/prod-dep/node_modules/dog +{CWD}/prefix +{CWD}/prefix/node_modules/chai +{CWD}/prefix/node_modules/optional-dep +{CWD}/prefix/node_modules/prod-dep +{CWD}/prefix/node_modules/prod-dep/node_modules/dog ` exports[`test/lib/commands/ls.js TAP ls --parseable cycle deps > should print tree output omitting deduped ref 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable-cycle-deps -{CWD}/tap-testdir-ls-ls---parseable-cycle-deps/node_modules/a -{CWD}/tap-testdir-ls-ls---parseable-cycle-deps/node_modules/b +{CWD}/prefix +{CWD}/prefix/node_modules/a +{CWD}/prefix/node_modules/b ` exports[`test/lib/commands/ls.js TAP ls --parseable default --depth value should be 0 > should output parseable output containing only top-level dependencies 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable-default---depth-value-should-be-0 -{CWD}/tap-testdir-ls-ls---parseable-default---depth-value-should-be-0/node_modules/chai -{CWD}/tap-testdir-ls-ls---parseable-default---depth-value-should-be-0/node_modules/foo +{CWD}/prefix +{CWD}/prefix/node_modules/chai +{CWD}/prefix/node_modules/foo ` exports[`test/lib/commands/ls.js TAP ls --parseable empty location > should print empty result 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable-empty-location +{CWD}/prefix ` exports[`test/lib/commands/ls.js TAP ls --parseable extraneous deps > should output containing problems info 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable-extraneous-deps -{CWD}/tap-testdir-ls-ls---parseable-extraneous-deps/node_modules/chai -{CWD}/tap-testdir-ls-ls---parseable-extraneous-deps/node_modules/foo -{CWD}/tap-testdir-ls-ls---parseable-extraneous-deps/node_modules/dog +{CWD}/prefix +{CWD}/prefix/node_modules/chai +{CWD}/prefix/node_modules/foo +{CWD}/prefix/node_modules/dog ` exports[`test/lib/commands/ls.js TAP ls --parseable from and resolved properties > should not be printed in tree output 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable-from-and-resolved-properties -{CWD}/tap-testdir-ls-ls---parseable-from-and-resolved-properties/node_modules/simple-output +{CWD}/prefix +{CWD}/prefix/node_modules/simple-output ` exports[`test/lib/commands/ls.js TAP ls --parseable global > should print parseable output for global deps 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable-global -{CWD}/tap-testdir-ls-ls---parseable-global/node_modules/a -{CWD}/tap-testdir-ls-ls---parseable-global/node_modules/b -{CWD}/tap-testdir-ls-ls---parseable-global/node_modules/b/node_modules/c +{CWD}/global +{CWD}/global/node_modules/a +{CWD}/global/node_modules/b +{CWD}/global/node_modules/b/node_modules/c ` exports[`test/lib/commands/ls.js TAP ls --parseable json read problems > should print empty result 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable-json-read-problems +{CWD}/prefix ` exports[`test/lib/commands/ls.js TAP ls --parseable missing package.json > should output parseable missing name/version of top-level package 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable-missing-package.json -{CWD}/tap-testdir-ls-ls---parseable-missing-package.json/node_modules/chai -{CWD}/tap-testdir-ls-ls---parseable-missing-package.json/node_modules/dog -{CWD}/tap-testdir-ls-ls---parseable-missing-package.json/node_modules/foo +{CWD}/prefix +{CWD}/prefix/node_modules/chai +{CWD}/prefix/node_modules/dog +{CWD}/prefix/node_modules/foo ` exports[`test/lib/commands/ls.js TAP ls --parseable missing/invalid/extraneous > should output parseable containing top-level deps and their deps only 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable-missing-invalid-extraneous -{CWD}/tap-testdir-ls-ls---parseable-missing-invalid-extraneous/node_modules/chai -{CWD}/tap-testdir-ls-ls---parseable-missing-invalid-extraneous/node_modules/foo -{CWD}/tap-testdir-ls-ls---parseable-missing-invalid-extraneous/node_modules/dog +{CWD}/prefix +{CWD}/prefix/node_modules/chai +{CWD}/prefix/node_modules/foo +{CWD}/prefix/node_modules/dog ` exports[`test/lib/commands/ls.js TAP ls --parseable no args > should output parseable representation of dependencies structure 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable-no-args -{CWD}/tap-testdir-ls-ls---parseable-no-args/node_modules/chai -{CWD}/tap-testdir-ls-ls---parseable-no-args/node_modules/foo -{CWD}/tap-testdir-ls-ls---parseable-no-args/node_modules/dog +{CWD}/prefix +{CWD}/prefix/node_modules/chai +{CWD}/prefix/node_modules/foo +{CWD}/prefix/node_modules/dog ` exports[`test/lib/commands/ls.js TAP ls --parseable overridden dep > should contain overridden outout 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable-overridden-dep:test-overridden@1.0.0 -{CWD}/tap-testdir-ls-ls---parseable-overridden-dep/node_modules/foo:foo@1.0.0 -{CWD}/tap-testdir-ls-ls---parseable-overridden-dep/node_modules/bar:bar@1.0.0:OVERRIDDEN +{CWD}/prefix:test-overridden@1.0.0 +{CWD}/prefix/node_modules/foo:foo@1.0.0 +{CWD}/prefix/node_modules/bar:bar@1.0.0:OVERRIDDEN ` exports[`test/lib/commands/ls.js TAP ls --parseable resolved points to git ref > should output tree containing git refs 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable-resolved-points-to-git-ref -{CWD}/tap-testdir-ls-ls---parseable-resolved-points-to-git-ref/node_modules/abbrev +{CWD}/prefix +{CWD}/prefix/node_modules/abbrev ` exports[`test/lib/commands/ls.js TAP ls --parseable unmet optional dep > should output parseable with empty entry for missing optional deps 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable-unmet-optional-dep -{CWD}/tap-testdir-ls-ls---parseable-unmet-optional-dep/node_modules/chai -{CWD}/tap-testdir-ls-ls---parseable-unmet-optional-dep/node_modules/dev-dep -{CWD}/tap-testdir-ls-ls---parseable-unmet-optional-dep/node_modules/optional-dep -{CWD}/tap-testdir-ls-ls---parseable-unmet-optional-dep/node_modules/peer-dep -{CWD}/tap-testdir-ls-ls---parseable-unmet-optional-dep/node_modules/prod-dep -{CWD}/tap-testdir-ls-ls---parseable-unmet-optional-dep/node_modules/foo -{CWD}/tap-testdir-ls-ls---parseable-unmet-optional-dep/node_modules/prod-dep/node_modules/dog -{CWD}/tap-testdir-ls-ls---parseable-unmet-optional-dep/node_modules/dog +{CWD}/prefix +{CWD}/prefix/node_modules/chai +{CWD}/prefix/node_modules/dev-dep +{CWD}/prefix/node_modules/optional-dep +{CWD}/prefix/node_modules/peer-dep +{CWD}/prefix/node_modules/prod-dep +{CWD}/prefix/node_modules/foo +{CWD}/prefix/node_modules/prod-dep/node_modules/dog +{CWD}/prefix/node_modules/dog ` exports[`test/lib/commands/ls.js TAP ls --parseable unmet peer dep > should output parseable signaling missing peer dep in problems 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable-unmet-peer-dep -{CWD}/tap-testdir-ls-ls---parseable-unmet-peer-dep/node_modules/chai -{CWD}/tap-testdir-ls-ls---parseable-unmet-peer-dep/node_modules/dev-dep -{CWD}/tap-testdir-ls-ls---parseable-unmet-peer-dep/node_modules/optional-dep -{CWD}/tap-testdir-ls-ls---parseable-unmet-peer-dep/node_modules/peer-dep -{CWD}/tap-testdir-ls-ls---parseable-unmet-peer-dep/node_modules/prod-dep -{CWD}/tap-testdir-ls-ls---parseable-unmet-peer-dep/node_modules/foo -{CWD}/tap-testdir-ls-ls---parseable-unmet-peer-dep/node_modules/prod-dep/node_modules/dog -{CWD}/tap-testdir-ls-ls---parseable-unmet-peer-dep/node_modules/dog +{CWD}/prefix +{CWD}/prefix/node_modules/chai +{CWD}/prefix/node_modules/dev-dep +{CWD}/prefix/node_modules/optional-dep +{CWD}/prefix/node_modules/peer-dep +{CWD}/prefix/node_modules/prod-dep +{CWD}/prefix/node_modules/foo +{CWD}/prefix/node_modules/prod-dep/node_modules/dog +{CWD}/prefix/node_modules/dog ` exports[`test/lib/commands/ls.js TAP ls --parseable using aliases > should output tree containing aliases 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable-using-aliases -{CWD}/tap-testdir-ls-ls---parseable-using-aliases/node_modules/a +{CWD}/prefix +{CWD}/prefix/node_modules/a ` exports[`test/lib/commands/ls.js TAP ls --parseable with filter arg > should output parseable contaning only occurrences of filtered by package 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable-with-filter-arg/node_modules/chai +{CWD}/prefix/node_modules/chai ` exports[`test/lib/commands/ls.js TAP ls --parseable with filter arg nested dep > should output parseable contaning only occurrences of filtered package 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable-with-filter-arg-nested-dep/node_modules/dog +{CWD}/prefix/node_modules/dog ` exports[`test/lib/commands/ls.js TAP ls --parseable with missing filter arg > should output parseable output containing no dependencies info 1`] = ` @@ -308,12 +308,12 @@ exports[`test/lib/commands/ls.js TAP ls --parseable with missing filter arg > sh ` exports[`test/lib/commands/ls.js TAP ls --parseable with multiple filter args > should output parseable contaning only occurrences of multiple filtered packages and their ancestors 1`] = ` -{CWD}/tap-testdir-ls-ls---parseable-with-multiple-filter-args/node_modules/chai -{CWD}/tap-testdir-ls-ls---parseable-with-multiple-filter-args/node_modules/dog +{CWD}/prefix/node_modules/chai +{CWD}/prefix/node_modules/dog ` exports[`test/lib/commands/ls.js TAP ls --production > should output tree containing production deps 1`] = ` -test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls---production +test-npm-ls@1.0.0 {CWD}/prefix +-- chai@1.0.0 +-- optional-dep@1.0.0 \`-- prod-dep@1.0.0 @@ -322,13 +322,13 @@ test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls---production ` exports[`test/lib/commands/ls.js TAP ls broken resolved field > should NOT print git refs in output tree 1`] = ` -npm-broken-resolved-field-test@1.0.0 {CWD}/tap-testdir-ls-ls-broken-resolved-field +npm-broken-resolved-field-test@1.0.0 {CWD}/prefix \`-- a@1.0.1 ` exports[`test/lib/commands/ls.js TAP ls colored output > should output tree containing color info 1`] = ` -test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-colored-output +test-npm-ls@1.0.0 {CWD}/prefix +-- chai@1.0.0 extraneous +-- foo@1.0.0 invalid: "^2.0.0" from the root project | \`-- dog@1.0.0 @@ -337,7 +337,7 @@ exports[`test/lib/commands/ls.js TAP ls colored output > should output tree cont ` exports[`test/lib/commands/ls.js TAP ls cycle deps > should print tree output containing deduped ref 1`] = ` -test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-cycle-deps +test-npm-ls@1.0.0 {CWD}/prefix \`-- a@1.0.0 \`-- b@1.0.0 \`-- a@1.0.0 deduped @@ -345,7 +345,7 @@ test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-cycle-deps ` exports[`test/lib/commands/ls.js TAP ls cycle deps with filter args > should print tree output containing deduped ref 1`] = ` -test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-cycle-deps-with-filter-args +test-npm-ls@1.0.0 {CWD}/prefix \`-- a@1.0.0  \`-- b@1.0.0  \`-- a@1.0.0 deduped @@ -353,7 +353,7 @@ exports[`test/lib/commands/ls.js TAP ls cycle deps with filter args > should pri ` exports[`test/lib/commands/ls.js TAP ls deduped missing dep > should output parseable signaling missing peer dep in problems 1`] = ` -test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-deduped-missing-dep +test-npm-ls@1.0.0 {CWD}/prefix +-- a@1.0.0 | \`-- UNMET DEPENDENCY b@^1.0.0 \`-- UNMET DEPENDENCY b@^1.0.0 @@ -361,40 +361,40 @@ test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-deduped-missing-dep ` exports[`test/lib/commands/ls.js TAP ls default --depth value should be 0 > should output tree containing only top-level dependencies 1`] = ` -test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-default---depth-value-should-be-0 +test-npm-ls@1.0.0 {CWD}/prefix +-- chai@1.0.0 \`-- foo@1.0.0 ` exports[`test/lib/commands/ls.js TAP ls empty location > should print empty result 1`] = ` -{CWD}/tap-testdir-ls-ls-empty-location +{CWD}/prefix \`-- (empty) ` exports[`test/lib/commands/ls.js TAP ls extraneous deps > should output containing problems info 1`] = ` -test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-extraneous-deps +test-npm-ls@1.0.0 {CWD}/prefix +-- chai@1.0.0 extraneous \`-- foo@1.0.0 \`-- dog@1.0.0 ` -exports[`test/lib/commands/ls.js TAP ls filter pkg arg using depth option > should list a in top-level only 1`] = ` -test-pkg-arg-filter-with-depth-opt@1.0.0 {CWD}/tap-testdir-ls-ls-filter-pkg-arg-using-depth-option +exports[`test/lib/commands/ls.js TAP ls filter pkg arg using depth option should list a in top-level only > output 1`] = ` +test-pkg-arg-filter-with-depth-opt@1.0.0 {CWD}/prefix \`-- a@1.0.0 ` -exports[`test/lib/commands/ls.js TAP ls filter pkg arg using depth option > should print empty results msg 1`] = ` -test-pkg-arg-filter-with-depth-opt@1.0.0 {CWD}/tap-testdir-ls-ls-filter-pkg-arg-using-depth-option +exports[`test/lib/commands/ls.js TAP ls filter pkg arg using depth option should print empty results msg > output 1`] = ` +test-pkg-arg-filter-with-depth-opt@1.0.0 {CWD}/prefix \`-- (empty) ` -exports[`test/lib/commands/ls.js TAP ls filter pkg arg using depth option > should print expected result 1`] = ` -test-pkg-arg-filter-with-depth-opt@1.0.0 {CWD}/tap-testdir-ls-ls-filter-pkg-arg-using-depth-option +exports[`test/lib/commands/ls.js TAP ls filter pkg arg using depth option should print expected result > output 1`] = ` +test-pkg-arg-filter-with-depth-opt@1.0.0 {CWD}/prefix \`-- b@1.0.0 \`-- c@1.0.0 \`-- d@1.0.0 @@ -402,7 +402,7 @@ test-pkg-arg-filter-with-depth-opt@1.0.0 {CWD}/tap-testdir-ls-ls-filter-pkg-arg- ` exports[`test/lib/commands/ls.js TAP ls filtering by child of missing dep > should print tree and not duplicate child of missing items 1`] = ` -filter-by-child-of-missing-dep@1.0.0 {CWD}/tap-testdir-ls-ls-filtering-by-child-of-missing-dep +filter-by-child-of-missing-dep@1.0.0 {CWD}/prefix +-- b@1.0.0 extraneous | \`-- c@1.0.0 deduped +-- c@1.0.0 extraneous @@ -412,13 +412,13 @@ filter-by-child-of-missing-dep@1.0.0 {CWD}/tap-testdir-ls-ls-filtering-by-child- ` exports[`test/lib/commands/ls.js TAP ls from and resolved properties > should not be printed in tree output 1`] = ` -test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-from-and-resolved-properties +test-npm-ls@1.0.0 {CWD}/prefix \`-- simple-output@2.1.1 ` exports[`test/lib/commands/ls.js TAP ls global > should print tree and not mark top-level items extraneous 1`] = ` -{CWD}/tap-testdir-ls-ls-global +{CWD}/global +-- a@1.0.0 \`-- b@1.0.0 \`-- c@1.0.0 @@ -426,7 +426,7 @@ exports[`test/lib/commands/ls.js TAP ls global > should print tree and not mark ` exports[`test/lib/commands/ls.js TAP ls invalid deduped dep > should output tree signaling mismatching peer dep in problems 1`] = ` -invalid-deduped-dep@1.0.0 {CWD}/tap-testdir-ls-ls-invalid-deduped-dep +invalid-deduped-dep@1.0.0 {CWD}/prefix +-- a@1.0.0 | \`-- b@1.0.0 deduped invalid: "^2.0.0" from the root project, "^2.0.0" from node_modules/a \`-- b@1.0.0 invalid: "^2.0.0" from the root project, "^2.0.0" from node_modules/a @@ -434,7 +434,7 @@ exports[`test/lib/commands/ls.js TAP ls invalid deduped dep > should output tree ` exports[`test/lib/commands/ls.js TAP ls invalid peer dep > should output tree signaling mismatching peer dep in problems 1`] = ` -test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-invalid-peer-dep +test-npm-ls@1.0.0 {CWD}/prefix +-- chai@1.0.0 +-- dev-dep@1.0.0 | \`-- foo@1.0.0 @@ -447,28 +447,28 @@ test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-invalid-peer-dep ` exports[`test/lib/commands/ls.js TAP ls json read problems > should print empty result 1`] = ` -{CWD}/tap-testdir-ls-ls-json-read-problems +{CWD}/prefix \`-- (empty) ` -exports[`test/lib/commands/ls.js TAP ls loading a tree containing workspaces > should filter by parent folder workspace config 1`] = ` -workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces +exports[`test/lib/commands/ls.js TAP ls loading a tree containing workspaces should filter by parent folder workspace config > output 1`] = ` +workspaces-tree@1.0.0 {CWD}/prefix +-- e@1.0.0 -> ./group/e \`-- f@1.0.0 -> ./group/f ` -exports[`test/lib/commands/ls.js TAP ls loading a tree containing workspaces > should filter single workspace 1`] = ` -workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces +exports[`test/lib/commands/ls.js TAP ls loading a tree containing workspaces should filter single workspace > output 1`] = ` +workspaces-tree@1.0.0 {CWD}/prefix +-- a@1.0.0 -> ./a | \`-- d@1.0.0 deduped -> ./d \`-- d@1.0.0 -> ./d ` -exports[`test/lib/commands/ls.js TAP ls loading a tree containing workspaces > should filter using workspace config 1`] = ` -workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces +exports[`test/lib/commands/ls.js TAP ls loading a tree containing workspaces should filter using workspace config > output 1`] = ` +workspaces-tree@1.0.0 {CWD}/prefix \`-- a@1.0.0 -> ./a +-- baz@1.0.0 +-- c@1.0.0 @@ -478,8 +478,8 @@ workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspac ` -exports[`test/lib/commands/ls.js TAP ls loading a tree containing workspaces > should inlude root and specified workspace 1`] = ` -workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces +exports[`test/lib/commands/ls.js TAP ls loading a tree containing workspaces should inlude root and specified workspace > output 1`] = ` +workspaces-tree@1.0.0 {CWD}/prefix +-- d@1.0.0 -> ./d | \`-- foo@1.1.1 | \`-- bar@1.0.0 @@ -487,8 +487,8 @@ workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspac ` -exports[`test/lib/commands/ls.js TAP ls loading a tree containing workspaces > should list --all workspaces properly 1`] = ` -workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces +exports[`test/lib/commands/ls.js TAP ls loading a tree containing workspaces should list --all workspaces properly > output 1`] = ` +workspaces-tree@1.0.0 {CWD}/prefix +-- a@1.0.0 -> ./a | +-- baz@1.0.0 | +-- c@1.0.0 @@ -503,8 +503,8 @@ workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspac ` -exports[`test/lib/commands/ls.js TAP ls loading a tree containing workspaces > should list only prod deps of workspaces 1`] = ` -workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces +exports[`test/lib/commands/ls.js TAP ls loading a tree containing workspaces should list only prod deps of workspaces > output 1`] = ` +workspaces-tree@1.0.0 {CWD}/prefix +-- a@1.0.0 -> ./a | +-- c@1.0.0 | \`-- d@1.0.0 deduped -> ./d @@ -518,8 +518,8 @@ workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspac ` -exports[`test/lib/commands/ls.js TAP ls loading a tree containing workspaces > should list workspaces properly with default configs 1`] = ` -workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces +exports[`test/lib/commands/ls.js TAP ls loading a tree containing workspaces should list workspaces properly with default configs > output 1`] = ` +workspaces-tree@1.0.0 {CWD}/prefix +-- a@1.0.0 -> ./a | +-- baz@1.0.0 | +-- c@1.0.0 @@ -533,14 +533,14 @@ exports[`test/lib/commands/ls.js TAP ls loading a tree containing workspaces > s  ` -exports[`test/lib/commands/ls.js TAP ls loading a tree containing workspaces > should not list workspaces with --no-workspaces 1`] = ` -workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces +exports[`test/lib/commands/ls.js TAP ls loading a tree containing workspaces should not list workspaces with --no-workspaces > output 1`] = ` +workspaces-tree@1.0.0 {CWD}/prefix \`-- pacote@1.0.0  ` -exports[`test/lib/commands/ls.js TAP ls loading a tree containing workspaces > should print all tree and filter by dep within only the ws subtree 1`] = ` -workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces +exports[`test/lib/commands/ls.js TAP ls loading a tree containing workspaces should print all tree and filter by dep within only the ws subtree > output 1`] = ` +workspaces-tree@1.0.0 {CWD}/prefix \`-- d@1.0.0 -> ./d \`-- foo@1.1.1 \`-- bar@1.0.0 @@ -548,7 +548,7 @@ workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspac ` exports[`test/lib/commands/ls.js TAP ls missing package.json > should output tree missing name/version of top-level package 1`] = ` -{CWD}/tap-testdir-ls-ls-missing-package.json +{CWD}/prefix +-- chai@1.0.0 extraneous +-- dog@1.0.0 extraneous \`-- foo@1.0.0 extraneous @@ -557,7 +557,7 @@ exports[`test/lib/commands/ls.js TAP ls missing package.json > should output tre ` exports[`test/lib/commands/ls.js TAP ls missing/invalid/extraneous > should output tree containing missing, invalid, extraneous labels 1`] = ` -test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-missing-invalid-extraneous +test-npm-ls@1.0.0 {CWD}/prefix +-- chai@1.0.0 extraneous +-- foo@1.0.0 invalid: "^2.0.0" from the root project | \`-- dog@1.0.0 @@ -566,7 +566,7 @@ test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-missing-invalid-extraneous ` exports[`test/lib/commands/ls.js TAP ls no args > should output tree representation of dependencies structure 1`] = ` -test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-no-args +test-npm-ls@1.0.0 {CWD}/prefix +-- chai@1.0.0 \`-- foo@1.0.0 \`-- dog@1.0.0 @@ -574,21 +574,21 @@ test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-no-args ` exports[`test/lib/commands/ls.js TAP ls overridden dep > should contain overridden outout 1`] = ` -test-overridden@1.0.0 {CWD}/tap-testdir-ls-ls-overridden-dep +test-overridden@1.0.0 {CWD}/prefix \`-- foo@1.0.0 \`-- bar@1.0.0 overridden ` exports[`test/lib/commands/ls.js TAP ls overridden dep w/ color > should contain overridden outout 1`] = ` -test-overridden@1.0.0 {CWD}/tap-testdir-ls-ls-overridden-dep-w-color +test-overridden@1.0.0 {CWD}/prefix \`-- foo@1.0.0  \`-- bar@1.0.0 overridden  ` exports[`test/lib/commands/ls.js TAP ls print deduped symlinks > should output tree containing linked deps 1`] = ` -print-deduped-symlinks@1.0.0 {CWD}/tap-testdir-ls-ls-print-deduped-symlinks +print-deduped-symlinks@1.0.0 {CWD}/prefix +-- a@1.0.0 | \`-- b@1.0.0 deduped -> ./b \`-- b@1.0.0 -> ./b @@ -596,13 +596,13 @@ print-deduped-symlinks@1.0.0 {CWD}/tap-testdir-ls-ls-print-deduped-symlinks ` exports[`test/lib/commands/ls.js TAP ls resolved points to git ref > should output tree containing git refs 1`] = ` -test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-resolved-points-to-git-ref +test-npm-ls@1.0.0 {CWD}/prefix \`-- abbrev@1.1.1 (git+ssh://git@github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c) ` exports[`test/lib/commands/ls.js TAP ls unmet optional dep > should output tree with empty entry for missing optional deps 1`] = ` -test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-unmet-optional-dep +test-npm-ls@1.0.0 {CWD}/prefix +-- chai@1.0.0 +-- dev-dep@1.0.0 | \`-- foo@1.0.0 @@ -616,19 +616,19 @@ exports[`test/lib/commands/ls.js TAP ls unmet optional dep > should output tree ` exports[`test/lib/commands/ls.js TAP ls unmet peer dep > should output tree signaling missing peer dep in problems 1`] = ` -test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-unmet-peer-dep +test-npm-ls@1.0.0 {CWD}/prefix \`-- UNMET DEPENDENCY peer-dep@* ` exports[`test/lib/commands/ls.js TAP ls using aliases > should output tree containing aliases 1`] = ` -test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-using-aliases +test-npm-ls@1.0.0 {CWD}/prefix \`-- a@npm:b@1.0.0 ` exports[`test/lib/commands/ls.js TAP ls with args and dedupe entries > should print tree output containing deduped ref 1`] = ` -dedupe-entries@1.0.0 {CWD}/tap-testdir-ls-ls-with-args-and-dedupe-entries +dedupe-entries@1.0.0 {CWD}/prefix +-- @npmcli/a@1.0.0 | \`-- @npmcli/b@1.1.2 deduped +-- @npmcli/b@1.1.2 @@ -638,7 +638,7 @@ exports[`test/lib/commands/ls.js TAP ls with args and dedupe entries > should pr ` exports[`test/lib/commands/ls.js TAP ls with args and different order of items > should print tree output containing deduped ref 1`] = ` -dedupe-entries@1.0.0 {CWD}/tap-testdir-ls-ls-with-args-and-different-order-of-items +dedupe-entries@1.0.0 {CWD}/prefix +-- @npmcli/a@1.0.0 | \`-- @npmcli/c@1.0.0 deduped +-- @npmcli/b@1.1.2 @@ -648,32 +648,32 @@ dedupe-entries@1.0.0 {CWD}/tap-testdir-ls-ls-with-args-and-different-order-of-it ` exports[`test/lib/commands/ls.js TAP ls with dot filter arg > should output tree contaning only occurrences of filtered by package and colored output 1`] = ` -test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-with-dot-filter-arg +test-npm-ls@1.0.0 {CWD}/prefix \`-- (empty) ` exports[`test/lib/commands/ls.js TAP ls with filter arg > should output tree contaning only occurrences of filtered by package and colored output 1`] = ` -test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-with-filter-arg +test-npm-ls@1.0.0 {CWD}/prefix \`-- chai@1.0.0  ` exports[`test/lib/commands/ls.js TAP ls with filter arg nested dep > should output tree contaning only occurrences of filtered package and its ancestors 1`] = ` -test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-with-filter-arg-nested-dep +test-npm-ls@1.0.0 {CWD}/prefix \`-- foo@1.0.0 \`-- dog@1.0.0 ` exports[`test/lib/commands/ls.js TAP ls with missing filter arg > should output tree containing no dependencies info 1`] = ` -test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-with-missing-filter-arg +test-npm-ls@1.0.0 {CWD}/prefix \`-- (empty) ` exports[`test/lib/commands/ls.js TAP ls with multiple filter args > should output tree contaning only occurrences of multiple filtered packages and their ancestors 1`] = ` -test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-with-multiple-filter-args +test-npm-ls@1.0.0 {CWD}/prefix +-- chai@1.0.0 \`-- foo@1.0.0 \`-- dog@1.0.0 @@ -681,7 +681,7 @@ test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-with-multiple-filter-args ` exports[`test/lib/commands/ls.js TAP ls with no args dedupe entries > should print tree output containing deduped ref 1`] = ` -dedupe-entries@1.0.0 {CWD}/tap-testdir-ls-ls-with-no-args-dedupe-entries +dedupe-entries@1.0.0 {CWD}/prefix +-- @npmcli/a@1.0.0 | \`-- @npmcli/b@1.1.2 deduped +-- @npmcli/b@1.1.2 @@ -691,7 +691,7 @@ dedupe-entries@1.0.0 {CWD}/tap-testdir-ls-ls-with-no-args-dedupe-entries ` exports[`test/lib/commands/ls.js TAP ls with no args dedupe entries and not displaying all > should print tree output containing deduped ref 1`] = ` -dedupe-entries@1.0.0 {CWD}/tap-testdir-ls-ls-with-no-args-dedupe-entries-and-not-displaying-all +dedupe-entries@1.0.0 {CWD}/prefix +-- @npmcli/a@1.0.0 +-- @npmcli/b@1.1.2 \`-- @npmcli/c@1.0.0 @@ -699,14 +699,14 @@ dedupe-entries@1.0.0 {CWD}/tap-testdir-ls-ls-with-no-args-dedupe-entries-and-not ` exports[`test/lib/commands/ls.js TAP ls workspace and missing optional dep > should omit missing optional dep 1`] = ` -root@ {CWD}/tap-testdir-ls-ls-workspace-and-missing-optional-dep +root@ {CWD}/prefix +-- baz@1.0.0 -> ./baz \`-- foo@1.0.0 ` exports[`test/lib/commands/ls.js TAP show multiple invalid reasons > ls result 1`] = ` -test-npm-ls@1.0.0 {cwd}/tap-testdir-ls-show-multiple-invalid-reasons +test-npm-ls@1.0.0 {CWD}/prefix +-- cat@1.0.0 invalid: "^2.0.0" from the root project | \`-- dog@1.0.0 deduped invalid: "^1.2.3" from the root project, "^2.0.0" from node_modules/cat +-- chai@1.0.0 extraneous diff --git a/deps/npm/tap-snapshots/test/lib/commands/outdated.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/outdated.js.test.cjs index ef6baa96661955..a72338b0bacc56 100644 --- a/deps/npm/tap-snapshots/test/lib/commands/outdated.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/outdated.js.test.cjs @@ -6,237 +6,216 @@ */ 'use strict' exports[`test/lib/commands/outdated.js TAP aliases > should display aliased outdated dep output 1`] = ` - Package Current Wanted Latest Location Depended by -cat:dog@latest 1.0.0 2.0.0 2.0.0 node_modules/cat tap-testdir-outdated-aliases +cat:dog@latest 1.0.0 2.0.0 2.0.0 node_modules/cat prefix ` exports[`test/lib/commands/outdated.js TAP should display outdated deps outdated --all > must match snapshot 1`] = ` - Package Current Wanted Latest Location Depended by -cat 1.0.0 1.0.1 1.0.1 node_modules/cat tap-testdir-outdated-should-display-outdated-deps -chai 1.0.0 1.0.1 1.0.1 node_modules/chai tap-testdir-outdated-should-display-outdated-deps -dog 1.0.1 1.0.1 2.0.0 node_modules/dog tap-testdir-outdated-should-display-outdated-deps -theta MISSING 1.0.1 1.0.1 - tap-testdir-outdated-should-display-outdated-deps +cat 1.0.0 1.0.1 1.0.1 node_modules/cat prefix +chai 1.0.0 1.0.1 1.0.1 node_modules/chai prefix +dog 1.0.1 1.0.1 2.0.0 node_modules/dog prefix +theta MISSING 1.0.1 1.0.1 - prefix ` exports[`test/lib/commands/outdated.js TAP should display outdated deps outdated --json --long > must match snapshot 1`] = ` - { "cat": { "current": "1.0.0", "wanted": "1.0.1", "latest": "1.0.1", - "dependent": "tap-testdir-outdated-should-display-outdated-deps", - "location": "{CWD}/test/lib/commands/tap-testdir-outdated-should-display-outdated-deps/node_modules/cat", + "dependent": "prefix", + "location": "{CWD}/prefix/node_modules/cat", "type": "dependencies" }, "chai": { "current": "1.0.0", "wanted": "1.0.1", "latest": "1.0.1", - "dependent": "tap-testdir-outdated-should-display-outdated-deps", - "location": "{CWD}/test/lib/commands/tap-testdir-outdated-should-display-outdated-deps/node_modules/chai", + "dependent": "prefix", + "location": "{CWD}/prefix/node_modules/chai", "type": "peerDependencies" }, "dog": { "current": "1.0.1", "wanted": "1.0.1", "latest": "2.0.0", - "dependent": "tap-testdir-outdated-should-display-outdated-deps", - "location": "{CWD}/test/lib/commands/tap-testdir-outdated-should-display-outdated-deps/node_modules/dog", + "dependent": "prefix", + "location": "{CWD}/prefix/node_modules/dog", "type": "dependencies" }, "theta": { "wanted": "1.0.1", "latest": "1.0.1", - "dependent": "tap-testdir-outdated-should-display-outdated-deps", + "dependent": "prefix", "type": "dependencies" } } ` exports[`test/lib/commands/outdated.js TAP should display outdated deps outdated --json > must match snapshot 1`] = ` - { "cat": { "current": "1.0.0", "wanted": "1.0.1", "latest": "1.0.1", - "dependent": "tap-testdir-outdated-should-display-outdated-deps", - "location": "{CWD}/test/lib/commands/tap-testdir-outdated-should-display-outdated-deps/node_modules/cat" + "dependent": "prefix", + "location": "{CWD}/prefix/node_modules/cat" }, "chai": { "current": "1.0.0", "wanted": "1.0.1", "latest": "1.0.1", - "dependent": "tap-testdir-outdated-should-display-outdated-deps", - "location": "{CWD}/test/lib/commands/tap-testdir-outdated-should-display-outdated-deps/node_modules/chai" + "dependent": "prefix", + "location": "{CWD}/prefix/node_modules/chai" }, "dog": { "current": "1.0.1", "wanted": "1.0.1", "latest": "2.0.0", - "dependent": "tap-testdir-outdated-should-display-outdated-deps", - "location": "{CWD}/test/lib/commands/tap-testdir-outdated-should-display-outdated-deps/node_modules/dog" + "dependent": "prefix", + "location": "{CWD}/prefix/node_modules/dog" }, "theta": { "wanted": "1.0.1", "latest": "1.0.1", - "dependent": "tap-testdir-outdated-should-display-outdated-deps" + "dependent": "prefix" } } ` exports[`test/lib/commands/outdated.js TAP should display outdated deps outdated --long > must match snapshot 1`] = ` - -Package Current Wanted Latest Location Depended by Package Type Homepage -cat 1.0.0 1.0.1 1.0.1 node_modules/cat tap-testdir-outdated-should-display-outdated-deps dependencies -chai 1.0.0 1.0.1 1.0.1 node_modules/chai tap-testdir-outdated-should-display-outdated-deps peerDependencies -dog 1.0.1 1.0.1 2.0.0 node_modules/dog tap-testdir-outdated-should-display-outdated-deps dependencies -theta MISSING 1.0.1 1.0.1 - tap-testdir-outdated-should-display-outdated-deps dependencies +Package Current Wanted Latest Location Depended by Package Type Homepage +cat 1.0.0 1.0.1 1.0.1 node_modules/cat prefix dependencies +chai 1.0.0 1.0.1 1.0.1 node_modules/chai prefix peerDependencies +dog 1.0.1 1.0.1 2.0.0 node_modules/dog prefix dependencies +theta MISSING 1.0.1 1.0.1 - prefix dependencies ` exports[`test/lib/commands/outdated.js TAP should display outdated deps outdated --omit=dev --omit=peer > must match snapshot 1`] = ` - Package Current Wanted Latest Location Depended by -cat 1.0.0 1.0.1 1.0.1 node_modules/cat tap-testdir-outdated-should-display-outdated-deps -dog 1.0.1 1.0.1 2.0.0 node_modules/dog tap-testdir-outdated-should-display-outdated-deps -theta MISSING 1.0.1 1.0.1 - tap-testdir-outdated-should-display-outdated-deps +cat 1.0.0 1.0.1 1.0.1 node_modules/cat prefix +dog 1.0.1 1.0.1 2.0.0 node_modules/dog prefix +theta MISSING 1.0.1 1.0.1 - prefix ` exports[`test/lib/commands/outdated.js TAP should display outdated deps outdated --omit=dev > must match snapshot 1`] = ` - Package Current Wanted Latest Location Depended by -cat 1.0.0 1.0.1 1.0.1 node_modules/cat tap-testdir-outdated-should-display-outdated-deps -chai 1.0.0 1.0.1 1.0.1 node_modules/chai tap-testdir-outdated-should-display-outdated-deps -dog 1.0.1 1.0.1 2.0.0 node_modules/dog tap-testdir-outdated-should-display-outdated-deps -theta MISSING 1.0.1 1.0.1 - tap-testdir-outdated-should-display-outdated-deps +cat 1.0.0 1.0.1 1.0.1 node_modules/cat prefix +chai 1.0.0 1.0.1 1.0.1 node_modules/chai prefix +dog 1.0.1 1.0.1 2.0.0 node_modules/dog prefix +theta MISSING 1.0.1 1.0.1 - prefix ` exports[`test/lib/commands/outdated.js TAP should display outdated deps outdated --omit=prod > must match snapshot 1`] = ` - Package Current Wanted Latest Location Depended by -cat 1.0.0 1.0.1 1.0.1 node_modules/cat tap-testdir-outdated-should-display-outdated-deps -chai 1.0.0 1.0.1 1.0.1 node_modules/chai tap-testdir-outdated-should-display-outdated-deps -dog 1.0.1 1.0.1 2.0.0 node_modules/dog tap-testdir-outdated-should-display-outdated-deps +cat 1.0.0 1.0.1 1.0.1 node_modules/cat prefix +chai 1.0.0 1.0.1 1.0.1 node_modules/chai prefix +dog 1.0.1 1.0.1 2.0.0 node_modules/dog prefix ` exports[`test/lib/commands/outdated.js TAP should display outdated deps outdated --parseable --long > must match snapshot 1`] = ` - -{CWD}/test/lib/commands/tap-testdir-outdated-should-display-outdated-deps/node_modules/cat:cat@1.0.1:cat@1.0.0:cat@1.0.1:tap-testdir-outdated-should-display-outdated-deps:dependencies: -{CWD}/test/lib/commands/tap-testdir-outdated-should-display-outdated-deps/node_modules/chai:chai@1.0.1:chai@1.0.0:chai@1.0.1:tap-testdir-outdated-should-display-outdated-deps:peerDependencies: -{CWD}/test/lib/commands/tap-testdir-outdated-should-display-outdated-deps/node_modules/dog:dog@1.0.1:dog@1.0.1:dog@2.0.0:tap-testdir-outdated-should-display-outdated-deps:dependencies: -:theta@1.0.1:MISSING:theta@1.0.1:tap-testdir-outdated-should-display-outdated-deps:dependencies: +{CWD}/prefix/node_modules/cat:cat@1.0.1:cat@1.0.0:cat@1.0.1:prefix:dependencies: +{CWD}/prefix/node_modules/chai:chai@1.0.1:chai@1.0.0:chai@1.0.1:prefix:peerDependencies: +{CWD}/prefix/node_modules/dog:dog@1.0.1:dog@1.0.1:dog@2.0.0:prefix:dependencies: +:theta@1.0.1:MISSING:theta@1.0.1:prefix:dependencies: ` exports[`test/lib/commands/outdated.js TAP should display outdated deps outdated --parseable > must match snapshot 1`] = ` - -{CWD}/test/lib/commands/tap-testdir-outdated-should-display-outdated-deps/node_modules/cat:cat@1.0.1:cat@1.0.0:cat@1.0.1:tap-testdir-outdated-should-display-outdated-deps -{CWD}/test/lib/commands/tap-testdir-outdated-should-display-outdated-deps/node_modules/chai:chai@1.0.1:chai@1.0.0:chai@1.0.1:tap-testdir-outdated-should-display-outdated-deps -{CWD}/test/lib/commands/tap-testdir-outdated-should-display-outdated-deps/node_modules/dog:dog@1.0.1:dog@1.0.1:dog@2.0.0:tap-testdir-outdated-should-display-outdated-deps -:theta@1.0.1:MISSING:theta@1.0.1:tap-testdir-outdated-should-display-outdated-deps +{CWD}/prefix/node_modules/cat:cat@1.0.1:cat@1.0.0:cat@1.0.1:prefix +{CWD}/prefix/node_modules/chai:chai@1.0.1:chai@1.0.0:chai@1.0.1:prefix +{CWD}/prefix/node_modules/dog:dog@1.0.1:dog@1.0.1:dog@2.0.0:prefix +:theta@1.0.1:MISSING:theta@1.0.1:prefix ` exports[`test/lib/commands/outdated.js TAP should display outdated deps outdated > must match snapshot 1`] = ` - Package Current Wanted Latest Location Depended by -cat 1.0.0 1.0.1 1.0.1 node_modules/cat tap-testdir-outdated-should-display-outdated-deps -chai 1.0.0 1.0.1 1.0.1 node_modules/chai tap-testdir-outdated-should-display-outdated-deps -dog 1.0.1 1.0.1 2.0.0 node_modules/dog tap-testdir-outdated-should-display-outdated-deps -theta MISSING 1.0.1 1.0.1 - tap-testdir-outdated-should-display-outdated-deps +cat 1.0.0 1.0.1 1.0.1 node_modules/cat prefix +chai 1.0.0 1.0.1 1.0.1 node_modules/chai prefix +dog 1.0.1 1.0.1 2.0.0 node_modules/dog prefix +theta MISSING 1.0.1 1.0.1 - prefix ` exports[`test/lib/commands/outdated.js TAP should display outdated deps outdated global > must match snapshot 1`] = ` - Package Current Wanted Latest Location Depended by cat 1.0.0 1.0.1 1.0.1 node_modules/cat global ` exports[`test/lib/commands/outdated.js TAP should display outdated deps outdated specific dep > must match snapshot 1`] = ` - Package Current Wanted Latest Location Depended by -cat 1.0.0 1.0.1 1.0.1 node_modules/cat tap-testdir-outdated-should-display-outdated-deps +cat 1.0.0 1.0.1 1.0.1 node_modules/cat prefix ` -exports[`test/lib/commands/outdated.js TAP workspaces > should display all dependencies 1`] = ` - +exports[`test/lib/commands/outdated.js TAP workspaces should display all dependencies > output 1`] = ` Package Current Wanted Latest Location Depended by cat 1.0.0 1.0.1 1.0.1 node_modules/cat a@1.0.0 chai 1.0.0 1.0.1 1.0.1 node_modules/chai foo -dog 1.0.1 1.0.1 2.0.0 node_modules/dog tap-testdir-outdated-workspaces +dog 1.0.1 1.0.1 2.0.0 node_modules/dog prefix theta MISSING 1.0.1 1.0.1 - c@1.0.0 ` -exports[`test/lib/commands/outdated.js TAP workspaces > should display json results filtered by ws 1`] = ` - +exports[`test/lib/commands/outdated.js TAP workspaces should display json results filtered by ws > output 1`] = ` { "cat": { "current": "1.0.0", "wanted": "1.0.1", "latest": "1.0.1", "dependent": "a", - "location": "{CWD}/test/lib/commands/tap-testdir-outdated-workspaces/node_modules/cat" + "location": "{CWD}/prefix/node_modules/cat" } } ` -exports[`test/lib/commands/outdated.js TAP workspaces > should display missing deps when filtering by ws 1`] = ` - +exports[`test/lib/commands/outdated.js TAP workspaces should display missing deps when filtering by ws > output 1`] = ` Package Current Wanted Latest Location Depended by theta MISSING 1.0.1 1.0.1 - c@1.0.0 ` -exports[`test/lib/commands/outdated.js TAP workspaces > should display nested deps when filtering by ws and using --all 1`] = ` - +exports[`test/lib/commands/outdated.js TAP workspaces should display nested deps when filtering by ws and using --all > output 1`] = ` Package Current Wanted Latest Location Depended by cat 1.0.0 1.0.1 1.0.1 node_modules/cat a@1.0.0 chai 1.0.0 1.0.1 1.0.1 node_modules/chai foo ` -exports[`test/lib/commands/outdated.js TAP workspaces > should display no results if ws has no deps to display 1`] = ` +exports[`test/lib/commands/outdated.js TAP workspaces should display no results if ws has no deps to display > output 1`] = ` ` -exports[`test/lib/commands/outdated.js TAP workspaces > should display only root outdated when ws disabled 1`] = ` +exports[`test/lib/commands/outdated.js TAP workspaces should display only root outdated when ws disabled > output 1`] = ` ` -exports[`test/lib/commands/outdated.js TAP workspaces > should display parseable results filtered by ws 1`] = ` - -{CWD}/test/lib/commands/tap-testdir-outdated-workspaces/node_modules/cat:cat@1.0.1:cat@1.0.0:cat@1.0.1:a +exports[`test/lib/commands/outdated.js TAP workspaces should display parseable results filtered by ws > output 1`] = ` +{CWD}/prefix/node_modules/cat:cat@1.0.1:cat@1.0.0:cat@1.0.1:a ` -exports[`test/lib/commands/outdated.js TAP workspaces > should display results filtered by ws 1`] = ` - +exports[`test/lib/commands/outdated.js TAP workspaces should display results filtered by ws > output 1`] = ` Package Current Wanted Latest Location Depended by cat 1.0.0 1.0.1 1.0.1 node_modules/cat a@1.0.0 ` -exports[`test/lib/commands/outdated.js TAP workspaces > should display ws outdated deps human output 1`] = ` - +exports[`test/lib/commands/outdated.js TAP workspaces should display ws outdated deps human output > output 1`] = ` Package Current Wanted Latest Location Depended by cat 1.0.0 1.0.1 1.0.1 node_modules/cat a@1.0.0 -dog 1.0.1 1.0.1 2.0.0 node_modules/dog tap-testdir-outdated-workspaces +dog 1.0.1 1.0.1 2.0.0 node_modules/dog prefix theta MISSING 1.0.1 1.0.1 - c@1.0.0 ` -exports[`test/lib/commands/outdated.js TAP workspaces > should display ws outdated deps json output 1`] = ` - +exports[`test/lib/commands/outdated.js TAP workspaces should display ws outdated deps json output > output 1`] = ` { "cat": { "current": "1.0.0", "wanted": "1.0.1", "latest": "1.0.1", "dependent": "a", - "location": "{CWD}/test/lib/commands/tap-testdir-outdated-workspaces/node_modules/cat" + "location": "{CWD}/prefix/node_modules/cat" }, "dog": { "current": "1.0.1", "wanted": "1.0.1", "latest": "2.0.0", - "dependent": "tap-testdir-outdated-workspaces", - "location": "{CWD}/test/lib/commands/tap-testdir-outdated-workspaces/node_modules/dog" + "dependent": "prefix", + "location": "{CWD}/prefix/node_modules/dog" }, "theta": { "wanted": "1.0.1", @@ -246,17 +225,15 @@ exports[`test/lib/commands/outdated.js TAP workspaces > should display ws outdat } ` -exports[`test/lib/commands/outdated.js TAP workspaces > should display ws outdated deps parseable output 1`] = ` - -{CWD}/test/lib/commands/tap-testdir-outdated-workspaces/node_modules/cat:cat@1.0.1:cat@1.0.0:cat@1.0.1:a -{CWD}/test/lib/commands/tap-testdir-outdated-workspaces/node_modules/dog:dog@1.0.1:dog@1.0.1:dog@2.0.0:tap-testdir-outdated-workspaces +exports[`test/lib/commands/outdated.js TAP workspaces should display ws outdated deps parseable output > output 1`] = ` +{CWD}/prefix/node_modules/cat:cat@1.0.1:cat@1.0.0:cat@1.0.1:a +{CWD}/prefix/node_modules/dog:dog@1.0.1:dog@1.0.1:dog@2.0.0:prefix :theta@1.0.1:MISSING:theta@1.0.1:c ` -exports[`test/lib/commands/outdated.js TAP workspaces > should highlight ws in dependend by section 1`] = ` - +exports[`test/lib/commands/outdated.js TAP workspaces should highlight ws in dependend by section > output 1`] = ` Package Current Wanted Latest Location Depended by cat 1.0.0 1.0.1 1.0.1 node_modules/cat a@1.0.0 -dog 1.0.1 1.0.1 2.0.0 node_modules/dog tap-testdir-outdated-workspaces +dog 1.0.1 1.0.1 2.0.0 node_modules/dog prefix theta MISSING 1.0.1 1.0.1 - c@1.0.0 ` diff --git a/deps/npm/tap-snapshots/test/lib/commands/profile.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/profile.js.test.cjs index 2103ccdd32e334..4959f7cdd2cc32 100644 --- a/deps/npm/tap-snapshots/test/lib/commands/profile.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/profile.js.test.cjs @@ -8,8 +8,7 @@ exports[`test/lib/commands/profile.js TAP enable-2fa from token and set otp, retries on pending and verifies with qrcode > should output 2fa enablement success msgs 1`] = ` Scan into your authenticator app: qrcode - Or enter code: -1234 + Or enter code: 1234 2FA successfully enabled. Below are your recovery codes, please print these out. You will need these to recover access to your account if you lose your authentication device. 123456 diff --git a/deps/npm/tap-snapshots/test/lib/commands/query.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/query.js.test.cjs index 9ad6e2e38084eb..a6dbfcf7c693c8 100644 --- a/deps/npm/tap-snapshots/test/lib/commands/query.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/query.js.test.cjs @@ -13,8 +13,8 @@ exports[`test/lib/commands/query.js TAP global > should return global package 1` "_id": "lorem@2.0.0", "pkgid": "lorem@2.0.0", "location": "node_modules/lorem", - "path": "{CWD}/test/lib/commands/tap-testdir-query-global/global/node_modules/lorem", - "realpath": "{CWD}/test/lib/commands/tap-testdir-query-global/global/node_modules/lorem", + "path": "{CWD}/global/node_modules/lorem", + "realpath": "{CWD}/global/node_modules/lorem", "resolved": null, "from": [ "" @@ -42,8 +42,8 @@ exports[`test/lib/commands/query.js TAP include-workspace-root > should return w }, "pkgid": "project@", "location": "", - "path": "{CWD}/test/lib/commands/tap-testdir-query-include-workspace-root/prefix", - "realpath": "{CWD}/test/lib/commands/tap-testdir-query-include-workspace-root/prefix", + "path": "{CWD}/prefix", + "realpath": "{CWD}/prefix", "resolved": null, "from": [], "to": [ @@ -63,8 +63,8 @@ exports[`test/lib/commands/query.js TAP include-workspace-root > should return w "_id": "c@1.0.0", "pkgid": "c@1.0.0", "location": "c", - "path": "{CWD}/test/lib/commands/tap-testdir-query-include-workspace-root/prefix/c", - "realpath": "{CWD}/test/lib/commands/tap-testdir-query-include-workspace-root/prefix/c", + "path": "{CWD}/prefix/c", + "realpath": "{CWD}/prefix/c", "resolved": null, "from": [], "to": [], @@ -85,8 +85,8 @@ exports[`test/lib/commands/query.js TAP linked node > should return linked node "_id": "a@1.0.0", "pkgid": "a@1.0.0", "location": "a", - "path": "{CWD}/test/lib/commands/tap-testdir-query-linked-node/prefix/a", - "realpath": "{CWD}/test/lib/commands/tap-testdir-query-linked-node/prefix/a", + "path": "{CWD}/prefix/a", + "realpath": "{CWD}/prefix/a", "resolved": null, "from": [], "to": [], @@ -109,8 +109,8 @@ exports[`test/lib/commands/query.js TAP recursive tree > should return everythin }, "pkgid": "project@", "location": "", - "path": "{CWD}/test/lib/commands/tap-testdir-query-recursive-tree/prefix", - "realpath": "{CWD}/test/lib/commands/tap-testdir-query-recursive-tree/prefix", + "path": "{CWD}/prefix", + "realpath": "{CWD}/prefix", "resolved": null, "from": [], "to": [ @@ -126,8 +126,8 @@ exports[`test/lib/commands/query.js TAP recursive tree > should return everythin { "pkgid": "a@", "location": "node_modules/a", - "path": "{CWD}/test/lib/commands/tap-testdir-query-recursive-tree/prefix/node_modules/a", - "realpath": "{CWD}/test/lib/commands/tap-testdir-query-recursive-tree/prefix/node_modules/a", + "path": "{CWD}/prefix/node_modules/a", + "realpath": "{CWD}/prefix/node_modules/a", "resolved": null, "from": [ "" @@ -142,8 +142,8 @@ exports[`test/lib/commands/query.js TAP recursive tree > should return everythin { "pkgid": "b@", "location": "node_modules/b", - "path": "{CWD}/test/lib/commands/tap-testdir-query-recursive-tree/prefix/node_modules/b", - "realpath": "{CWD}/test/lib/commands/tap-testdir-query-recursive-tree/prefix/node_modules/b", + "path": "{CWD}/prefix/node_modules/b", + "realpath": "{CWD}/prefix/node_modules/b", "resolved": null, "from": [ "" @@ -171,8 +171,8 @@ exports[`test/lib/commands/query.js TAP simple query > should return root object }, "pkgid": "project@", "location": "", - "path": "{CWD}/test/lib/commands/tap-testdir-query-simple-query/prefix", - "realpath": "{CWD}/test/lib/commands/tap-testdir-query-simple-query/prefix", + "path": "{CWD}/prefix", + "realpath": "{CWD}/prefix", "resolved": null, "from": [], "to": [ @@ -188,8 +188,8 @@ exports[`test/lib/commands/query.js TAP simple query > should return root object { "pkgid": "a@", "location": "node_modules/a", - "path": "{CWD}/test/lib/commands/tap-testdir-query-simple-query/prefix/node_modules/a", - "realpath": "{CWD}/test/lib/commands/tap-testdir-query-simple-query/prefix/node_modules/a", + "path": "{CWD}/prefix/node_modules/a", + "realpath": "{CWD}/prefix/node_modules/a", "resolved": null, "from": [ "" @@ -204,8 +204,8 @@ exports[`test/lib/commands/query.js TAP simple query > should return root object { "pkgid": "b@", "location": "node_modules/b", - "path": "{CWD}/test/lib/commands/tap-testdir-query-simple-query/prefix/node_modules/b", - "realpath": "{CWD}/test/lib/commands/tap-testdir-query-simple-query/prefix/node_modules/b", + "path": "{CWD}/prefix/node_modules/b", + "realpath": "{CWD}/prefix/node_modules/b", "resolved": null, "from": [ "" @@ -228,8 +228,8 @@ exports[`test/lib/commands/query.js TAP workspace query > should return workspac "_id": "c@1.0.0", "pkgid": "c@1.0.0", "location": "c", - "path": "{CWD}/test/lib/commands/tap-testdir-query-workspace-query/prefix/c", - "realpath": "{CWD}/test/lib/commands/tap-testdir-query-workspace-query/prefix/c", + "path": "{CWD}/prefix/c", + "realpath": "{CWD}/prefix/c", "resolved": null, "from": [], "to": [], diff --git a/deps/npm/tap-snapshots/test/lib/commands/stars.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/stars.js.test.cjs index fbf074f718d1d9..d55d7b414d7fd2 100644 --- a/deps/npm/tap-snapshots/test/lib/commands/stars.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/stars.js.test.cjs @@ -6,7 +6,6 @@ */ 'use strict' exports[`test/lib/commands/stars.js TAP no args > should output a list of starred packages 1`] = ` - @npmcli/arborist @npmcli/map-workspaces libnpmfund diff --git a/deps/npm/tap-snapshots/test/lib/commands/team.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/team.js.test.cjs index 6a93234f54fc84..f72fcb2f1fa943 100644 --- a/deps/npm/tap-snapshots/test/lib/commands/team.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/team.js.test.cjs @@ -37,18 +37,18 @@ ruyadorno ` exports[`test/lib/commands/team.js TAP team ls default output > should list users for a given scope:team 1`] = ` - @npmcli:developers has 4 users: -darcyclarke isaacs nlf ruyadorno +darcyclarke +isaacs +nlf +ruyadorno ` exports[`test/lib/commands/team.js TAP team ls no users > should list no users for a given scope 1`] = ` - @npmcli:developers has 0 users ` exports[`test/lib/commands/team.js TAP team ls single user > should list single user for a given scope 1`] = ` - @npmcli:developers has 1 user: foo ` @@ -60,18 +60,17 @@ npmcli:product ` exports[`test/lib/commands/team.js TAP team ls default output > should list teams for a given scope 1`] = ` - @npmcli has 3 teams: -@npmcli:designers @npmcli:developers @npmcli:product +@npmcli:designers +@npmcli:developers +@npmcli:product ` exports[`test/lib/commands/team.js TAP team ls no teams > should list no teams for a given scope 1`] = ` - @npmcli has 0 teams ` exports[`test/lib/commands/team.js TAP team ls single team > should list single team for a given scope 1`] = ` - @npmcli has 1 team: @npmcli:developers ` diff --git a/deps/npm/tap-snapshots/test/lib/docs.js.test.cjs b/deps/npm/tap-snapshots/test/lib/docs.js.test.cjs index c18dd305b052b4..578bbd79812a22 100644 --- a/deps/npm/tap-snapshots/test/lib/docs.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/docs.js.test.cjs @@ -604,8 +604,8 @@ safer to use a registry-provided authentication bearer token stored in the current level * Type: null, "restricted", or "public" -If do not want your scoped package to be publicly viewable (and installable) -set \`--access=restricted\`. +If you do not want your scoped package to be publicly viewable (and +installable) set \`--access=restricted\`. Unscoped packages can not be set to \`restricted\`. @@ -654,7 +654,8 @@ exit code. * Default: "web" * Type: "legacy" or "web" -What authentication strategy to use with \`login\`. +What authentication strategy to use with \`login\`. Note that if an \`otp\` +config is given, this value will always be set to \`legacy\`. #### \`before\` @@ -1702,7 +1703,7 @@ be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range set in their package's \`peerDependencies\` object. -When such and override is performed, a warning is printed, explaining the +When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If \`--strict-peer-deps\` is set, then this warning is treated as a failure. @@ -1983,7 +1984,7 @@ Alias for \`--include=dev\`. \`--install-strategy=shallow\` Only install direct dependencies in the top level \`node_modules\`, but hoist -on deeper dependendencies. Sets \`--install-strategy=shallow\`. +on deeper dependencies. Sets \`--install-strategy=shallow\`. #### \`init.author.email\` @@ -2380,6 +2381,7 @@ Array [ "tag", "tag-version-prefix", "umask", + "unicode", "user-agent", "workspace", "workspaces", @@ -2409,7 +2411,6 @@ Array [ "prefix", "timing", "tmp", - "unicode", "update-notifier", "usage", "userconfig", @@ -2491,6 +2492,8 @@ npm access grant [] npm access revoke [] \`\`\` +Note: This command is unaware of workspaces. + #### \`json\` #### \`otp\` #### \`registry\` @@ -2515,6 +2518,8 @@ npm adduser alias: add-user \`\`\` +Note: This command is unaware of workspaces. + #### \`registry\` #### \`scope\` #### \`auth-type\` @@ -2603,6 +2608,8 @@ npm cache ls [@] npm cache verify \`\`\` +Note: This command is unaware of workspaces. + #### \`cache\` ` @@ -2665,6 +2672,8 @@ Run "npm help completion" for more info npm completion \`\`\` +Note: This command is unaware of workspaces. + NO PARAMS ` @@ -2698,6 +2707,8 @@ npm config fix alias: c \`\`\` +Note: This command is unaware of workspaces. + #### \`json\` #### \`global\` #### \`editor\` @@ -2761,6 +2772,8 @@ Run "npm help deprecate" for more info npm deprecate \`\`\` +Note: This command is unaware of workspaces. + #### \`registry\` #### \`otp\` ` @@ -2872,6 +2885,8 @@ Run "npm help doctor" for more info npm doctor [ping] [registry] [versions] [environment] [permissions] [cache] \`\`\` +Note: This command is unaware of workspaces. + #### \`registry\` ` @@ -2890,6 +2905,8 @@ Run "npm help edit" for more info npm edit [/...] \`\`\` +Note: This command is unaware of workspaces. + #### \`editor\` ` @@ -2965,6 +2982,8 @@ Run "npm help explore" for more info npm explore [ -- ] \`\`\` +Note: This command is unaware of workspaces. + #### \`shell\` ` @@ -3040,6 +3059,8 @@ Run "npm help get" for more info npm get [ ...] (See \`npm config\`) \`\`\` +Note: This command is unaware of workspaces. + NO PARAMS ` @@ -3062,6 +3083,8 @@ npm help [] alias: hlep \`\`\` +Note: This command is unaware of workspaces. + #### \`viewer\` ` @@ -3080,6 +3103,8 @@ Run "npm help help-search" for more info npm help-search \`\`\` +Note: This command is unaware of workspaces. + #### \`long\` ` @@ -3104,6 +3129,8 @@ npm hook rm npm hook update \`\`\` +Note: This command is unaware of workspaces. + #### \`registry\` #### \`otp\` ` @@ -3112,7 +3139,7 @@ exports[`test/lib/docs.js TAP usage init > must match snapshot 1`] = ` Create a package.json file Usage: -npm init (same as \`npx ) +npm init (same as \`npx \`) npm init <@scope> (same as \`npx <@scope>/create\`) Options: @@ -3125,7 +3152,7 @@ aliases: create, innit Run "npm help init" for more info \`\`\`bash -npm init (same as \`npx ) +npm init (same as \`npx \`) npm init <@scope> (same as \`npx <@scope>/create\`) aliases: create, innit @@ -3380,6 +3407,8 @@ Run "npm help login" for more info npm login \`\`\` +Note: This command is unaware of workspaces. + #### \`registry\` #### \`scope\` #### \`auth-type\` @@ -3400,6 +3429,8 @@ Run "npm help logout" for more info npm logout \`\`\` +Note: This command is unaware of workspaces. + #### \`registry\` #### \`scope\` ` @@ -3448,6 +3479,8 @@ exports[`test/lib/docs.js TAP usage npm > must match snapshot 1`] = ` npm \`\`\` +Note: This command is unaware of workspaces. + NO PARAMS ` @@ -3485,6 +3518,8 @@ npm org ls orgname [] alias: ogr \`\`\` +Note: This command is unaware of workspaces. + #### \`registry\` #### \`otp\` #### \`json\` @@ -3586,6 +3621,8 @@ Run "npm help ping" for more info npm ping \`\`\` +Note: This command is unaware of workspaces. + #### \`registry\` ` @@ -3635,6 +3672,8 @@ Run "npm help prefix" for more info npm prefix [-g] \`\`\` +Note: This command is unaware of workspaces. + #### \`global\` ` @@ -3659,6 +3698,8 @@ npm profile get [] npm profile set \`\`\` +Note: This command is unaware of workspaces. + #### \`registry\` #### \`json\` #### \`parseable\` @@ -3832,6 +3873,8 @@ Run "npm help root" for more info npm root \`\`\` +Note: This command is unaware of workspaces. + #### \`global\` ` @@ -3886,6 +3929,8 @@ npm search [search terms ...] aliases: find, s, se \`\`\` +Note: This command is unaware of workspaces. + #### \`long\` #### \`json\` #### \`color\` @@ -3911,6 +3956,8 @@ Run "npm help set" for more info npm set = [= ...] (See \`npm config\`) \`\`\` +Note: This command is unaware of workspaces. + NO PARAMS ` @@ -3926,6 +3973,8 @@ Run "npm help shrinkwrap" for more info npm shrinkwrap \`\`\` +Note: This command is unaware of workspaces. + NO PARAMS ` @@ -3944,6 +3993,8 @@ Run "npm help star" for more info npm star [...] \`\`\` +Note: This command is unaware of workspaces. + #### \`registry\` #### \`unicode\` #### \`otp\` @@ -3964,6 +4015,8 @@ Run "npm help stars" for more info npm stars [] \`\`\` +Note: This command is unaware of workspaces. + #### \`registry\` ` @@ -4028,6 +4081,8 @@ npm team rm [--otp ] npm team ls | \`\`\` +Note: This command is unaware of workspaces. + #### \`registry\` #### \`otp\` #### \`parseable\` @@ -4077,6 +4132,8 @@ npm token revoke npm token create [--read-only] [--cidr=list] \`\`\` +Note: This command is unaware of workspaces. + #### \`read-only\` #### \`cidr\` #### \`registry\` @@ -4149,6 +4206,8 @@ Run "npm help unstar" for more info npm unstar [...] \`\`\` +Note: This command is unaware of workspaces. + #### \`registry\` #### \`unicode\` #### \`otp\` @@ -4274,5 +4333,7 @@ Run "npm help whoami" for more info npm whoami \`\`\` +Note: This command is unaware of workspaces. + #### \`registry\` ` diff --git a/deps/npm/tap-snapshots/test/lib/utils/error-message.js.test.cjs b/deps/npm/tap-snapshots/test/lib/utils/error-message.js.test.cjs index 7b689ff9728203..5fe20969fce315 100644 --- a/deps/npm/tap-snapshots/test/lib/utils/error-message.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/utils/error-message.js.test.cjs @@ -390,7 +390,7 @@ Object { "", Error: whoopsie { "code": "EACCES", - "dest": "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-false-cachePath-false-cacheDest-true-/cache/dest", + "dest": "{CWD}/cache/dest", "path": "/not/cache/dir/path", }, ], @@ -424,7 +424,7 @@ Object { Error: whoopsie { "code": "EACCES", "dest": "/not/cache/dir/dest", - "path": "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-false-cachePath-true-cacheDest-false-/cache/path", + "path": "{CWD}/cache/path", }, ], ], @@ -456,8 +456,8 @@ Object { "", Error: whoopsie { "code": "EACCES", - "dest": "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-false-cachePath-true-cacheDest-true-/cache/dest", - "path": "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-false-cachePath-true-cacheDest-true-/cache/path", + "dest": "{CWD}/cache/dest", + "path": "{CWD}/cache/path", }, ], ], @@ -505,15 +505,15 @@ Array [ ], Array [ "argv", - "", + "/"--fetch-retries/" /"0/" /"--cache/" /"{CWD}/cache/"", ], Array [ "logfile", - "logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-true-cachePath-false-cacheDest-false-/cache/_logs/{DATE}-", + "logs-max:10 dir:{CWD}/cache/_logs/{DATE}-", ], Array [ "logfile", - "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-true-cachePath-false-cacheDest-false-/cache/_logs/{DATE}-debug-0.log", + "{CWD}/cache/_logs/{DATE}-debug-0.log", ], ] ` @@ -530,7 +530,7 @@ Object { previous versions of npm which has since been addressed. To permanently fix this problem, please run: - sudo chown -R 867:5309 "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-true-cachePath-false-cacheDest-true-/cache" + sudo chown -R 867:5309 "{CWD}/cache" ), ], ], @@ -545,18 +545,15 @@ Array [ ], Array [ "argv", - "", + "/"--fetch-retries/" /"0/" /"--cache/" /"{CWD}/cache/"", ], Array [ "logfile", - "logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-true-cachePath-false-cacheDest-true-/cache/_logs/{DATE}-", + "logs-max:10 dir:{CWD}/cache/_logs/{DATE}-", ], Array [ "logfile", - "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-true-cachePath-false-cacheDest-true-/cache/_logs/{DATE}-debug-0.log", - ], - Array [ - "dummy stack trace", + "{CWD}/cache/_logs/{DATE}-debug-0.log", ], ] ` @@ -573,7 +570,7 @@ Object { previous versions of npm which has since been addressed. To permanently fix this problem, please run: - sudo chown -R 867:5309 "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-true-cachePath-true-cacheDest-false-/cache" + sudo chown -R 867:5309 "{CWD}/cache" ), ], ], @@ -588,18 +585,15 @@ Array [ ], Array [ "argv", - "", + "/"--fetch-retries/" /"0/" /"--cache/" /"{CWD}/cache/"", ], Array [ "logfile", - "logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-true-cachePath-true-cacheDest-false-/cache/_logs/{DATE}-", + "logs-max:10 dir:{CWD}/cache/_logs/{DATE}-", ], Array [ "logfile", - "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-true-cachePath-true-cacheDest-false-/cache/_logs/{DATE}-debug-0.log", - ], - Array [ - "dummy stack trace", + "{CWD}/cache/_logs/{DATE}-debug-0.log", ], ] ` @@ -616,7 +610,7 @@ Object { previous versions of npm which has since been addressed. To permanently fix this problem, please run: - sudo chown -R 867:5309 "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-true-cachePath-true-cacheDest-true-/cache" + sudo chown -R 867:5309 "{CWD}/cache" ), ], ], @@ -631,18 +625,15 @@ Array [ ], Array [ "argv", - "", + "/"--fetch-retries/" /"0/" /"--cache/" /"{CWD}/cache/"", ], Array [ "logfile", - "logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-true-cachePath-true-cacheDest-true-/cache/_logs/{DATE}-", + "logs-max:10 dir:{CWD}/cache/_logs/{DATE}-", ], Array [ "logfile", - "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-true-cachePath-true-cacheDest-true-/cache/_logs/{DATE}-debug-0.log", - ], - Array [ - "dummy stack trace", + "{CWD}/cache/_logs/{DATE}-debug-0.log", ], ] ` @@ -703,7 +694,7 @@ Object { "", Error: whoopsie { "code": "EACCES", - "dest": "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-false-cachePath-false-cacheDest-true-/cache/dest", + "dest": "{CWD}/cache/dest", "path": "/not/cache/dir/path", }, ], @@ -738,7 +729,7 @@ Object { Error: whoopsie { "code": "EACCES", "dest": "/not/cache/dir/dest", - "path": "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-false-cachePath-true-cacheDest-false-/cache/path", + "path": "{CWD}/cache/path", }, ], ], @@ -771,8 +762,8 @@ Object { "", Error: whoopsie { "code": "EACCES", - "dest": "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-false-cachePath-true-cacheDest-true-/cache/dest", - "path": "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-false-cachePath-true-cacheDest-true-/cache/path", + "dest": "{CWD}/cache/dest", + "path": "{CWD}/cache/path", }, ], ], @@ -821,15 +812,15 @@ Array [ ], Array [ "argv", - "", + "/"--fetch-retries/" /"0/" /"--cache/" /"{CWD}/cache/"", ], Array [ "logfile", - "logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-false-cacheDest-false-/cache/_logs/{DATE}-", + "logs-max:10 dir:{CWD}/cache/_logs/{DATE}-", ], Array [ "logfile", - "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-false-cacheDest-false-/cache/_logs/{DATE}-debug-0.log", + "{CWD}/cache/_logs/{DATE}-debug-0.log", ], ] ` @@ -856,7 +847,7 @@ Object { "", Error: whoopsie { "code": "EACCES", - "dest": "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-false-cacheDest-true-/cache/dest", + "dest": "{CWD}/cache/dest", "path": "/not/cache/dir/path", }, ], @@ -872,15 +863,15 @@ Array [ ], Array [ "argv", - "", + "/"--fetch-retries/" /"0/" /"--cache/" /"{CWD}/cache/"", ], Array [ "logfile", - "logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-false-cacheDest-true-/cache/_logs/{DATE}-", + "logs-max:10 dir:{CWD}/cache/_logs/{DATE}-", ], Array [ "logfile", - "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-false-cacheDest-true-/cache/_logs/{DATE}-debug-0.log", + "{CWD}/cache/_logs/{DATE}-debug-0.log", ], ] ` @@ -908,7 +899,7 @@ Object { Error: whoopsie { "code": "EACCES", "dest": "/not/cache/dir/dest", - "path": "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-true-cacheDest-false-/cache/path", + "path": "{CWD}/cache/path", }, ], ], @@ -923,15 +914,15 @@ Array [ ], Array [ "argv", - "", + "/"--fetch-retries/" /"0/" /"--cache/" /"{CWD}/cache/"", ], Array [ "logfile", - "logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-true-cacheDest-false-/cache/_logs/{DATE}-", + "logs-max:10 dir:{CWD}/cache/_logs/{DATE}-", ], Array [ "logfile", - "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-true-cacheDest-false-/cache/_logs/{DATE}-debug-0.log", + "{CWD}/cache/_logs/{DATE}-debug-0.log", ], ] ` @@ -958,8 +949,8 @@ Object { "", Error: whoopsie { "code": "EACCES", - "dest": "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-true-cacheDest-true-/cache/dest", - "path": "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-true-cacheDest-true-/cache/path", + "dest": "{CWD}/cache/dest", + "path": "{CWD}/cache/path", }, ], ], @@ -974,15 +965,15 @@ Array [ ], Array [ "argv", - "", + "/"--fetch-retries/" /"0/" /"--cache/" /"{CWD}/cache/"", ], Array [ "logfile", - "logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-true-cacheDest-true-/cache/_logs/{DATE}-", + "logs-max:10 dir:{CWD}/cache/_logs/{DATE}-", ], Array [ "logfile", - "{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-true-cacheDest-true-/cache/_logs/{DATE}-debug-0.log", + "{CWD}/cache/_logs/{DATE}-debug-0.log", ], ] ` @@ -1280,7 +1271,7 @@ Object { String( Not compatible with your version of node/npm: some@package Required: undefined - Actual: {"npm":"123.456.789-npm","node":"99.99.99"} + Actual: {"npm":"123.456.789-npm","node":"123.456.789-node"} ), ], ], diff --git a/deps/npm/tap-snapshots/test/lib/utils/exit-handler.js.test.cjs b/deps/npm/tap-snapshots/test/lib/utils/exit-handler.js.test.cjs index eed705be384a25..4c163e7df5593d 100644 --- a/deps/npm/tap-snapshots/test/lib/utils/exit-handler.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/utils/exit-handler.js.test.cjs @@ -12,18 +12,18 @@ exports[`test/lib/utils/exit-handler.js TAP handles unknown error with logs and 15 timing npm:load:mkdirpcache Completed in {TIME}ms 16 timing npm:load:mkdirplogs Completed in {TIME}ms 17 verbose title npm -18 verbose argv +18 verbose argv "--fetch-retries" "0" "--cache" "{CWD}/cache" "--loglevel" "notice" 19 timing npm:load:setTitle Completed in {TIME}ms 21 timing npm:load:display Completed in {TIME}ms -22 verbose logfile logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-exit-handler-handles-unknown-error-with-logs-and-debug-file/cache/_logs/{DATE}- -23 verbose logfile {CWD}/test/lib/utils/tap-testdir-exit-handler-handles-unknown-error-with-logs-and-debug-file/cache/_logs/{DATE}-debug-0.log +22 verbose logfile logs-max:10 dir:{CWD}/cache/_logs/{DATE}- +23 verbose logfile {CWD}/cache/_logs/{DATE}-debug-0.log 24 timing npm:load:logFile Completed in {TIME}ms 25 timing npm:load:timers Completed in {TIME}ms 26 timing npm:load:configScope Completed in {TIME}ms 27 timing npm:load Completed in {TIME}ms 28 silly logfile done cleaning log files 29 verbose stack Error: Unknown error -30 verbose cwd {CWD} +30 verbose cwd {CWD}/prefix 31 verbose Foo 1.0.0 32 verbose node v1.0.0 33 verbose npm v1.0.0 @@ -31,10 +31,10 @@ exports[`test/lib/utils/exit-handler.js TAP handles unknown error with logs and 35 error ERR SUMMARY Unknown error 36 error ERR DETAIL Unknown error 37 verbose exit 1 -39 timing npm Completed in {TIME}ms -40 verbose code 1 -41 error A complete log of this run can be found in: -41 error {CWD}/test/lib/utils/tap-testdir-exit-handler-handles-unknown-error-with-logs-and-debug-file/cache/_logs/{DATE}-debug-0.log +38 timing npm Completed in {TIME}ms +39 verbose code 1 +40 error A complete log of this run can be found in: +40 error {CWD}/cache/_logs/{DATE}-debug-0.log ` exports[`test/lib/utils/exit-handler.js TAP handles unknown error with logs and debug file > logs 1`] = ` @@ -44,18 +44,18 @@ timing npm:load:configload Completed in {TIME}ms timing npm:load:mkdirpcache Completed in {TIME}ms timing npm:load:mkdirplogs Completed in {TIME}ms verbose title npm -verbose argv +verbose argv "--fetch-retries" "0" "--cache" "{CWD}/cache" "--loglevel" "notice" timing npm:load:setTitle Completed in {TIME}ms timing npm:load:display Completed in {TIME}ms -verbose logfile logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-exit-handler-handles-unknown-error-with-logs-and-debug-file/cache/_logs/{DATE}- -verbose logfile {CWD}/test/lib/utils/tap-testdir-exit-handler-handles-unknown-error-with-logs-and-debug-file/cache/_logs/{DATE}-debug-0.log +verbose logfile logs-max:10 dir:{CWD}/cache/_logs/{DATE}- +verbose logfile {CWD}/cache/_logs/{DATE}-debug-0.log timing npm:load:logFile Completed in {TIME}ms timing npm:load:timers Completed in {TIME}ms timing npm:load:configScope Completed in {TIME}ms timing npm:load Completed in {TIME}ms silly logfile done cleaning log files verbose stack Error: Unknown error -verbose cwd {CWD} +verbose cwd {CWD}/prefix verbose Foo 1.0.0 verbose node v1.0.0 verbose npm v1.0.0 @@ -66,5 +66,5 @@ verbose exit 1 timing npm Completed in {TIME}ms verbose code 1 error A complete log of this run can be found in: - {CWD}/test/lib/utils/tap-testdir-exit-handler-handles-unknown-error-with-logs-and-debug-file/cache/_logs/{DATE}-debug-0.log + {CWD}/cache/_logs/{DATE}-debug-0.log ` diff --git a/deps/npm/tap-snapshots/test/lib/utils/log-file.js.test.cjs b/deps/npm/tap-snapshots/test/lib/utils/log-file.js.test.cjs index 912a4365f68104..0a4af7cadf0607 100644 --- a/deps/npm/tap-snapshots/test/lib/utils/log-file.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/utils/log-file.js.test.cjs @@ -6,7 +6,7 @@ */ 'use strict' exports[`test/lib/utils/log-file.js TAP snapshot > must match snapshot 1`] = ` -0 verbose logfile logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-log-file-snapshot/{DATE}- +0 verbose logfile logs-max:10 dir:{CWD}/{DATE}- 1 silly logfile done cleaning log files 2 error no prefix 3 error prefix with prefix diff --git a/deps/npm/tap-snapshots/test/lib/utils/reify-output.js.test.cjs b/deps/npm/tap-snapshots/test/lib/utils/reify-output.js.test.cjs index 755b2364253047..3fb3fa2611c231 100644 --- a/deps/npm/tap-snapshots/test/lib/utils/reify-output.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/utils/reify-output.js.test.cjs @@ -15,12 +15,12 @@ exports[`test/lib/utils/reify-output.js TAP added packages should be looked up w up to date in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":0,"audited":0,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":0,"audited":0,"json":false} 1`] = ` up to date in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":0,"audited":0,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":0,"audited":0,"json":true} 1`] = ` { "added": 0, "removed": 0, @@ -30,14 +30,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":0,"audited":1,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":0,"audited":1,"json":false} 1`] = ` up to date, audited 1 package in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":0,"audited":1,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":0,"audited":1,"json":true} 1`] = ` { "added": 0, "removed": 0, @@ -52,21 +52,21 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":0,"audited":2,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":0,"audited":2,"json":false} 1`] = ` up to date, audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":0,"audited":2,"json":false} 2`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":0,"audited":2,"json":false} 2`] = ` up to date, audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":0,"audited":2,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":0,"audited":2,"json":true} 1`] = ` { "added": 0, "removed": 0, @@ -81,7 +81,7 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":0,"audited":2,"json":true} 2`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":0,"audited":2,"json":true} 2`] = ` { "added": 0, "removed": 0, @@ -99,12 +99,12 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":1,"audited":0,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":1,"audited":0,"json":false} 1`] = ` changed 1 package in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":1,"audited":0,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":1,"audited":0,"json":true} 1`] = ` { "added": 0, "removed": 0, @@ -114,14 +114,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":1,"audited":1,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":1,"audited":1,"json":false} 1`] = ` changed 1 package, and audited 1 package in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":1,"audited":1,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":1,"audited":1,"json":true} 1`] = ` { "added": 0, "removed": 0, @@ -136,14 +136,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":1,"audited":2,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":1,"audited":2,"json":false} 1`] = ` changed 1 package, and audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":1,"audited":2,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":1,"audited":2,"json":true} 1`] = ` { "added": 0, "removed": 0, @@ -158,12 +158,12 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":2,"audited":0,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":2,"audited":0,"json":false} 1`] = ` changed 2 packages in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":2,"audited":0,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":2,"audited":0,"json":true} 1`] = ` { "added": 0, "removed": 0, @@ -173,14 +173,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":2,"audited":1,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":2,"audited":1,"json":false} 1`] = ` changed 2 packages, and audited 1 package in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":2,"audited":1,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":2,"audited":1,"json":true} 1`] = ` { "added": 0, "removed": 0, @@ -195,14 +195,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":2,"audited":2,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":2,"audited":2,"json":false} 1`] = ` changed 2 packages, and audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":2,"audited":2,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":0,"changed":2,"audited":2,"json":true} 1`] = ` { "added": 0, "removed": 0, @@ -217,12 +217,12 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":0,"audited":0,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":0,"audited":0,"json":false} 1`] = ` removed 1 package in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":0,"audited":0,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":0,"audited":0,"json":true} 1`] = ` { "added": 0, "removed": 1, @@ -232,14 +232,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":0,"audited":1,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":0,"audited":1,"json":false} 1`] = ` removed 1 package, and audited 1 package in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":0,"audited":1,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":0,"audited":1,"json":true} 1`] = ` { "added": 0, "removed": 1, @@ -254,14 +254,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":0,"audited":2,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":0,"audited":2,"json":false} 1`] = ` removed 1 package, and audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":0,"audited":2,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":0,"audited":2,"json":true} 1`] = ` { "added": 0, "removed": 1, @@ -276,12 +276,12 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":1,"audited":0,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":1,"audited":0,"json":false} 1`] = ` removed 1 package, and changed 1 package in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":1,"audited":0,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":1,"audited":0,"json":true} 1`] = ` { "added": 0, "removed": 1, @@ -291,14 +291,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":1,"audited":1,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":1,"audited":1,"json":false} 1`] = ` removed 1 package, changed 1 package, and audited 1 package in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":1,"audited":1,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":1,"audited":1,"json":true} 1`] = ` { "added": 0, "removed": 1, @@ -313,14 +313,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":1,"audited":2,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":1,"audited":2,"json":false} 1`] = ` removed 1 package, changed 1 package, and audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":1,"audited":2,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":1,"audited":2,"json":true} 1`] = ` { "added": 0, "removed": 1, @@ -335,12 +335,12 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":2,"audited":0,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":2,"audited":0,"json":false} 1`] = ` removed 1 package, and changed 2 packages in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":2,"audited":0,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":2,"audited":0,"json":true} 1`] = ` { "added": 0, "removed": 1, @@ -350,14 +350,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":2,"audited":1,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":2,"audited":1,"json":false} 1`] = ` removed 1 package, changed 2 packages, and audited 1 package in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":2,"audited":1,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":2,"audited":1,"json":true} 1`] = ` { "added": 0, "removed": 1, @@ -372,14 +372,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":2,"audited":2,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":2,"audited":2,"json":false} 1`] = ` removed 1 package, changed 2 packages, and audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":2,"audited":2,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":1,"changed":2,"audited":2,"json":true} 1`] = ` { "added": 0, "removed": 1, @@ -394,12 +394,12 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":0,"audited":0,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":0,"audited":0,"json":false} 1`] = ` removed 2 packages in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":0,"audited":0,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":0,"audited":0,"json":true} 1`] = ` { "added": 0, "removed": 2, @@ -409,14 +409,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":0,"audited":1,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":0,"audited":1,"json":false} 1`] = ` removed 2 packages, and audited 1 package in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":0,"audited":1,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":0,"audited":1,"json":true} 1`] = ` { "added": 0, "removed": 2, @@ -431,14 +431,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":0,"audited":2,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":0,"audited":2,"json":false} 1`] = ` removed 2 packages, and audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":0,"audited":2,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":0,"audited":2,"json":true} 1`] = ` { "added": 0, "removed": 2, @@ -453,12 +453,12 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":1,"audited":0,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":1,"audited":0,"json":false} 1`] = ` removed 2 packages, and changed 1 package in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":1,"audited":0,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":1,"audited":0,"json":true} 1`] = ` { "added": 0, "removed": 2, @@ -468,14 +468,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":1,"audited":1,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":1,"audited":1,"json":false} 1`] = ` removed 2 packages, changed 1 package, and audited 1 package in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":1,"audited":1,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":1,"audited":1,"json":true} 1`] = ` { "added": 0, "removed": 2, @@ -490,14 +490,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":1,"audited":2,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":1,"audited":2,"json":false} 1`] = ` removed 2 packages, changed 1 package, and audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":1,"audited":2,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":1,"audited":2,"json":true} 1`] = ` { "added": 0, "removed": 2, @@ -512,12 +512,12 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":2,"audited":0,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":2,"audited":0,"json":false} 1`] = ` removed 2 packages, and changed 2 packages in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":2,"audited":0,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":2,"audited":0,"json":true} 1`] = ` { "added": 0, "removed": 2, @@ -527,14 +527,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":2,"audited":1,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":2,"audited":1,"json":false} 1`] = ` removed 2 packages, changed 2 packages, and audited 1 package in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":2,"audited":1,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":2,"audited":1,"json":true} 1`] = ` { "added": 0, "removed": 2, @@ -549,14 +549,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":2,"audited":2,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":2,"audited":2,"json":false} 1`] = ` removed 2 packages, changed 2 packages, and audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":2,"audited":2,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":0,"removed":2,"changed":2,"audited":2,"json":true} 1`] = ` { "added": 0, "removed": 2, @@ -571,12 +571,12 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":0,"audited":0,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":0,"audited":0,"json":false} 1`] = ` added 1 package in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":0,"audited":0,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":0,"audited":0,"json":true} 1`] = ` { "added": 1, "removed": 0, @@ -586,14 +586,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":0,"audited":1,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":0,"audited":1,"json":false} 1`] = ` added 1 package, and audited 1 package in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":0,"audited":1,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":0,"audited":1,"json":true} 1`] = ` { "added": 1, "removed": 0, @@ -608,14 +608,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":0,"audited":2,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":0,"audited":2,"json":false} 1`] = ` added 1 package, and audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":0,"audited":2,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":0,"audited":2,"json":true} 1`] = ` { "added": 1, "removed": 0, @@ -630,12 +630,12 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":1,"audited":0,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":1,"audited":0,"json":false} 1`] = ` added 1 package, and changed 1 package in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":1,"audited":0,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":1,"audited":0,"json":true} 1`] = ` { "added": 1, "removed": 0, @@ -645,14 +645,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":1,"audited":1,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":1,"audited":1,"json":false} 1`] = ` added 1 package, changed 1 package, and audited 1 package in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":1,"audited":1,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":1,"audited":1,"json":true} 1`] = ` { "added": 1, "removed": 0, @@ -667,14 +667,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":1,"audited":2,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":1,"audited":2,"json":false} 1`] = ` added 1 package, changed 1 package, and audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":1,"audited":2,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":1,"audited":2,"json":true} 1`] = ` { "added": 1, "removed": 0, @@ -689,12 +689,12 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":2,"audited":0,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":2,"audited":0,"json":false} 1`] = ` added 1 package, and changed 2 packages in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":2,"audited":0,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":2,"audited":0,"json":true} 1`] = ` { "added": 1, "removed": 0, @@ -704,14 +704,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":2,"audited":1,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":2,"audited":1,"json":false} 1`] = ` added 1 package, changed 2 packages, and audited 1 package in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":2,"audited":1,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":2,"audited":1,"json":true} 1`] = ` { "added": 1, "removed": 0, @@ -726,14 +726,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":2,"audited":2,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":2,"audited":2,"json":false} 1`] = ` added 1 package, changed 2 packages, and audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":2,"audited":2,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":0,"changed":2,"audited":2,"json":true} 1`] = ` { "added": 1, "removed": 0, @@ -748,12 +748,12 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":0,"audited":0,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":0,"audited":0,"json":false} 1`] = ` added 1 package, and removed 1 package in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":0,"audited":0,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":0,"audited":0,"json":true} 1`] = ` { "added": 1, "removed": 1, @@ -763,14 +763,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":0,"audited":1,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":0,"audited":1,"json":false} 1`] = ` added 1 package, removed 1 package, and audited 1 package in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":0,"audited":1,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":0,"audited":1,"json":true} 1`] = ` { "added": 1, "removed": 1, @@ -785,14 +785,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":0,"audited":2,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":0,"audited":2,"json":false} 1`] = ` added 1 package, removed 1 package, and audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":0,"audited":2,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":0,"audited":2,"json":true} 1`] = ` { "added": 1, "removed": 1, @@ -807,12 +807,12 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":1,"audited":0,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":1,"audited":0,"json":false} 1`] = ` added 1 package, removed 1 package, and changed 1 package in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":1,"audited":0,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":1,"audited":0,"json":true} 1`] = ` { "added": 1, "removed": 1, @@ -822,14 +822,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":1,"audited":1,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":1,"audited":1,"json":false} 1`] = ` added 1 package, removed 1 package, changed 1 package, and audited 1 package in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":1,"audited":1,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":1,"audited":1,"json":true} 1`] = ` { "added": 1, "removed": 1, @@ -844,14 +844,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":1,"audited":2,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":1,"audited":2,"json":false} 1`] = ` added 1 package, removed 1 package, changed 1 package, and audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":1,"audited":2,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":1,"audited":2,"json":true} 1`] = ` { "added": 1, "removed": 1, @@ -866,12 +866,12 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":2,"audited":0,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":2,"audited":0,"json":false} 1`] = ` added 1 package, removed 1 package, and changed 2 packages in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":2,"audited":0,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":2,"audited":0,"json":true} 1`] = ` { "added": 1, "removed": 1, @@ -881,14 +881,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":2,"audited":1,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":2,"audited":1,"json":false} 1`] = ` added 1 package, removed 1 package, changed 2 packages, and audited 1 package in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":2,"audited":1,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":2,"audited":1,"json":true} 1`] = ` { "added": 1, "removed": 1, @@ -903,14 +903,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":2,"audited":2,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":2,"audited":2,"json":false} 1`] = ` added 1 package, removed 1 package, changed 2 packages, and audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":2,"audited":2,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":1,"changed":2,"audited":2,"json":true} 1`] = ` { "added": 1, "removed": 1, @@ -925,12 +925,12 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":0,"audited":0,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":0,"audited":0,"json":false} 1`] = ` added 1 package, and removed 2 packages in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":0,"audited":0,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":0,"audited":0,"json":true} 1`] = ` { "added": 1, "removed": 2, @@ -940,14 +940,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":0,"audited":1,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":0,"audited":1,"json":false} 1`] = ` added 1 package, removed 2 packages, and audited 1 package in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":0,"audited":1,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":0,"audited":1,"json":true} 1`] = ` { "added": 1, "removed": 2, @@ -962,14 +962,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":0,"audited":2,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":0,"audited":2,"json":false} 1`] = ` added 1 package, removed 2 packages, and audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":0,"audited":2,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":0,"audited":2,"json":true} 1`] = ` { "added": 1, "removed": 2, @@ -984,12 +984,12 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":1,"audited":0,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":1,"audited":0,"json":false} 1`] = ` added 1 package, removed 2 packages, and changed 1 package in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":1,"audited":0,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":1,"audited":0,"json":true} 1`] = ` { "added": 1, "removed": 2, @@ -999,14 +999,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":1,"audited":1,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":1,"audited":1,"json":false} 1`] = ` added 1 package, removed 2 packages, changed 1 package, and audited 1 package in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":1,"audited":1,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":1,"audited":1,"json":true} 1`] = ` { "added": 1, "removed": 2, @@ -1021,14 +1021,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":1,"audited":2,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":1,"audited":2,"json":false} 1`] = ` added 1 package, removed 2 packages, changed 1 package, and audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":1,"audited":2,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":1,"audited":2,"json":true} 1`] = ` { "added": 1, "removed": 2, @@ -1043,12 +1043,12 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":2,"audited":0,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":2,"audited":0,"json":false} 1`] = ` added 1 package, removed 2 packages, and changed 2 packages in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":2,"audited":0,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":2,"audited":0,"json":true} 1`] = ` { "added": 1, "removed": 2, @@ -1058,14 +1058,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":2,"audited":1,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":2,"audited":1,"json":false} 1`] = ` added 1 package, removed 2 packages, changed 2 packages, and audited 1 package in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":2,"audited":1,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":2,"audited":1,"json":true} 1`] = ` { "added": 1, "removed": 2, @@ -1080,14 +1080,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":2,"audited":2,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":2,"audited":2,"json":false} 1`] = ` added 1 package, removed 2 packages, changed 2 packages, and audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":2,"audited":2,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":1,"removed":2,"changed":2,"audited":2,"json":true} 1`] = ` { "added": 1, "removed": 2, @@ -1102,12 +1102,12 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":0,"audited":0,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":0,"audited":0,"json":false} 1`] = ` added 2 packages in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":0,"audited":0,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":0,"audited":0,"json":true} 1`] = ` { "added": 2, "removed": 0, @@ -1117,14 +1117,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":0,"audited":1,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":0,"audited":1,"json":false} 1`] = ` added 2 packages, and audited 1 package in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":0,"audited":1,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":0,"audited":1,"json":true} 1`] = ` { "added": 2, "removed": 0, @@ -1139,14 +1139,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":0,"audited":2,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":0,"audited":2,"json":false} 1`] = ` added 2 packages, and audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":0,"audited":2,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":0,"audited":2,"json":true} 1`] = ` { "added": 2, "removed": 0, @@ -1161,12 +1161,12 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":1,"audited":0,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":1,"audited":0,"json":false} 1`] = ` added 2 packages, and changed 1 package in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":1,"audited":0,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":1,"audited":0,"json":true} 1`] = ` { "added": 2, "removed": 0, @@ -1176,14 +1176,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":1,"audited":1,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":1,"audited":1,"json":false} 1`] = ` added 2 packages, changed 1 package, and audited 1 package in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":1,"audited":1,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":1,"audited":1,"json":true} 1`] = ` { "added": 2, "removed": 0, @@ -1198,14 +1198,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":1,"audited":2,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":1,"audited":2,"json":false} 1`] = ` added 2 packages, changed 1 package, and audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":1,"audited":2,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":1,"audited":2,"json":true} 1`] = ` { "added": 2, "removed": 0, @@ -1220,12 +1220,12 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":2,"audited":0,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":2,"audited":0,"json":false} 1`] = ` added 2 packages, and changed 2 packages in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":2,"audited":0,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":2,"audited":0,"json":true} 1`] = ` { "added": 2, "removed": 0, @@ -1235,14 +1235,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":2,"audited":1,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":2,"audited":1,"json":false} 1`] = ` added 2 packages, changed 2 packages, and audited 1 package in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":2,"audited":1,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":2,"audited":1,"json":true} 1`] = ` { "added": 2, "removed": 0, @@ -1257,14 +1257,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":2,"audited":2,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":2,"audited":2,"json":false} 1`] = ` added 2 packages, changed 2 packages, and audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":2,"audited":2,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":0,"changed":2,"audited":2,"json":true} 1`] = ` { "added": 2, "removed": 0, @@ -1279,12 +1279,12 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":0,"audited":0,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":0,"audited":0,"json":false} 1`] = ` added 2 packages, and removed 1 package in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":0,"audited":0,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":0,"audited":0,"json":true} 1`] = ` { "added": 2, "removed": 1, @@ -1294,14 +1294,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":0,"audited":1,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":0,"audited":1,"json":false} 1`] = ` added 2 packages, removed 1 package, and audited 1 package in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":0,"audited":1,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":0,"audited":1,"json":true} 1`] = ` { "added": 2, "removed": 1, @@ -1316,14 +1316,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":0,"audited":2,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":0,"audited":2,"json":false} 1`] = ` added 2 packages, removed 1 package, and audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":0,"audited":2,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":0,"audited":2,"json":true} 1`] = ` { "added": 2, "removed": 1, @@ -1338,12 +1338,12 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":1,"audited":0,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":1,"audited":0,"json":false} 1`] = ` added 2 packages, removed 1 package, and changed 1 package in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":1,"audited":0,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":1,"audited":0,"json":true} 1`] = ` { "added": 2, "removed": 1, @@ -1353,14 +1353,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":1,"audited":1,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":1,"audited":1,"json":false} 1`] = ` added 2 packages, removed 1 package, changed 1 package, and audited 1 package in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":1,"audited":1,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":1,"audited":1,"json":true} 1`] = ` { "added": 2, "removed": 1, @@ -1375,14 +1375,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":1,"audited":2,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":1,"audited":2,"json":false} 1`] = ` added 2 packages, removed 1 package, changed 1 package, and audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":1,"audited":2,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":1,"audited":2,"json":true} 1`] = ` { "added": 2, "removed": 1, @@ -1397,12 +1397,12 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":2,"audited":0,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":2,"audited":0,"json":false} 1`] = ` added 2 packages, removed 1 package, and changed 2 packages in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":2,"audited":0,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":2,"audited":0,"json":true} 1`] = ` { "added": 2, "removed": 1, @@ -1412,14 +1412,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":2,"audited":1,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":2,"audited":1,"json":false} 1`] = ` added 2 packages, removed 1 package, changed 2 packages, and audited 1 package in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":2,"audited":1,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":2,"audited":1,"json":true} 1`] = ` { "added": 2, "removed": 1, @@ -1434,14 +1434,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":2,"audited":2,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":2,"audited":2,"json":false} 1`] = ` added 2 packages, removed 1 package, changed 2 packages, and audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":2,"audited":2,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":1,"changed":2,"audited":2,"json":true} 1`] = ` { "added": 2, "removed": 1, @@ -1456,12 +1456,12 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":0,"audited":0,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":0,"audited":0,"json":false} 1`] = ` added 2 packages, and removed 2 packages in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":0,"audited":0,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":0,"audited":0,"json":true} 1`] = ` { "added": 2, "removed": 2, @@ -1471,14 +1471,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":0,"audited":1,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":0,"audited":1,"json":false} 1`] = ` added 2 packages, removed 2 packages, and audited 1 package in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":0,"audited":1,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":0,"audited":1,"json":true} 1`] = ` { "added": 2, "removed": 2, @@ -1493,14 +1493,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":0,"audited":2,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":0,"audited":2,"json":false} 1`] = ` added 2 packages, removed 2 packages, and audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":0,"audited":2,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":0,"audited":2,"json":true} 1`] = ` { "added": 2, "removed": 2, @@ -1515,12 +1515,12 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":1,"audited":0,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":1,"audited":0,"json":false} 1`] = ` added 2 packages, removed 2 packages, and changed 1 package in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":1,"audited":0,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":1,"audited":0,"json":true} 1`] = ` { "added": 2, "removed": 2, @@ -1530,14 +1530,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":1,"audited":1,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":1,"audited":1,"json":false} 1`] = ` added 2 packages, removed 2 packages, changed 1 package, and audited 1 package in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":1,"audited":1,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":1,"audited":1,"json":true} 1`] = ` { "added": 2, "removed": 2, @@ -1552,14 +1552,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":1,"audited":2,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":1,"audited":2,"json":false} 1`] = ` added 2 packages, removed 2 packages, changed 1 package, and audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":1,"audited":2,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":1,"audited":2,"json":true} 1`] = ` { "added": 2, "removed": 2, @@ -1574,12 +1574,12 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":2,"audited":0,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":2,"audited":0,"json":false} 1`] = ` added 2 packages, removed 2 packages, and changed 2 packages in {TIME} ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":2,"audited":0,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":2,"audited":0,"json":true} 1`] = ` { "added": 2, "removed": 2, @@ -1589,14 +1589,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":2,"audited":1,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":2,"audited":1,"json":false} 1`] = ` added 2 packages, removed 2 packages, changed 2 packages, and audited 1 package in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":2,"audited":1,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":2,"audited":1,"json":true} 1`] = ` { "added": 2, "removed": 2, @@ -1611,14 +1611,14 @@ exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added": } ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":2,"audited":2,"json":false} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":2,"audited":2,"json":false} 1`] = ` added 2 packages, removed 2 packages, changed 2 packages, and audited 2 packages in {TIME} -found 0 vulnerabilities +found 0 vulnerabilities ` -exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":2,"audited":2,"json":true} 1`] = ` +exports[`test/lib/utils/reify-output.js TAP packages changed message > {"added":2,"removed":2,"changed":2,"audited":2,"json":true} 1`] = ` { "added": 2, "removed": 2, diff --git a/deps/npm/test/bin/npm-cli.js b/deps/npm/test/bin/npm-cli.js index 7b4b619e2b7712..134208c8160c1e 100644 --- a/deps/npm/test/bin/npm-cli.js +++ b/deps/npm/test/bin/npm-cli.js @@ -1,7 +1,9 @@ const t = require('tap') +const tmock = require('../fixtures/tmock') + t.test('loading the bin calls the implementation', t => { - t.mock('../../bin/npm-cli.js', { - '../../lib/cli.js': proc => { + tmock(t, '{BIN}/npm-cli.js', { + '{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 b526f2dfbe32eb..5670f24f07b77a 100644 --- a/deps/npm/test/bin/npx-cli.js +++ b/deps/npm/test/bin/npx-cli.js @@ -1,45 +1,46 @@ const t = require('tap') -const npx = require.resolve('../../bin/npx-cli.js') -const cli = require.resolve('../../lib/cli.js') -const npm = require.resolve('../../bin/npm-cli.js') +const mockGlobals = require('../fixtures/mock-globals') +const tmock = require('../fixtures/tmock') -const logs = [] -console.error = (...msg) => logs.push(msg) +const npm = require.resolve('../../bin/npm-cli.js') +const npx = require.resolve('../../bin/npx-cli.js') -t.afterEach(() => (logs.length = 0)) +const mockNpx = (t, argv) => { + const logs = [] + mockGlobals(t, { + 'process.argv': argv, + 'console.error': (...msg) => logs.push(msg), + }) + tmock(t, '{BIN}/npx-cli.js', { '{LIB}/cli.js': () => {} }) + return { + logs, + argv: process.argv, + } +} -t.test('npx foo -> npm exec -- foo', t => { - process.argv = ['node', npx, 'foo'] - t.mock(npx, { [cli]: () => {} }) - t.strictSame(process.argv, ['node', npm, 'exec', '--', 'foo']) - t.end() +t.test('npx foo -> npm exec -- foo', async t => { + const { argv } = mockNpx(t, ['node', npx, 'foo']) + t.strictSame(argv, ['node', npm, 'exec', '--', 'foo']) }) -t.test('npx -- foo -> npm exec -- foo', t => { - process.argv = ['node', npx, '--', 'foo'] - t.mock(npx, { [cli]: () => {} }) - t.strictSame(process.argv, ['node', npm, 'exec', '--', 'foo']) - t.end() +t.test('npx -- foo -> npm exec -- foo', async t => { + const { argv } = mockNpx(t, ['node', npx, '--', 'foo']) + t.strictSame(argv, ['node', npm, 'exec', '--', 'foo']) }) -t.test('npx -x y foo -z -> npm exec -x y -- foo -z', t => { - process.argv = ['node', npx, '-x', 'y', 'foo', '-z'] - t.mock(npx, { [cli]: () => {} }) - t.strictSame(process.argv, ['node', npm, 'exec', '-x', 'y', '--', 'foo', '-z']) - t.end() +t.test('npx -x y foo -z -> npm exec -x y -- foo -z', async t => { + const { argv } = mockNpx(t, ['node', npx, '-x', 'y', 'foo', '-z']) + t.strictSame(argv, ['node', npm, 'exec', '-x', 'y', '--', 'foo', '-z']) }) -t.test('npx --x=y --no-install foo -z -> npm exec --x=y -- foo -z', t => { - process.argv = ['node', npx, '--x=y', '--no-install', 'foo', '-z'] - t.mock(npx, { [cli]: () => {} }) - t.strictSame(process.argv, ['node', npm, 'exec', '--x=y', '--yes=false', '--', 'foo', '-z']) - t.end() +t.test('npx --x=y --no-install foo -z -> npm exec --x=y -- foo -z', async t => { + const { argv } = mockNpx(t, ['node', npx, '--x=y', '--no-install', 'foo', '-z']) + t.strictSame(argv, ['node', npm, 'exec', '--x=y', '--yes=false', '--', 'foo', '-z']) }) -t.test('transform renamed options into proper values', t => { - process.argv = ['node', npx, '-y', '--shell=bash', '-p', 'foo', '-c', 'asdf'] - t.mock(npx, { [cli]: () => {} }) - t.strictSame(process.argv, [ +t.test('transform renamed options into proper values', async t => { + const { argv } = mockNpx(t, ['node', npx, '-y', '--shell=bash', '-p', 'foo', '-c', 'asdf']) + t.strictSame(argv, [ 'node', npm, 'exec', @@ -50,12 +51,11 @@ t.test('transform renamed options into proper values', t => { '--call', 'asdf', ]) - t.end() }) // warn if deprecated switches/options are used -t.test('use a bunch of deprecated switches and options', t => { - process.argv = [ +t.test('use a bunch of deprecated switches and options', async t => { + const { argv, logs } = mockNpx(t, [ 'node', npx, '--npm', @@ -71,7 +71,7 @@ t.test('use a bunch of deprecated switches and options', t => { '--ignore-existing', '-q', 'foobar', - ] + ]) const expect = [ 'node', @@ -86,8 +86,7 @@ t.test('use a bunch of deprecated switches and options', t => { '--', 'foobar', ] - t.mock(npx, { [cli]: () => {} }) - t.strictSame(process.argv, expect) + t.strictSame(argv, expect) t.strictSame(logs, [ ['npx: the --npm argument has been removed.'], ['npx: the --node-arg argument has been removed.'], @@ -97,5 +96,4 @@ t.test('use a bunch of deprecated switches and options', t => { ['npx: the --ignore-existing argument has been removed.'], ['See `npm help exec` for more information'], ]) - t.end() }) diff --git a/deps/npm/test/fixtures/clean-snapshot.js b/deps/npm/test/fixtures/clean-snapshot.js index b0ea28cee4d814..83ddc00f4b7877 100644 --- a/deps/npm/test/fixtures/clean-snapshot.js +++ b/deps/npm/test/fixtures/clean-snapshot.js @@ -1,19 +1,43 @@ +const { relative, dirname } = require('path') + +// normalize line endings (for ini) +const cleanNewlines = (s) => s.replace(/\r\n/g, '\n') + // XXX: this also cleans quoted " in json snapshots // ideally this could be avoided but its easier to just // run this command inside cleanSnapshot -const normalizePath = (str) => str - .replace(/\r\n/g, '\n') // normalize line endings (for ini) +const normalizePath = (str) => cleanNewlines(str) .replace(/[A-z]:\\/g, '\\') // turn windows roots to posix ones .replace(/\\+/g, '/') // replace \ with / +const pathRegex = (p) => new RegExp(normalizePath(p), 'gi') + +// create a cwd replacer in the module scope, since some tests +// overwrite process.cwd() +const CWD = pathRegex(process.cwd()) +const TESTDIR = pathRegex(relative(process.cwd(), dirname(require.main.filename))) + const cleanCwd = (path) => normalizePath(path) - .replace(new RegExp(normalizePath(process.cwd()), 'g'), '{CWD}') + // repalce CWD, TESTDIR, and TAPDIR separately + .replace(CWD, '{CWD}') + .replace(TESTDIR, '{TESTDIR}') + .replace(/tap-testdir-[\w-.]+/gi, '{TAPDIR}') + // if everything ended up in line, reduce it all to CWD + .replace(/\{CWD\}\/\{TESTDIR\}\/\{TAPDIR\}/g, '{CWD}') + // replace for platform differences in global nodemodules + .replace(/lib\/node_modules/g, 'node_modules') + .replace(/global\/lib/g, 'global') const cleanDate = (str) => str.replace(/\d{4}-\d{2}-\d{2}T\d{2}[_:]\d{2}[_:]\d{2}[_:.]\d{3}Z/g, '{DATE}') +const cleanTime = str => str.replace(/in [0-9]+m?s\s*$/gm, 'in {TIME}') + module.exports = { normalizePath, + pathRegex, cleanCwd, cleanDate, + cleanTime, + cleanNewlines, } diff --git a/deps/npm/test/fixtures/merge-conflict.json b/deps/npm/test/fixtures/merge-conflict.json new file mode 100644 index 00000000000000..2591c62efb37a0 --- /dev/null +++ b/deps/npm/test/fixtures/merge-conflict.json @@ -0,0 +1,36 @@ +{ + "array": [ +<<<<<<< HEAD + 100, + { + "foo": "baz" + }, +||||||| merged common ancestors + 1, +======= + 111, + 1, + 2, + 3, + { + "foo": "bar" + }, +>>>>>>> a + 1 + ], + "a": { + "b": { +<<<<<<< HEAD + "c": { + "x": "bbbb" + } +||||||| merged common ancestors + "c": { + "x": "aaaa" + } +======= + "c": "xxxx" +>>>>>>> a + } + } +} diff --git a/deps/npm/test/fixtures/mock-globals.js b/deps/npm/test/fixtures/mock-globals.js index 29da2a48b092d2..aec8a83963687a 100644 --- a/deps/npm/test/fixtures/mock-globals.js +++ b/deps/npm/test/fixtures/mock-globals.js @@ -4,23 +4,49 @@ // Hopefully it can be removed for a feature in tap in the future const sep = '.' +const escapeSep = '"' const has = (o, k) => Object.prototype.hasOwnProperty.call(o, k) const opd = (o, k) => Object.getOwnPropertyDescriptor(o, k) const po = (o) => Object.getPrototypeOf(o) const pojo = (o) => Object.prototype.toString.call(o) === '[object Object]' const last = (arr) => arr[arr.length - 1] -const splitLast = (str) => str.split(new RegExp(`\\${sep}(?=[^${sep}]+$)`)) const dupes = (arr) => arr.filter((k, i) => arr.indexOf(k) !== i) const dupesStartsWith = (arr) => arr.filter((k1) => arr.some((k2) => k2.startsWith(k1 + sep))) +const splitLastSep = (str) => { + let escaped = false + for (let i = str.length - 1; i >= 0; i--) { + const c = str[i] + const cp = str[i + 1] + const cn = str[i - 1] + if (!escaped && c === escapeSep && (cp == null || cp === sep)) { + escaped = true + continue + } + if (escaped && c === escapeSep && cn === sep) { + escaped = false + continue + } + if (!escaped && c === sep) { + return [ + str.slice(0, i), + str.slice(i + 1).replace(new RegExp(`^${escapeSep}(.*)${escapeSep}$`), '$1'), + ] + } + } + return [str] +} + // A weird getter that can look up keys on nested objects but also // match keys with dots in their names, eg { 'process.env': { TERM: 'a' } } // can be looked up with the key 'process.env.TERM' const get = (obj, key, childKey = '') => { if (has(obj, key)) { return childKey ? get(obj[key], childKey) : obj[key] - } else if (key.includes(sep)) { - const [parentKey, prefix] = splitLast(key) + } + const split = splitLastSep(key) + if (split.length === 2) { + const [parentKey, prefix] = split return get( obj, parentKey, @@ -81,7 +107,7 @@ class DescriptorStack { #isDelete = (o) => o && o.DELETE === true constructor (key) { - const keys = splitLast(key) + const keys = splitLastSep(key) this.#global = keys.length === 1 ? global : get(global, keys[0]) this.#valueKey = specialCaseKeys(key) || last(keys) // If the global object doesnt return a descriptor for the key diff --git a/deps/npm/test/fixtures/mock-npm.js b/deps/npm/test/fixtures/mock-npm.js index 8a744cd559eaf0..2cada1354878c0 100644 --- a/deps/npm/test/fixtures/mock-npm.js +++ b/deps/npm/test/fixtures/mock-npm.js @@ -1,26 +1,81 @@ const os = require('os') const fs = require('fs').promises const path = require('path') +const tap = require('tap') +const errorMessage = require('../../lib/utils/error-message') const mockLogs = require('./mock-logs') const mockGlobals = require('./mock-globals') -const log = require('../../lib/utils/log-shim') -const envConfigKeys = Object.keys(require('../../lib/utils/config/definitions.js')) +const tmock = require('./tmock') +const defExitCode = process.exitCode + +const changeDir = (dir) => { + if (dir) { + const cwd = process.cwd() + process.chdir(dir) + return () => process.chdir(cwd) + } + return () => {} +} + +const setGlobalNodeModules = (globalDir) => { + const updateSymlinks = (obj, visit) => { + for (const [key, value] of Object.entries(obj)) { + if (/Fixture/.test(value.toString())) { + obj[key] = tap.fixture('symlink', path.join('..', value.content)) + } else if (typeof value === 'object') { + obj[key] = updateSymlinks(value, visit) + } + } + return obj + } + + if (globalDir.lib) { + throw new Error('`globalPrefixDir` should not have a top-level `lib/` directory, only a ' + + 'top-level `node_modules/` dir that gets set in the correct location based on platform. ' + + `Received the following top level entries: ${Object.keys(globalDir).join(', ')}.` + ) + } + + if (process.platform !== 'win32' && globalDir.node_modules) { + const { node_modules: nm, ...rest } = globalDir + return { + ...rest, + lib: { node_modules: updateSymlinks(nm) }, + } + } -const RealMockNpm = (t, otherMocks = {}) => { + return globalDir +} + +const getMockNpm = async (t, { mocks, init, load, npm: npmOpts }) => { const mock = { - ...mockLogs(otherMocks), + ...mockLogs(mocks), outputs: [], outputErrors: [], joinedOutput: () => mock.outputs.map(o => o.join(' ')).join('\n'), } - const Npm = t.mock('../../lib/npm.js', { - '../../lib/utils/update-notifier.js': async () => {}, - ...otherMocks, + const Npm = tmock(t, '{LIB}/npm.js', { + '{LIB}/utils/update-notifier.js': async () => {}, + ...mocks, ...mock.logMocks, }) - mock.Npm = class MockNpm extends Npm { + class MockNpm extends Npm { + async exec (...args) { + const [res, err] = await super.exec(...args).then((r) => [r]).catch(e => [null, e]) + // This mimics how the exit handler flushes output for commands that have + // buffered output. It also uses the same json error processing from the + // error message fn. This is necessary for commands with buffered output + // to read the output after exec is called. This is not *exactly* how it + // works in practice, but it is close enough for now. + this.flushOutput(err ? errorMessage(err, this).json : null) + if (err) { + throw err + } + return res + } + // lib/npm.js tests needs this to actually test the function! originalOutput (...args) { super.output(...args) @@ -39,77 +94,88 @@ const RealMockNpm = (t, otherMocks = {}) => { } } - return mock -} - -const setLoglevel = (t, loglevel, reset = true) => { - if (t && reset) { - const _level = log.level - t.teardown(() => log.level = _level) + mock.Npm = MockNpm + if (init) { + mock.npm = new MockNpm(npmOpts) + if (load) { + await mock.npm.load() + } } - if (loglevel) { - // Set log level on the npmlog singleton and shared across everything - log.level = loglevel - } + return mock } -// Resolve some options to a function call with supplied args -const result = (fn, ...args) => typeof fn === 'function' ? fn(...args) : fn +const mockNpms = new Map() -const LoadMockNpm = async (t, { +const setupMockNpm = async (t, { init = true, load = init, + // preload a command + command = null, // string name of the command + exec = null, // optionally exec the command before returning + // test dirs prefixDir = {}, homeDir = {}, cacheDir = {}, - globalPrefixDir = { lib: {} }, - config = {}, - mocks = {}, + globalPrefixDir = { node_modules: {} }, otherDirs = {}, - globals = null, + chdir = ({ prefix }) => prefix, + // setup config, env vars, mocks, npm opts + config: _config = {}, + mocks = {}, + globals = {}, + npm: npmOpts = {}, + argv: rawArgv = [], } = {}) => { - // Mock some globals with their original values so they get torn down - // back to the original at the end of the test since they are manipulated - // by npm itself - const npmConfigEnv = {} - for (const key in process.env) { - if (key.startsWith('npm_config_')) { - npmConfigEnv[key] = undefined + // easy to accidentally forget to pass in tap + if (!(t instanceof tap.Test)) { + throw new Error('first argument must be a tap instance') + } + + // mockNpm is designed to only be run once per test chain so we assign it to + // the test in the cache and error if it is attempted to run again + let tapInstance = t + while (tapInstance) { + if (mockNpms.has(tapInstance)) { + throw new Error('mockNpm can only be called once in each t.test chain') } + tapInstance = tapInstance.parent } + mockNpms.set(t, true) + + if (!init && load) { + throw new Error('cant `load` without `init`') + } + + // These are globals manipulated by npm itself that we need to reset to their + // original values between tests + const npmEnvs = Object.keys(process.env).filter(k => k.startsWith('npm_')) mockGlobals(t, { process: { title: process.title, execPath: process.execPath, env: { - npm_command: process.env.npm_command, + NODE_ENV: process.env.NODE_ENV, COLOR: process.env.COLOR, - ...npmConfigEnv, + // further, these are npm controlled envs that we need to zero out before + // before the test. setting them to undefined ensures they are not set and + // also returned to their original value after the test + ...npmEnvs.reduce((acc, k) => { + acc[k] = undefined + return acc + }, {}), }, }, }) - const { Npm, ...rest } = RealMockNpm(t, mocks) - - // We want to fail fast when writing tests. Default this to 0 unless it was - // explicitly set in a test. - config = { 'fetch-retries': 0, ...config } - - if (!init && load) { - throw new Error('cant `load` without `init`') - } - - // Set log level as early as possible since - setLoglevel(t, config.loglevel) - const dir = t.testdir({ home: homeDir, prefix: prefixDir, cache: cacheDir, - global: globalPrefixDir, + global: setGlobalNodeModules(globalPrefixDir), other: otherDirs, }) + const dirs = { testdir: dir, prefix: path.join(dir, 'prefix'), @@ -119,52 +185,93 @@ const LoadMockNpm = async (t, { other: path.join(dir, 'other'), } - // Set cache to testdir via env var so it is available when load is run - // XXX: remove this for a solution where cache argv is passed in + // Option objects can also be functions that are called with all the dir paths + // so they can be used to set configs that need to be based on paths + const withDirs = (v) => typeof v === 'function' ? v(dirs) : v + + const teardownDir = changeDir(withDirs(chdir)) + + const defaultConfigs = { + // We want to fail fast when writing tests. Default this to 0 unless it was + // explicitly set in a test. + 'fetch-retries': 0, + cache: dirs.cache, + } + + const { argv, env, config } = Object.entries({ ...defaultConfigs, ...withDirs(_config) }) + .reduce((acc, [key, value]) => { + // nerfdart configs passed in need to be set via env var instead of argv + // and quoted with `"` so mock globals will ignore that it contains dots + if (key.startsWith('//')) { + acc.env[`process.env."npm_config_${key}"`] = value + } else { + const values = [].concat(value) + acc.argv.push(...values.flatMap(v => [`--${key}`, v.toString()])) + } + acc.config[key] = value + return acc + }, { argv: [...rawArgv], env: {}, config: {} }) + mockGlobals(t, { 'process.env.HOME': dirs.home, - 'process.env.npm_config_cache': dirs.cache, - ...(globals ? result(globals, { ...dirs }) : {}), - // Some configs don't work because they can't be set via npm.config.set until - // config is loaded. But some config items are needed before that. So this is - // an explicit set of configs that must be loaded as env vars. - // XXX(npm9): make this possible by passing in argv directly to npm/config - ...Object.entries(config) - .filter(([k]) => envConfigKeys.includes(k)) - .reduce((acc, [k, v]) => { - acc[`process.env.npm_config_${k.replace(/-/g, '_')}`] = - result(v, { ...dirs }).toString() - return acc - }, {}), + // global prefix cannot be (easily) set via argv so this is the easiest way + // to set it that also closely mimics the behavior a user would see since it + // will already be set while `npm.load()` is being run + // Note that this only sets the global prefix and the prefix is set via chdir + 'process.env.PREFIX': dirs.globalPrefix, + ...withDirs(globals), + ...env, }) - const npm = init ? new Npm() : null + const { npm, ...mockNpm } = await getMockNpm(t, { + init, + load, + mocks: withDirs(mocks), + npm: { argv, excludeNpmCwd: true, ...withDirs(npmOpts) }, + }) + + if (config.omit?.includes('prod')) { + // XXX(HACK): --omit=prod is not a valid config according to the definitions but + // it was being hacked in via flatOptions for older tests so this is to + // preserve that behavior and reduce churn in the snapshots. this should be + // removed or fixed in the future + npm.flatOptions.omit.push('prod') + } + t.teardown(() => { - npm && npm.unload() + if (npm) { + npm.unload() + } + // only set exitCode back if we're passing tests + if (t.passing()) { + process.exitCode = defExitCode + } + teardownDir() }) - if (load) { - await npm.load() - for (const [k, v] of Object.entries(result(config, { npm, ...dirs }))) { - if (typeof v === 'object' && v.value && v.where) { - npm.config.set(k, v.value, v.where) - } else { - npm.config.set(k, v) - } + const mockCommand = {} + if (command) { + const cmd = await npm.cmd(command) + const usage = await cmd.usage + mockCommand.cmd = cmd + mockCommand[command] = { + usage, + exec: (args) => npm.exec(command, args), + completion: (args) => cmd.completion(args), + } + if (exec) { + await mockCommand[command].exec(exec) + // assign string output to the command now that we have it + // for easier testing + mockCommand[command].output = mockNpm.joinedOutput() } - // Set global loglevel *again* since it possibly got reset during load - // XXX: remove with npmlog - setLoglevel(t, config.loglevel, false) - npm.prefix = dirs.prefix - npm.cache = dirs.cache - npm.globalPrefix = dirs.globalPrefix } return { - ...rest, - ...dirs, - Npm, npm, + ...mockNpm, + ...dirs, + ...mockCommand, debugFile: async () => { const readFiles = npm.logFiles.map(f => fs.readFile(f)) const logFiles = await Promise.all(readFiles) @@ -180,80 +287,6 @@ const LoadMockNpm = async (t, { } } -const realConfig = require('../../lib/utils/config') - -// Basic npm fixture that you can give a config object that acts like -// npm.config You still need a separate flatOptions. Tests should migrate to -// using the real npm mock above -class MockNpm { - constructor (base = {}, t) { - this._mockOutputs = [] - this.isMockNpm = true - this.base = base - - const config = base.config || {} - - for (const attr in base) { - if (attr !== 'config') { - this[attr] = base[attr] - } - } - - this.flatOptions = base.flatOptions || {} - this.config = { - // for now just set `find` to what config.find should return - // this works cause `find` is not an existing config entry - find: (k) => ({ ...realConfig.defaults, ...config })[k], - // for now isDefault is going to just return false if a value was defined - isDefault: (k) => !Object.prototype.hasOwnProperty.call(config, k), - get: (k) => ({ ...realConfig.defaults, ...config })[k], - set: (k, v) => { - config[k] = v - // mock how real npm derives silent - if (k === 'loglevel') { - this.flatOptions.silent = v === 'silent' - this.silent = v === 'silent' - } - }, - list: [{ ...realConfig.defaults, ...config }], - validate: () => {}, - } - - if (t && config.loglevel) { - setLoglevel(t, config.loglevel) - } - - if (config.loglevel) { - this.config.set('loglevel', config.loglevel) - } - } - - get global () { - return this.config.get('global') || this.config.get('location') === 'global' - } - - output (...msg) { - if (this.base.output) { - return this.base.output(msg) - } - this._mockOutputs.push(msg) - } - - // with the older fake mock npm there is no - // difference between output and outputBuffer - // since it just collects the output and never - // calls the exit handler, so we just mock the - // method the same as output. - outputBuffer (...msg) { - this.output(...msg) - } -} - -const FakeMockNpm = (base = {}, t) => { - return new MockNpm(base, t) -} - -module.exports = { - fake: FakeMockNpm, - load: LoadMockNpm, -} +module.exports = setupMockNpm +module.exports.load = setupMockNpm +module.exports.setGlobalNodeModules = setGlobalNodeModules diff --git a/deps/npm/test/fixtures/sandbox.js b/deps/npm/test/fixtures/sandbox.js index c7bb8218dc60a0..460609628c8abb 100644 --- a/deps/npm/test/fixtures/sandbox.js +++ b/deps/npm/test/fixtures/sandbox.js @@ -2,9 +2,7 @@ const { createHook, executionAsyncId } = require('async_hooks') const { EventEmitter } = require('events') const { homedir, tmpdir } = require('os') const { dirname, join } = require('path') -const { promisify } = require('util') -const { mkdir } = require('fs/promises') -const rimraf = promisify(require('rimraf')) +const { mkdir, rm } = require('fs/promises') const mockLogs = require('./mock-logs') const pkg = require('../../package.json') @@ -201,7 +199,7 @@ class Sandbox extends EventEmitter { if (this[_npm]) { this[_npm].unload() } - return rimraf(this[_dirs].temp).catch(() => null) + return rm(this[_dirs].temp, { recursive: true, force: true }).catch(() => null) } // proxy get handler diff --git a/deps/npm/test/fixtures/tmock.js b/deps/npm/test/fixtures/tmock.js new file mode 100644 index 00000000000000..321e8bc07c581c --- /dev/null +++ b/deps/npm/test/fixtures/tmock.js @@ -0,0 +1,27 @@ +const path = require('path') + +const ROOT = path.resolve(__dirname, '../..') +const BIN = path.join(ROOT, 'bin') +const LIB = path.join(ROOT, 'lib') + +// since mock npm changes directories it can be hard to figure out the +// correct path to mock something with tap since the directory will change +// before/after npm is loaded. This helper replaces {BIN} and {LIB} with +// the absolute path to those directories +const replace = (s) => { + if (/^[./{]/.test(s)) { + return s + .replace(/^\{BIN\}/, BIN) + .replace(/^\{LIB\}/, LIB) + .replace(/^\{ROOT\}/, ROOT) + } else { + return require.resolve(s) + } +} + +const tmock = (t, p, mocks = {}) => { + const entries = Object.entries(mocks).map(([k, v]) => [replace(k), v]) + return t.mock(replace(p), Object.fromEntries(entries)) +} + +module.exports = tmock diff --git a/deps/npm/test/index.js b/deps/npm/test/index.js index 747d75b5fd4c0b..44fb0989df4258 100644 --- a/deps/npm/test/index.js +++ b/deps/npm/test/index.js @@ -1,34 +1,20 @@ const t = require('tap') +const spawn = require('@npmcli/promise-spawn') const index = require.resolve('../index.js') const packageIndex = require.resolve('../') +const { load: loadMockNpm } = require('./fixtures/mock-npm') t.equal(index, packageIndex, 'index is main package require() export') t.throws(() => require(index), { message: 'The programmatic API was removed in npm v8.0.0', }) -t.test('loading as main module will load the cli', t => { - const cwd = t.testdir() - const { spawn } = require('child_process') +t.test('loading as main module will load the cli', async t => { + const { npm, cache } = await loadMockNpm(t) const LS = require('../lib/commands/ls.js') - const ls = new LS({ - config: { - validate: () => {}, - get: (key) => { - if (key === 'location') { - return 'project' - } - }, - isDefault: () => {}, - }, - }) - const p = spawn(process.execPath, [index, 'ls', '-h', '--cache', cwd]) - const out = [] - p.stdout.on('data', c => out.push(c)) - p.on('close', (code, signal) => { - t.equal(code, 0) - t.equal(signal, null) - t.match(Buffer.concat(out).toString(), ls.usage) - t.end() - }) + const ls = new LS(npm) + const p = await spawn(process.execPath, [index, 'ls', '-h', '--cache', cache]) + t.equal(p.code, 0) + t.equal(p.signal, null) + t.match(p.stdout, ls.usage) }) diff --git a/deps/npm/test/lib/arborist-cmd.js b/deps/npm/test/lib/arborist-cmd.js index f3c1d2573d33fd..36c697cd9e8fd8 100644 --- a/deps/npm/test/lib/arborist-cmd.js +++ b/deps/npm/test/lib/arborist-cmd.js @@ -1,115 +1,140 @@ const { resolve } = require('path') const t = require('tap') -const ArboristCmd = require('../../lib/arborist-cmd.js') +const { load: loadMockNpm } = require('../fixtures/mock-npm') +const tmock = require('../fixtures/tmock') -const configMock = { - validate: () => {}, - get: (key) => { - if (key === 'location') { - return 'project' - } - }, - isDefault: () => {}, -} +const mockArboristCmd = async (t, exec, workspace, { mocks = {}, ...opts } = {}) => { + const ArboristCmd = tmock(t, '{LIB}/arborist-cmd.js', mocks) -t.test('arborist-cmd', async t => { - const path = t.testdir({ - 'package.json': JSON.stringify({ - name: 'simple-workspaces-list', - version: '1.1.1', - workspaces: [ - 'a', - 'b', - 'group/*', - ], - }), - node_modules: { - abbrev: { - 'package.json': JSON.stringify({ name: 'abbrev', version: '1.1.1' }), + const config = (typeof workspace === 'function') + ? (dirs) => ({ workspace: workspace(dirs) }) + : { workspace } + + const mock = await loadMockNpm(t, { + config, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'simple-workspaces-list', + version: '1.1.1', + workspaces: [ + 'a', + 'b', + 'group/*', + ], + }), + node_modules: { + abbrev: { + 'package.json': JSON.stringify({ name: 'abbrev', version: '1.1.1' }), + }, + a: t.fixture('symlink', '../a'), + b: t.fixture('symlink', '../b'), }, - a: t.fixture('symlink', '../a'), - b: t.fixture('symlink', '../b'), - }, - a: { - 'package.json': JSON.stringify({ name: 'a', version: '1.0.0' }), - }, - b: { - 'package.json': JSON.stringify({ name: 'b', version: '1.0.0' }), - }, - group: { - c: { - 'package.json': JSON.stringify({ - name: 'c', - version: '1.0.0', - dependencies: { - abbrev: '^1.1.1', - }, - }), + a: { + 'package.json': JSON.stringify({ name: 'a', version: '1.0.0' }), + }, + b: { + 'package.json': JSON.stringify({ name: 'b', version: '1.0.0' }), }, - d: { - 'package.json': JSON.stringify({ name: 'd', version: '1.0.0' }), + group: { + c: { + 'package.json': JSON.stringify({ + name: 'c', + version: '1.0.0', + dependencies: { + abbrev: '^1.1.1', + }, + }), + }, + d: { + 'package.json': JSON.stringify({ name: 'd', version: '1.0.0' }), + }, }, }, + ...opts, }) - class TestCmd extends ArboristCmd {} - - const cmd = new TestCmd({ localPrefix: path, config: configMock }) - - // check filtering for a single workspace name - cmd.exec = async function (args) { - t.same(this.workspaceNames, ['a'], 'should set array with single ws name') - t.same(args, ['foo'], 'should get received args') + let execArg + class TestCmd extends ArboristCmd { + async exec (arg) { + execArg = arg + } } - await cmd.execWorkspaces(['foo'], ['a']) - // check filtering single workspace by path - cmd.exec = async function (args) { - t.same(this.workspaceNames, ['a'], - 'should set array with single ws name from path') + const cmd = new TestCmd(mock.npm) + if (exec) { + await cmd.execWorkspaces(exec) } - await cmd.execWorkspaces([], ['./a']) - // check filtering single workspace by full path - cmd.exec = function (args) { - t.same(this.workspaceNames, ['a'], - 'should set array with single ws name from full path') - } - await cmd.execWorkspaces([], [resolve(path, './a')]) + return { ...mock, cmd, getArg: () => execArg } +} - // filtering multiple workspaces by name - cmd.exec = async function (args) { - t.same(this.workspaceNames, ['a', 'c'], - 'should set array with multiple listed ws names') - } - await cmd.execWorkspaces([], ['a', 'c']) +t.test('arborist-cmd', async t => { + await t.test('single name', async t => { + const { cmd, getArg } = await mockArboristCmd(t, ['foo'], 'a') - // filtering multiple workspaces by path names - cmd.exec = async function (args) { - t.same(this.workspaceNames, ['a', 'c'], - 'should set array with multiple ws names from paths') - } - await cmd.execWorkspaces([], ['./a', 'group/c']) + t.same(cmd.workspaceNames, ['a'], 'should set array with single ws name') + t.same(getArg(), ['foo'], 'should get received args') + }) - // filtering multiple workspaces by parent path name - cmd.exec = async function (args) { - t.same(this.workspaceNames, ['c', 'd'], - 'should set array with multiple ws names from a parent folder name') - } - await cmd.execWorkspaces([], ['./group']) + await t.test('single path', async t => { + const { cmd } = await mockArboristCmd(t, [], './a') + + t.same(cmd.workspaceNames, ['a'], 'should set array with single ws name') + }) + + await t.test('single full path', async t => { + const { cmd } = await mockArboristCmd(t, [], ({ prefix }) => resolve(prefix, 'a')) + + t.same(cmd.workspaceNames, ['a'], 'should set array with single ws name') + }) + + await t.test('multiple names', async t => { + const { cmd } = await mockArboristCmd(t, [], ['a', 'c']) + + t.same(cmd.workspaceNames, ['a', 'c'], 'should set array with single ws name') + }) + + await t.test('multiple paths', async t => { + const { cmd } = await mockArboristCmd(t, [], ['./a', 'group/c']) + + t.same(cmd.workspaceNames, ['a', 'c'], 'should set array with single ws name') + }) + + await t.test('parent path', async t => { + const { cmd } = await mockArboristCmd(t, [], './group') + + t.same(cmd.workspaceNames, ['c', 'd'], 'should set array with single ws name') + }) + + await t.test('parent path', async t => { + const { cmd } = await mockArboristCmd(t, [], './group') + + t.same(cmd.workspaceNames, ['c', 'd'], 'should set array with single ws name') + }) + + await t.test('prefix inside cwd', async t => { + const { npm, cmd, prefix } = await mockArboristCmd(t, null, ['a', 'c'], { + chdir: (dirs) => dirs.testdir, + }) + + npm.localPrefix = prefix + await cmd.execWorkspaces([]) + + t.same(cmd.workspaceNames, ['a', 'c'], 'should set array with single ws name') + }) }) t.test('handle getWorkspaces raising an error', async t => { - const ArboristCmd = t.mock('../../lib/arborist-cmd.js', { - '../../lib/workspaces/get-workspaces.js': async () => { - throw new Error('oopsie') + const { cmd } = await mockArboristCmd(t, null, 'a', { + mocks: { + '{LIB}/workspaces/get-workspaces.js': async () => { + throw new Error('oopsie') + }, }, }) - class TestCmd extends ArboristCmd {} - const cmd = new TestCmd({ localPrefix: t.testdir(), config: configMock }) await t.rejects( - cmd.execWorkspaces(['foo'], ['a']), + cmd.execWorkspaces(['foo']), { message: 'oopsie' } ) }) diff --git a/deps/npm/test/lib/cli.js b/deps/npm/test/lib/cli.js index 42a22a20b39643..28640a226065e5 100644 --- a/deps/npm/test/lib/cli.js +++ b/deps/npm/test/lib/cli.js @@ -1,6 +1,6 @@ const t = require('tap') - const { load: loadMockNpm } = require('../fixtures/mock-npm.js') +const tmock = require('../fixtures/tmock') const cliMock = async (t, opts) => { let exitHandlerArgs = null @@ -12,9 +12,9 @@ const cliMock = async (t, opts) => { exitHandlerMock.setNpm = _npm => npm = _npm const { Npm, outputs, logMocks, logs } = await loadMockNpm(t, { ...opts, init: false }) - const cli = t.mock('../../lib/cli.js', { - '../../lib/npm.js': Npm, - '../../lib/utils/exit-handler.js': exitHandlerMock, + const cli = tmock(t, '{LIB}/cli.js', { + '{LIB}/npm.js': Npm, + '{LIB}/utils/exit-handler.js': exitHandlerMock, ...logMocks, }) @@ -29,10 +29,6 @@ const cliMock = async (t, opts) => { } } -t.afterEach(() => { - process.exitCode = undefined -}) - t.test('print the version, and treat npm_g as npm -g', async t => { const { logsBy, logs, cli, Npm, outputs, exitHandlerCalled } = await cliMock(t, { globals: { 'process.argv': ['node', 'npm_g', '-v'] }, @@ -42,24 +38,18 @@ t.test('print the version, and treat npm_g as npm -g', async t => { t.strictSame(process.argv, ['node', 'npm', '-g', '-v'], 'system process.argv was rewritten') t.strictSame(logsBy('cli'), [['node npm']]) t.strictSame(logsBy('title'), [['npm']]) - t.strictSame(logsBy('argv'), [['"--global" "--version"']]) + t.match(logsBy('argv'), [['"--global" "--version"']]) t.strictSame(logs.info, [ ['using', 'npm@%s', Npm.version], ['using', 'node@%s', process.version], ]) + t.equal(outputs.length, 1) t.strictSame(outputs, [[Npm.version]]) t.strictSame(exitHandlerCalled(), []) }) t.test('calling with --versions calls npm version with no args', async t => { const { logsBy, cli, outputs, exitHandlerCalled } = await cliMock(t, { - mocks: { - '../../lib/commands/version.js': class Version { - async exec (args) { - t.strictSame(args, []) - } - }, - }, globals: { 'process.argv': ['node', 'npm', 'install', 'or', 'whatever', '--versions'], }, @@ -69,18 +59,14 @@ t.test('calling with --versions calls npm version with no args', async t => { t.equal(process.title, 'npm install or whatever') t.strictSame(logsBy('cli'), [['node npm']]) t.strictSame(logsBy('title'), [['npm install or whatever']]) - t.strictSame(logsBy('argv'), [['"install" "or" "whatever" "--versions"']]) - t.strictSame(outputs, []) + t.match(logsBy('argv'), [['"install" "or" "whatever" "--versions"']]) + t.equal(outputs.length, 1) + t.match(outputs[0][0], { npm: String, node: String, v8: String }) t.strictSame(exitHandlerCalled(), []) }) t.test('logged argv is sanitized', async t => { const { logsBy, cli } = await cliMock(t, { - mocks: { - '../../lib/commands/version.js': class Version { - async exec () {} - }, - }, globals: { 'process.argv': [ 'node', @@ -96,16 +82,11 @@ t.test('logged argv is sanitized', async t => { t.equal(process.title, 'npm version') t.strictSame(logsBy('cli'), [['node npm']]) t.strictSame(logsBy('title'), [['npm version']]) - t.strictSame(logsBy('argv'), [['"version" "--registry" "https://u:***@npmjs.org/password"']]) + t.match(logsBy('argv'), [['"version" "--registry" "https://u:***@npmjs.org/password"']]) }) t.test('logged argv is sanitized with equals', async t => { const { logsBy, cli } = await cliMock(t, { - mocks: { - '../../lib/commands/version.js': class Version { - async exec () {} - }, - }, globals: { 'process.argv': [ 'node', @@ -117,7 +98,7 @@ t.test('logged argv is sanitized with equals', async t => { }) await cli(process) - t.strictSame(logsBy('argv'), [['"version" "--registry" "https://u:***@npmjs.org"']]) + t.match(logsBy('argv'), [['"version" "--registry" "https://u:***@npmjs.org"']]) }) t.test('print usage if no params provided', async t => { @@ -153,7 +134,7 @@ t.test('load error calls error handler', async t => { const err = new Error('test load error') const { cli, exitHandlerCalled } = await cliMock(t, { mocks: { - '../../lib/utils/config/index.js': { + '{LIB}/utils/config/index.js': { definitions: null, flatten: null, shorthands: null, diff --git a/deps/npm/test/lib/commands/audit.js b/deps/npm/test/lib/commands/audit.js index 02b00f7f9ad88a..bba74407cb3fef 100644 --- a/deps/npm/test/lib/commands/audit.js +++ b/deps/npm/test/lib/commands/audit.js @@ -86,7 +86,6 @@ t.test('normal audit', async t => { await npm.exec('audit', []) t.ok(process.exitCode, 'would have exited uncleanly') - process.exitCode = 0 t.matchSnapshot(joinedOutput()) }) @@ -135,7 +134,6 @@ t.test('fallback audit ', async t => { }) await npm.exec('audit', []) t.ok(process.exitCode, 'would have exited uncleanly') - process.exitCode = 0 t.matchSnapshot(joinedOutput()) }) @@ -165,7 +163,6 @@ t.test('json audit', async t => { await npm.exec('audit', []) t.ok(process.exitCode, 'would have exited uncleanly') - process.exitCode = 0 t.matchSnapshot(joinedOutput()) }) @@ -762,7 +759,6 @@ t.test('audit signatures', async t => { await npm.exec('audit', ['signatures']) t.equal(process.exitCode, 0, 'should exit successfully') - process.exitCode = 0 t.match(joinedOutput(), /audited 1 package/) t.matchSnapshot(joinedOutput()) }) @@ -796,7 +792,6 @@ t.test('audit signatures', async t => { await npm.exec('audit', ['signatures']) t.equal(process.exitCode, 0, 'should exit successfully') - process.exitCode = 0 t.match(joinedOutput(), /audited 1 package/) t.matchSnapshot(joinedOutput()) }) @@ -903,7 +898,6 @@ t.test('audit signatures', async t => { await npm.exec('audit', ['signatures']) t.equal(process.exitCode, 1, 'should exit with error') - process.exitCode = 0 t.match(joinedOutput(), /audited 3 packages/) t.match(joinedOutput(), /2 packages have verified registry signatures/) t.match(joinedOutput(), /1 package has an invalid registry signature/) @@ -921,7 +915,6 @@ t.test('audit signatures', async t => { await npm.exec('audit', ['signatures']) t.equal(process.exitCode, 0, 'should exit successfully') - process.exitCode = 0 t.match(joinedOutput(), /audited 1 package/) t.matchSnapshot(joinedOutput()) }) @@ -937,7 +930,6 @@ t.test('audit signatures', async t => { await npm.exec('audit', ['signatures']) t.equal(process.exitCode, 1, 'should exit with error') - process.exitCode = 0 t.match(joinedOutput(), /invalid registry signature/) t.match(joinedOutput(), /kms-demo@1.0.0/) t.matchSnapshot(joinedOutput()) @@ -955,7 +947,6 @@ t.test('audit signatures', async t => { await npm.exec('audit', ['signatures']) t.equal(process.exitCode, 1, 'should exit with error') - process.exitCode = 0 t.match(joinedOutput(), /audited 2 packages/) t.match(joinedOutput(), /verified registry signature/) t.match(joinedOutput(), /missing registry signature/) @@ -974,7 +965,6 @@ t.test('audit signatures', async t => { await npm.exec('audit', ['signatures']) t.equal(process.exitCode, 1, 'should exit with error') - process.exitCode = 0 t.match(joinedOutput(), /audited 2 packages/) t.match(joinedOutput(), /invalid/) t.match(joinedOutput(), /missing/) @@ -993,7 +983,6 @@ t.test('audit signatures', async t => { await npm.exec('audit', ['signatures']) t.equal(process.exitCode, 1, 'should exit with error') - process.exitCode = 0 t.matchSnapshot(joinedOutput()) }) @@ -1009,7 +998,6 @@ t.test('audit signatures', async t => { await npm.exec('audit', ['signatures']) t.equal(process.exitCode, 1, 'should exit with error') - process.exitCode = 0 t.matchSnapshot(joinedOutput()) }) @@ -1069,7 +1057,6 @@ t.test('audit signatures', async t => { await npm.exec('audit', ['signatures']) t.equal(process.exitCode, 1, 'should exit with error') - process.exitCode = 0 t.match( joinedOutput(), /registry is providing signing keys/ @@ -1088,7 +1075,6 @@ t.test('audit signatures', async t => { await npm.exec('audit', ['signatures']) t.equal(process.exitCode, 1, 'should exit with error') - process.exitCode = 0 t.match( joinedOutput(), /kms-demo/ @@ -1110,7 +1096,6 @@ t.test('audit signatures', async t => { await npm.exec('audit', ['signatures']) t.equal(process.exitCode, 0, 'should exit successfully') - process.exitCode = 0 t.match(joinedOutput(), JSON.stringify({ invalid: [], missing: [] }, null, 2)) t.matchSnapshot(joinedOutput()) }) @@ -1129,7 +1114,6 @@ t.test('audit signatures', async t => { await npm.exec('audit', ['signatures']) t.equal(process.exitCode, 1, 'should exit with error') - process.exitCode = 0 t.matchSnapshot(joinedOutput()) }) @@ -1148,7 +1132,6 @@ t.test('audit signatures', async t => { await npm.exec('audit', ['signatures']) t.equal(process.exitCode, 1, 'should exit with error') - process.exitCode = 0 t.matchSnapshot(joinedOutput()) }) @@ -1166,7 +1149,6 @@ t.test('audit signatures', async t => { await npm.exec('audit', ['signatures']) t.equal(process.exitCode, 0, 'should exit successfully') - process.exitCode = 0 t.match(joinedOutput(), /audited 1 package/) t.matchSnapshot(joinedOutput()) }) @@ -1176,7 +1158,8 @@ t.test('audit signatures', async t => { const { npm } = await loadMockNpm(t, { prefixDir: installWithThirdPartyRegistry, config: { - '@npmcli:registry': registryUrl, + scope: '@npmcli', + registry: registryUrl, }, }) const registry = new MockRegistry({ tap: t, registry: registryUrl }) @@ -1205,7 +1188,8 @@ t.test('audit signatures', async t => { const { npm } = await loadMockNpm(t, { prefixDir: installWithThirdPartyRegistry, config: { - '@npmcli:registry': registryUrl, + scope: '@npmcli', + registry: registryUrl, }, }) const registry = new MockRegistry({ tap: t, registry: registryUrl }) @@ -1234,7 +1218,8 @@ t.test('audit signatures', async t => { const { npm, joinedOutput } = await loadMockNpm(t, { prefixDir: installWithThirdPartyRegistry, config: { - '@npmcli:registry': registryUrl, + scope: '@npmcli', + registry: registryUrl, }, }) const registry = new MockRegistry({ tap: t, registry: registryUrl }) @@ -1273,7 +1258,6 @@ t.test('audit signatures', async t => { await npm.exec('audit', ['signatures']) t.equal(process.exitCode, 0, 'should exit successfully') - process.exitCode = 0 t.match(joinedOutput(), /audited 1 package/) t.matchSnapshot(joinedOutput()) }) @@ -1283,7 +1267,8 @@ t.test('audit signatures', async t => { const { npm, joinedOutput } = await loadMockNpm(t, { prefixDir: installWithThirdPartyRegistry, config: { - '@npmcli:registry': registryUrl, + scope: '@npmcli', + registry: registryUrl, }, }) const registry = new MockRegistry({ tap: t, registry: registryUrl }) @@ -1321,7 +1306,6 @@ t.test('audit signatures', async t => { await npm.exec('audit', ['signatures']) t.equal(process.exitCode, 1, 'should exit with error') - process.exitCode = 0 t.match(joinedOutput(), /https:\/\/verdaccio-clone.org/) t.matchSnapshot(joinedOutput()) }) @@ -1331,7 +1315,8 @@ t.test('audit signatures', async t => { const { npm, joinedOutput } = await loadMockNpm(t, { prefixDir: installWithThirdPartyRegistry, config: { - '@npmcli:registry': registryUrl, + scope: '@npmcli', + registry: registryUrl, }, }) const registry = new MockRegistry({ tap: t, registry: registryUrl }) @@ -1363,7 +1348,6 @@ t.test('audit signatures', async t => { await npm.exec('audit', ['signatures']) t.equal(process.exitCode, 1, 'should exit with error') - process.exitCode = 0 t.match(joinedOutput(), /1 package has a missing registry signature/) t.matchSnapshot(joinedOutput()) }) @@ -1371,9 +1355,9 @@ t.test('audit signatures', async t => { t.test('multiple registries with keys and signatures', async t => { const registryUrl = 'https://verdaccio-clone.org' const { npm, joinedOutput } = await loadMockNpm(t, { - prefixDir: installWithMultipleRegistries, - config: { - '@npmcli:registry': registryUrl, + prefixDir: { + ...installWithMultipleRegistries, + '.npmrc': `@npmcli:registry=${registryUrl}\n`, }, }) const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) @@ -1418,7 +1402,6 @@ t.test('audit signatures', async t => { await npm.exec('audit', ['signatures']) t.equal(process.exitCode, 0, 'should exit successfully') - process.exitCode = 0 t.match(joinedOutput(), /audited 2 packages/) t.matchSnapshot(joinedOutput()) }) @@ -1465,7 +1448,6 @@ t.test('audit signatures', async t => { await npm.exec('audit', ['signatures']) t.equal(process.exitCode, 0, 'should exit successfully') - process.exitCode = 0 t.match(joinedOutput(), /audited 1 package/) t.matchSnapshot(joinedOutput()) }) @@ -1586,7 +1568,6 @@ t.test('audit signatures', async t => { await npm.exec('audit', ['signatures']) t.equal(process.exitCode, 1, 'should exit with error') - process.exitCode = 0 t.match( joinedOutput(), // eslint-disable-next-line no-control-regex @@ -1645,7 +1626,6 @@ t.test('audit signatures', async t => { await npm.exec('audit', ['signatures']) t.equal(process.exitCode, 0, 'should exit successfully') - process.exitCode = 0 t.match(joinedOutput(), /audited 3 packages/) t.matchSnapshot(joinedOutput()) }) @@ -1653,7 +1633,7 @@ t.test('audit signatures', async t => { t.test('verifies registry deps when filtering by workspace name', async t => { const { npm, joinedOutput } = await loadMockNpm(t, { prefixDir: workspaceInstall, - config: { workspace: ['./packages/a'] }, + config: { workspace: './packages/a' }, }) const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) const asyncManifest = registry.manifest({ @@ -1699,7 +1679,6 @@ t.test('audit signatures', async t => { await npm.exec('audit', ['signatures']) t.equal(process.exitCode, 0, 'should exit successfully') - process.exitCode = 0 t.match(joinedOutput(), /audited 2 packages/) t.matchSnapshot(joinedOutput()) }) diff --git a/deps/npm/test/lib/commands/bugs.js b/deps/npm/test/lib/commands/bugs.js index 91d144b6bdc970..bf45b9eee81ab3 100644 --- a/deps/npm/test/lib/commands/bugs.js +++ b/deps/npm/test/lib/commands/bugs.js @@ -1,79 +1,71 @@ const t = require('tap') +const { load: loadMockNpm } = require('../../fixtures/mock-npm') const pacote = { - manifest: async (spec, options) => { + manifest: async (spec) => { 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 === 'mailtest' ? { - name: 'mailtest', - version: '3.7.4', - bugs: { email: 'hello@example.com' }, - } - : spec === 'secondmailtest' ? { - name: 'secondmailtest', - version: '0.1.1', - bugs: { email: 'ABC432abc@a.b.example.net' }, - } - : 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 === 'mailtest' ? { + name: 'mailtest', + version: '3.7.4', + bugs: { email: 'hello@example.com' }, + } : spec === 'secondmailtest' ? { + name: 'secondmailtest', + version: '0.1.1', + bugs: { email: 'ABC432abc@a.b.example.net' }, + } : spec === '.' ? { + name: 'thispkg', + version: '1.2.3', + bugs: 'https://example.com', + } : null }, } -// keep a tally of which urls got opened -let opened = {} -const openUrl = async (npm, url, errMsg) => { - opened[url] = opened[url] || 0 - opened[url]++ -} - -const Bugs = t.mock('../../../lib/commands/bugs.js', { - pacote, - '../../../lib/utils/open-url.js': openUrl, +t.test('usage', async (t) => { + const { npm } = await loadMockNpm(t) + const bugs = await npm.cmd('bugs') + t.match(bugs.usage, 'bugs', 'usage has command name in it') }) -const bugs = new Bugs({ flatOptions: {}, config: { validate: () => {} } }) +t.test('open bugs urls & emails', async t => { + // keep a tally of which urls got opened + let opened = {} -t.test('usage', (t) => { - t.match(bugs.usage, 'bugs', 'usage has command name in it') - t.end() -}) + const openUrl = async (_, url) => { + opened[url] = opened[url] || 0 + opened[url]++ + } -t.afterEach(() => { - opened = {} -}) -t.test('open bugs urls & emails', t => { - const expect = { + const { npm } = await loadMockNpm(t, { + mocks: { + pacote, + '{LIB}/utils/open-url.js': openUrl, + }, + }) + + const expected = { + '.': 'https://example.com', nobugs: 'https://www.npmjs.com/package/nobugs', 'bugsobj-nourl': 'https://www.npmjs.com/package/bugsobj-nourl', bugsurl: 'https://bugzilla.localhost/bugsurl', @@ -82,19 +74,19 @@ t.test('open bugs urls & emails', t => { repoobj: 'https://github.com/foo/repoobj/issues', mailtest: 'mailto:hello@example.com', secondmailtest: 'mailto:ABC432abc@a.b.example.net', - '.': 'https://example.com', } - const keys = Object.keys(expect) - t.plan(keys.length) - keys.forEach(pkg => { - t.test(pkg, async t => { - await bugs.exec([pkg]) - t.equal(opened[expect[pkg]], 1, 'opened expected url', { opened }) + + for (const [pkg, expect] of Object.entries(expected)) { + await t.test(pkg, async t => { + await npm.exec('bugs', [pkg]) + t.equal(opened[expect], 1, 'opened expected url', { opened }) }) - }) -}) + } -t.test('open default package if none specified', async t => { - await bugs.exec([]) - t.equal(opened['https://example.com'], 1, 'opened expected url', { opened }) + opened = {} + + await t.test('open default package if none specified', async t => { + await npm.exec('bugs', []) + t.equal(opened['https://example.com'], 1, 'opened expected url', { opened }) + }) }) diff --git a/deps/npm/test/lib/commands/config.js b/deps/npm/test/lib/commands/config.js index 35872e722e17e3..f2bdcc7231ddf9 100644 --- a/deps/npm/test/lib/commands/config.js +++ b/deps/npm/test/lib/commands/config.js @@ -26,16 +26,10 @@ t.test('config ignores workspaces', async t => { await t.rejects( sandbox.run('config', ['--workspaces']), { - code: 'EUSAGE', + code: 'ENOWORKSPACES', }, 'rejects with usage' ) - - t.match( - sandbox.logs.warn, - [['config', 'This command does not support workspaces.']], - 'logged the warning' - ) }) t.test('config list', async t => { diff --git a/deps/npm/test/lib/commands/diff.js b/deps/npm/test/lib/commands/diff.js index 0ca9c3b8d078b3..d9ff9e5dad0e6a 100644 --- a/deps/npm/test/lib/commands/diff.js +++ b/deps/npm/test/lib/commands/diff.js @@ -1,1164 +1,1041 @@ const t = require('tap') -const { resolve, join } = require('path') -const { fake: mockNpm } = require('../../fixtures/mock-npm') +const { join, extname } = require('path') +const MockRegistry = require('@npmcli/mock-registry') +const { load: loadMockNpm } = require('../../fixtures/mock-npm') + +const jsonifyTestdir = (obj) => { + for (const [key, value] of Object.entries(obj || {})) { + if (extname(key) === '.json') { + obj[key] = JSON.stringify(value, null, 2) + '\n' + } else if (typeof value === 'object') { + obj[key] = jsonifyTestdir(value) + } else { + obj[key] = value.trim() + '\n' + } + } + return obj +} -const noop = () => null -let libnpmdiff = noop +// generic helper to call diff with a specified dir contents and registry calls +const mockDiff = async (t, { + exec, + diff = [], + tarballs = {}, + times = {}, + ...opts +} = {}) => { + const tarballFixtures = Object.entries(tarballs).reduce((acc, [spec, fixture]) => { + const [name, version] = spec.split('@') + acc[name] = acc[name] || {} + acc[name][version] = fixture + if (!acc[name][version]['package.json']) { + acc[name][version]['package.json'] = { name, version } + } else { + acc[name][version]['package.json'].name = name + acc[name][version]['package.json'].version = version + } + return acc + }, {}) + + const { prefixDir, globalPrefixDir, otherDirs, config, ...rest } = opts + const { npm, ...res } = await loadMockNpm(t, { + prefixDir: jsonifyTestdir(prefixDir), + otherDirs: jsonifyTestdir({ tarballs: tarballFixtures, ...otherDirs }), + globalPrefixDir: jsonifyTestdir(globalPrefixDir), + config: { + ...config, + diff: [].concat(diff), + }, + ...rest, + }) -const config = { - global: false, - tag: 'latest', - diff: [], -} -const flatOptions = { - global: false, - diffUnified: null, - diffIgnoreAllSpace: false, - diffNoPrefix: false, - diffSrcPrefix: '', - diffDstPrefix: '', - diffText: false, - savePrefix: '^', -} -const fooPath = t.testdir({ - 'package.json': JSON.stringify({ name: 'foo', version: '1.0.0' }), -}) -const npm = mockNpm({ - prefix: fooPath, - config, - flatOptions, - output: noop, -}) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + strict: true, + debug: true, + }) + + const manifests = Object.entries(tarballFixtures).reduce((acc, [name, versions]) => { + acc[name] = registry.manifest({ + name, + packuments: Object.keys(versions).map((version) => ({ version })), + }) + return acc + }, {}) + + for (const [name, manifest] of Object.entries(manifests)) { + await registry.package({ manifest, times: times[name] ?? 1 }) + for (const [version, tarballManifest] of Object.entries(manifest.versions)) { + await registry.tarball({ + manifest: tarballManifest, + tarball: join(res.other, 'tarballs', name, version), + }) + } + } -const mocks = { - 'proc-log': { info: noop, verbose: noop }, - libnpmdiff: (...args) => libnpmdiff(...args), - 'npm-registry-fetch': async () => ({}), + if (exec) { + await npm.exec('diff', exec) + res.output = res.joinedOutput() + } + + return { npm, registry, ...res } } -t.afterEach(() => { - config.global = false - config.tag = 'latest' - config.diff = [] - flatOptions.global = false - flatOptions.diffUnified = null - flatOptions.diffIgnoreAllSpace = false - flatOptions.diffNoPrefix = false - flatOptions.diffSrcPrefix = '' - flatOptions.diffDstPrefix = '' - flatOptions.diffText = false - flatOptions.savePrefix = '^' - npm.globalDir = fooPath - npm.prefix = fooPath - libnpmdiff = noop - diff.prefix = undefined - diff.top = undefined -}) +// a more specific helper to call diff against a local package and a registry package +// and assert the diff output contains the matching strings +const assertFoo = async (t, arg) => { + let diff = [] + let exec = [] + + if (typeof arg === 'string' || Array.isArray(arg)) { + diff = arg + } else if (arg && typeof arg === 'object') { + diff = arg.diff + exec = arg.exec + } + + const { output } = await mockDiff(t, { + diff, + prefixDir: { + 'package.json': { name: 'foo', version: '1.0.0' }, + 'index.js': 'const version = "1.0.0"', + 'a.js': 'const a = "a@1.0.0"', + 'b.js': 'const b = "b@1.0.0"', + }, + tarballs: { + 'foo@0.1.0': { + 'index.js': 'const version = "0.1.0"', + 'a.js': 'const a = "a@0.1.0"', + 'b.js': 'const b = "b@0.1.0"', + }, + }, + exec, + }) -const Diff = t.mock('../../../lib/commands/diff.js', mocks) -const diff = new Diff(npm) + const hasFile = (f) => !exec.length || exec.some(e => e.endsWith(f)) -t.test('no args', t => { - t.test('in a project dir', async t => { - t.plan(3) + if (hasFile('package.json')) { + t.match(output, /-\s*"version": "0\.1\.0"/) + t.match(output, /\+\s*"version": "1\.0\.0"/) + } - libnpmdiff = async ([a, b], opts) => { - t.equal(a, 'foo@latest', 'should have default spec comparison') - t.equal(b, `file:${fooPath}`, 'should compare to cwd') - t.match(opts, npm.flatOptions, 'should forward flat options') - } + if (hasFile('index.js')) { + t.match(output, /-\s*const version = "0\.1\.0"/) + t.match(output, /\+\s*const version = "1\.0\.0"/) + } + + if (hasFile('a.js')) { + t.match(output, /-\s*const a = "a@0\.1\.0"/) + t.match(output, /\+\s*const a = "a@1\.0\.0"/) + } + + if (hasFile('b.js')) { + t.match(output, /-\s*const b = "b@0\.1\.0"/) + t.match(output, /\+\s*const b = "b@1\.0\.0"/) + } - npm.prefix = fooPath - await diff.exec([]) + return output +} + +const rejectDiff = async (t, msg, opts) => { + const { npm } = await mockDiff(t, opts) + await t.rejects(npm.exec('diff', []), msg) +} + +t.test('no args', async t => { + t.test('in a project dir', async t => { + const output = await assertFoo(t) + t.matchSnapshot(output) }) t.test('no args, missing package.json name in cwd', async t => { - const path = t.testdir({}) - npm.prefix = path - await t.rejects( - diff.exec([]), - /Needs multiple arguments to compare or run from a project dir./, - 'should throw EDIFF error msg' - ) + await rejectDiff(t, /Needs multiple arguments to compare or run from a project dir./) }) t.test('no args, bad package.json in cwd', async t => { - const path = t.testdir({ - 'package.json': '{invalid"json', + await rejectDiff(t, /Needs multiple arguments to compare or run from a project dir./, { + prefixDir: { 'package.json': '{invalid"json' }, }) - npm.prefix = path - - await t.rejects( - diff.exec([]), - /Needs multiple arguments to compare or run from a project dir./, - 'should throw EDIFF error msg' - ) }) - - t.end() }) -t.test('single arg', t => { +t.test('single arg', async t => { t.test('spec using cwd package name', async t => { - t.plan(3) - - libnpmdiff = async ([a, b], opts) => { - t.equal(a, 'foo@1.0.0', 'should forward single spec') - t.equal(b, `file:${fooPath}`, 'should compare to cwd') - t.match(opts, npm.flatOptions, 'should forward flat options') - } - - config.diff = ['foo@1.0.0'] - npm.prefix = fooPath - await diff.exec([]) + await assertFoo(t, 'foo@0.1.0') }) t.test('unknown spec, no package.json', async t => { - const path = t.testdir({}) - - config.diff = ['foo@1.0.0'] - npm.prefix = path - await t.rejects( - diff.exec([]), - /Needs multiple arguments to compare or run from a project dir./, - 'should throw usage error' - ) + await rejectDiff(t, /Needs multiple arguments to compare or run from a project dir./, { + diff: ['foo@1.0.0'], + }) }) t.test('spec using semver range', async t => { - t.plan(3) - - libnpmdiff = async ([a, b], opts) => { - t.equal(a, 'foo@~1.0.0', 'should forward single spec') - t.equal(b, `file:${fooPath}`, 'should compare to cwd') - t.match(opts, npm.flatOptions, 'should forward flat options') - } - - config.diff = ['foo@~1.0.0'] - await diff.exec([]) + await assertFoo(t, 'foo@~0.1.0') }) t.test('version', async t => { - t.plan(3) - - libnpmdiff = async ([a, b], opts) => { - t.equal(a, 'foo@2.1.4', 'should convert to expected first spec') - t.equal(b, `file:${fooPath}`, 'should compare to cwd') - t.match(opts, npm.flatOptions, 'should forward flat options') - } - - config.diff = ['2.1.4'] - await diff.exec([]) + await assertFoo(t, '0.1.0') }) t.test('version, no package.json', async t => { - const path = t.testdir({}) - npm.prefix = path - config.diff = ['2.1.4'] - await t.rejects( - diff.exec([]), - /Needs multiple arguments to compare or run from a project dir./, - 'should throw an error message explaining usage' - ) + await rejectDiff(t, /Needs multiple arguments to compare or run from a project dir./, { + diff: ['0.1.0'], + }) }) t.test('version, filtering by files', async t => { - t.plan(3) - - libnpmdiff = async ([a, b], opts) => { - t.equal(a, 'foo@2.1.4', 'should use expected spec') - t.equal(b, `file:${fooPath}`, 'should compare to cwd') - t.match( - opts, - { - ...npm.flatOptions, - diffFiles: ['./foo.js', './bar.js'], - }, - 'should forward flatOptions and diffFiles' - ) - } - - config.diff = ['2.1.4'] - await diff.exec(['./foo.js', './bar.js']) + const output = await assertFoo(t, { diff: '0.1.0', exec: ['./a.js', './b.js'] }) + t.matchSnapshot(output) }) t.test('spec is not a dep', async t => { - t.plan(2) - - const path = t.testdir({ - node_modules: {}, - 'package.json': JSON.stringify({ - name: 'my-project', - }), + const { output } = await mockDiff(t, { + diff: 'bar@1.0.0', + prefixDir: { + node_modules: {}, + 'package.json': { name: 'my-project', version: '1.0.0' }, + }, + tarballs: { + 'bar@1.0.0': {}, + }, + exec: [], }) - libnpmdiff = async ([a, b], opts) => { - t.equal(a, 'bar@1.0.0', 'should have current spec') - t.equal(b, `file:${path}`, 'should compare to cwd') - } - - config.diff = ['bar@1.0.0'] - npm.prefix = path - - await diff.exec([]) + t.match(output, /-\s*"name": "bar"/) + t.match(output, /\+\s*"name": "my-project"/) }) t.test('unknown package name', async t => { - t.plan(3) - - const path = t.testdir({ - 'package.json': JSON.stringify({ - name: 'my-project', - dependencies: { - bar: '^1.0.0', + const { npm, registry } = await mockDiff(t, { + diff: 'bar', + prefixDir: { + 'package.json': { + name: 'my-project', + dependencies: { + bar: '^1.0.0', + }, }, - }), + }, }) - - libnpmdiff = async ([a, b], opts) => { - t.equal(a, 'simple-output@*', 'should forward single spec') - t.equal(b, `file:${path}`, 'should compare to cwd') - t.match(opts, npm.flatOptions, 'should forward flat options') - } - - config.diff = ['simple-output'] - npm.prefix = path - await diff.exec([]) + registry.getPackage('bar', { times: 2, code: 404 }) + t.rejects(npm.exec('diff', []), /404 Not Found.*bar/) }) t.test('unknown package name, no package.json', async t => { - const path = t.testdir({}) - - config.diff = ['bar'] - npm.prefix = path - await t.rejects( - diff.exec([]), - /Needs multiple arguments to compare or run from a project dir./, - 'should throw usage error' - ) + const { npm } = await mockDiff(t, { + diff: 'bar', + }) + t.rejects(npm.exec('diff', []), + /Needs multiple arguments to compare or run from a project dir./) }) t.test('transform single direct dep name into spec comparison', async t => { - t.plan(4) - - const path = t.testdir({ - node_modules: { - bar: { - 'package.json': JSON.stringify({ - name: 'bar', - version: '1.0.0', - }), - }, - }, - 'package.json': JSON.stringify({ - name: 'my-project', - dependencies: { - bar: '^1.0.0', + const { output } = await mockDiff(t, { + diff: 'bar', + prefixDir: { + node_modules: { + bar: { + 'package.json': { + name: 'bar', + version: '1.0.0', + }, + }, }, - }), - }) - - config.diff = ['bar'] - npm.prefix = path - - const Diff = t.mock('../../../lib/commands/diff.js', { - ...mocks, - pacote: { - packument: spec => { - t.equal(spec.name, 'bar', 'should have expected spec name') + 'package.json': { + name: 'my-project', + dependencies: { + bar: '^1.0.0', + }, }, }, - 'npm-pick-manifest': (packument, target) => { - t.equal(target, '^1.0.0', 'should use expected target') - return { version: '1.8.10' } - }, - libnpmdiff: async ([a, b], opts) => { - t.equal( - a, - `bar@file:${resolve(path, 'node_modules/bar')}`, - 'should target local node_modules pkg' - ) - t.equal(b, 'bar@1.8.10', 'should have possible semver range spec') + tarballs: { + 'bar@1.8.0': {}, }, + times: { bar: 2 }, + exec: [], }) - const diff = new Diff(npm) - await diff.exec([]) + t.match(output, /-\s*"version": "1\.0\.0"/) + t.match(output, /\+\s*"version": "1\.8\.0"/) }) t.test('global space, transform single direct dep name', async t => { - t.plan(4) - - const path = t.testdir({ - globalDir: { - lib: { - node_modules: { - lorem: { - 'package.json': JSON.stringify({ - name: 'lorem', - version: '2.0.0', - }), + const { output } = await mockDiff(t, { + diff: 'lorem', + config: { + global: true, + }, + globalPrefixDir: { + node_modules: { + lorem: { + 'package.json': { + name: 'lorem', + version: '2.0.0', }, }, }, }, - project: { + prefixDir: { node_modules: { - bar: { - 'package.json': JSON.stringify({ - name: 'bar', - version: '1.0.0', - }), + lorem: { + 'package.json': { + name: 'lorem', + version: '3.0.0', + }, }, }, - 'package.json': JSON.stringify({ + 'package.json': { name: 'my-project', dependencies: { - bar: '^1.0.0', + lorem: '^3.0.0', }, - }), - }, - }) - - config.global = true - flatOptions.global = true - config.diff = ['lorem'] - npm.prefix = resolve(path, 'project') - npm.globalDir = resolve(path, 'globalDir/lib/node_modules') - - const Diff = t.mock('../../../lib/commands/diff.js', { - ...mocks, - pacote: { - packument: spec => { - t.equal(spec.name, 'lorem', 'should have expected spec name') }, }, - 'npm-pick-manifest': (packument, target) => { - t.equal(target, '*', 'should always want latest in global space') - return { version: '2.1.0' } + tarballs: { + 'lorem@1.0.0': {}, }, - libnpmdiff: async ([a, b], opts) => { - t.equal( - a, - `lorem@file:${resolve(path, 'globalDir/lib/node_modules/lorem')}`, - 'should target local node_modules pkg' - ) - t.equal(b, 'lorem@2.1.0', 'should have possible semver range spec') + times: { + lorem: 2, }, + exec: [], }) - const diff = new Diff(npm) - await diff.exec([]) + t.match(output, 'lorem') + t.match(output, /-\s*"version": "2\.0\.0"/) + t.match(output, /\+\s*"version": "1\.0\.0"/) }) t.test('transform single spec into spec comparison', async t => { - t.plan(2) - - const path = t.testdir({ - node_modules: { - bar: { - 'package.json': JSON.stringify({ - name: 'bar', - version: '1.0.0', - }), + const { output } = await mockDiff(t, { + diff: 'bar@2.0.0', + prefixDir: { + node_modules: { + bar: { + 'package.json': { + name: 'bar', + version: '1.0.0', + }, + }, }, - }, - 'package.json': JSON.stringify({ - name: 'my-project', - dependencies: { - bar: '^1.0.0', + 'package.json': { + name: 'my-project', + dependencies: { + bar: '^1.0.0', + }, }, - }), + }, + tarballs: { + 'bar@2.0.0': {}, + }, + times: { + lorem: 2, + }, + exec: [], }) - libnpmdiff = async ([a, b], opts) => { - t.equal( - a, - `bar@file:${resolve(path, 'node_modules/bar')}`, - 'should target local node_modules pkg' - ) - t.equal(b, 'bar@2.0.0', 'should have expected comparison spec') - } - - config.diff = ['bar@2.0.0'] - npm.prefix = path - - await diff.exec([]) + t.match(output, 'bar') + t.match(output, /-\s*"version": "1\.0\.0"/) + t.match(output, /\+\s*"version": "2\.0\.0"/) }) t.test('transform single spec from transitive deps', async t => { - t.plan(4) - - const path = t.testdir({ - node_modules: { - bar: { - 'package.json': JSON.stringify({ - name: 'bar', - version: '1.0.0', - dependencies: { - lorem: '^2.0.0', + const { output } = await mockDiff(t, { + diff: 'lorem', + prefixDir: { + node_modules: { + bar: { + 'package.json': { + name: 'bar', + version: '1.0.0', + dependencies: { + lorem: '^2.0.0', + }, }, - }), - }, - lorem: { - 'package.json': JSON.stringify({ - name: 'lorem', - version: '2.0.0', - }), - }, - }, - 'package.json': JSON.stringify({ - name: 'my-project', - dependencies: { - bar: '^1.0.0', + }, + lorem: { + 'package.json': { + name: 'lorem', + version: '2.0.0', + }, + }, }, - }), - }) - - const Diff = t.mock('../../../lib/commands/diff.js', { - ...mocks, - pacote: { - packument: spec => { - t.equal(spec.name, 'lorem', 'should have expected spec name') + 'package.json': { + name: 'my-project', + dependencies: { + bar: '^1.0.0', + }, }, }, - 'npm-pick-manifest': (packument, target) => { - t.equal(target, '^2.0.0', 'should target first semver-range spec found') - return { version: '2.2.2' } + tarballs: { + 'lorem@2.2.2': {}, }, - libnpmdiff: async ([a, b], opts) => { - t.equal( - a, - `lorem@file:${resolve(path, 'node_modules/lorem')}`, - 'should target local node_modules pkg' - ) - t.equal(b, 'lorem@2.2.2', 'should have expected target spec') + times: { + lorem: 2, }, + exec: [], }) - const diff = new Diff(npm) - - config.diff = ['lorem'] - npm.prefix = path - await diff.exec([]) + t.match(output, 'lorem') + t.match(output, /-\s*"version": "2\.0\.0"/) + t.match(output, /\+\s*"version": "2\.2\.2"/) }) t.test('missing actual tree', async t => { - t.plan(2) - - const path = t.testdir({ - 'package.json': JSON.stringify({ - name: 'my-project', - }), - }) - - const Diff = t.mock('../../../lib/commands/diff.js', { - ...mocks, - '@npmcli/arborist': class { - constructor () { - throw new Error('ERR') - } + const { output } = await mockDiff(t, { + diff: 'lorem', + prefixDir: { + 'package.json': { + name: 'lorem', + version: '2.0.0', + }, + }, + mocks: { + '@npmcli/arborist': class { + constructor () { + throw new Error('ERR') + } + }, }, - libnpmdiff: async ([a, b], opts) => { - t.equal(a, 'lorem@*', 'should target any version of pkg name') - t.equal(b, `file:${path}`, 'should target current cwd') + tarballs: { + 'lorem@2.2.2': {}, }, + exec: [], }) - const diff = new Diff(npm) - config.diff = ['lorem'] - npm.prefix = path - - await diff.exec([]) + t.match(output, 'lorem') + t.match(output, /-\s*"version": "2\.2\.2"/) + t.match(output, /\+\s*"version": "2\.0\.0"/) }) t.test('unknown package name', async t => { - t.plan(2) + const { output } = await mockDiff(t, { + diff: 'bar', + prefixDir: { + 'package.json': { version: '1.0.0' }, + }, - const path = t.testdir({ - 'package.json': JSON.stringify({ version: '1.0.0' }), + tarballs: { + 'bar@2.2.2': {}, + }, + exec: [], }) - libnpmdiff = async ([a, b], opts) => { - t.equal(a, 'bar@*', 'should target any version of pkg name') - t.equal(b, `file:${path}`, 'should compare to cwd') - } - - config.diff = ['bar'] - npm.prefix = path - await diff.exec([]) + t.match(output, 'bar') + t.match(output, /-\s*"version": "2\.2\.2"/) + t.match(output, /\+\s*"version": "1\.0\.0"/) }) t.test('use project name in project dir', async t => { - t.plan(2) - - libnpmdiff = async ([a, b], opts) => { - t.equal(a, 'foo@*', 'should target any version of pkg name') - t.equal(b, `file:${fooPath}`, 'should compare to cwd') - } + const { output } = await mockDiff(t, { + diff: 'foo', + prefixDir: { + 'package.json': { name: 'foo', version: '1.0.0' }, + }, + tarballs: { + 'foo@2.2.2': {}, + }, + exec: [], + }) - config.diff = ['foo'] - await diff.exec([]) + t.match(output, 'foo') + t.match(output, /-\s*"version": "2\.2\.2"/) + t.match(output, /\+\s*"version": "1\.0\.0"/) }) t.test('dir spec type', async t => { - t.plan(2) - - const otherPath = resolve('/path/to/other-dir') - libnpmdiff = async ([a, b], opts) => { - t.equal(a, `file:${otherPath}`, 'should target dir') - t.equal(b, `file:${fooPath}`, 'should compare to cwd') - } + const { output } = await mockDiff(t, { + diff: '../other/other-pkg', + prefixDir: { + 'package.json': { name: 'foo', version: '1.0.0' }, + }, + otherDirs: { + 'other-pkg': { + 'package.json': { name: 'foo', version: '2.0.0' }, + }, + }, + exec: [], + }) - config.diff = [otherPath] - await diff.exec([]) + t.match(output, 'foo') + t.match(output, /-\s*"version": "2\.0\.0"/) + t.match(output, /\+\s*"version": "1\.0\.0"/) }) t.test('unsupported spec type', async t => { - config.diff = ['git+https://github.com/user/foo'] + const p = mockDiff(t, { + diff: 'git+https://github.com/user/foo', + exec: [], + }) + await t.rejects( - diff.exec([]), + p, /Spec type git not supported./, 'should throw spec type not supported error.' ) }) - - t.end() }) -t.test('first arg is a qualified spec', t => { +t.test('first arg is a qualified spec', async t => { t.test('second arg is ALSO a qualified spec', async t => { - t.plan(3) - - libnpmdiff = async ([a, b], opts) => { - t.equal(a, 'bar@1.0.0', 'should set expected first spec') - t.equal(b, 'bar@^2.0.0', 'should set expected second spec') - t.match(opts, npm.flatOptions, 'should forward flat options') - } + const { output } = await mockDiff(t, { + diff: ['bar@1.0.0', 'bar@^2.0.0'], + tarballs: { + 'bar@1.0.0': {}, + 'bar@2.2.2': {}, + }, + times: { + bar: 2, + }, + exec: [], + }) - config.diff = ['bar@1.0.0', 'bar@^2.0.0'] - await diff.exec([]) + t.match(output, 'bar') + t.match(output, /-\s*"version": "1\.0\.0"/) + t.match(output, /\+\s*"version": "2\.2\.2"/) }) t.test('second arg is a known dependency name', async t => { - t.plan(2) - - const path = t.testdir({ - node_modules: { - bar: { - 'package.json': JSON.stringify({ - name: 'bar', - version: '1.0.0', - }), + const { output } = await mockDiff(t, { + prefixDir: { + node_modules: { + bar: { + 'package.json': { + name: 'bar', + version: '1.0.0', + }, + }, }, - }, - 'package.json': JSON.stringify({ - name: 'my-project', - dependencies: { - bar: '^1.0.0', + 'package.json': { + name: 'my-project', + dependencies: { + bar: '^1.0.0', + }, }, - }), + }, + tarballs: { + 'bar@2.0.0': {}, + }, + diff: ['bar@2.0.0', 'bar'], + exec: [], }) - libnpmdiff = async ([a, b], opts) => { - t.equal(a, 'bar@2.0.0', 'should set expected first spec') - t.equal( - b, - `bar@file:${resolve(path, 'node_modules/bar')}`, - 'should target local node_modules pkg' - ) - } - - npm.prefix = path - config.diff = ['bar@2.0.0', 'bar'] - await diff.exec([]) + t.match(output, 'bar') + t.match(output, /-\s*"version": "2\.0\.0"/) + t.match(output, /\+\s*"version": "1\.0\.0"/) }) t.test('second arg is a valid semver version', async t => { - t.plan(2) - - config.diff = ['bar@1.0.0', '2.0.0'] - - libnpmdiff = async ([a, b], opts) => { - t.equal(a, 'bar@1.0.0', 'should set expected first spec') - t.equal(b, 'bar@2.0.0', 'should use name from first arg') - } + const { output } = await mockDiff(t, { + tarballs: { + 'bar@1.0.0': {}, + 'bar@2.0.0': {}, + }, + times: { + bar: 2, + }, + diff: ['bar@1.0.0', '2.0.0'], + exec: [], + }) - await diff.exec([]) + t.match(output, 'bar') + t.match(output, /-\s*"version": "1\.0\.0"/) + t.match(output, /\+\s*"version": "2\.0\.0"/) }) t.test('second arg is an unknown dependency name', async t => { - t.plan(2) + const { output } = await mockDiff(t, { + tarballs: { + 'bar@1.0.0': {}, + 'bar-fork@2.0.0': {}, + }, + diff: ['bar@1.0.0', 'bar-fork'], + exec: [], + }) - libnpmdiff = async ([a, b], opts) => { - t.equal(a, 'bar@1.0.0', 'should set expected first spec') - t.equal(b, 'bar-fork@*', 'should target any version if not a dep') - } + t.match(output, /-\s*"name": "bar"/) + t.match(output, /\+\s*"name": "bar-fork"/) - config.diff = ['bar@1.0.0', 'bar-fork'] - await diff.exec([]) + t.match(output, /-\s*"version": "1\.0\.0"/) + t.match(output, /\+\s*"version": "2\.0\.0"/) }) - - t.end() }) t.test('first arg is a known dependency name', async t => { - t.test('second arg is a qualified spec', t => { - t.plan(2) - - const path = t.testdir({ - node_modules: { - bar: { - 'package.json': JSON.stringify({ - name: 'bar', - version: '1.0.0', - }), + t.test('second arg is a qualified spec', async t => { + const { output } = await mockDiff(t, { + prefixDir: { + node_modules: { + bar: { + 'package.json': { + name: 'bar', + version: '1.0.0', + }, + }, }, - }, - 'package.json': JSON.stringify({ - name: 'my-project', - dependencies: { - bar: '^1.0.0', + 'package.json': { + name: 'my-project', + dependencies: { + bar: '^1.0.0', + }, }, - }), + }, + tarballs: { + 'bar@2.0.0': {}, + }, + diff: ['bar', 'bar@2.0.0'], + exec: [], }) - libnpmdiff = async ([a, b], opts) => { - t.equal( - a, - `bar@file:${resolve(path, 'node_modules/bar')}`, - 'should target local node_modules pkg' - ) - t.equal(b, 'bar@2.0.0', 'should set expected second spec') - } - - npm.prefix = path - config.diff = ['bar', 'bar@2.0.0'] - diff.exec([], err => { - if (err) { - throw err - } - }) + t.match(output, 'bar') + t.match(output, /-\s*"version": "1\.0\.0"/) + t.match(output, /\+\s*"version": "2\.0\.0"/) }) - t.test('second arg is ALSO a known dependency', t => { - t.plan(2) - - const path = t.testdir({ - node_modules: { - bar: { - 'package.json': JSON.stringify({ - name: 'bar', - version: '1.0.0', - }), + t.test('second arg is ALSO a known dependency', async t => { + const { output } = await mockDiff(t, { + prefixDir: { + node_modules: { + bar: { + 'package.json': { + name: 'bar', + version: '1.0.0', + }, + }, + 'bar-fork': { + 'package.json': { + name: 'bar-fork', + version: '1.0.0', + }, + }, }, - 'bar-fork': { - 'package.json': JSON.stringify({ - name: 'bar-fork', - version: '1.0.0', - }), + 'package.json': { + name: 'my-project', + dependencies: { + bar: '^1.0.0', + }, }, }, - 'package.json': JSON.stringify({ - name: 'my-project', - dependencies: { - bar: '^1.0.0', - }, - }), + diff: ['bar', 'bar-fork'], + exec: [], }) - libnpmdiff = async ([a, b], opts) => { - t.equal( - a, - `bar@file:${resolve(path, 'node_modules/bar')}`, - 'should target local node_modules pkg' - ) - t.equal( - b, - `bar-fork@file:${resolve(path, 'node_modules/bar-fork')}`, - 'should target fork local node_modules pkg' - ) - } - - npm.prefix = path - config.diff = ['bar', 'bar-fork'] - diff.exec([], err => { - if (err) { - throw err - } - }) + t.match(output, /-\s*"name": "bar"/) + t.match(output, /\+\s*"name": "bar-fork"/) }) - t.test('second arg is a valid semver version', t => { - t.plan(2) - - const path = t.testdir({ - node_modules: { - bar: { - 'package.json': JSON.stringify({ - name: 'bar', - version: '1.0.0', - }), + t.test('second arg is a valid semver version', async t => { + const { output } = await mockDiff(t, { + prefixDir: { + node_modules: { + bar: { + 'package.json': { + name: 'bar', + version: '1.0.0', + }, + }, }, - }, - 'package.json': JSON.stringify({ - name: 'my-project', - dependencies: { - bar: '^1.0.0', + 'package.json': { + name: 'my-project', + dependencies: { + bar: '^1.0.0', + }, }, - }), + }, + tarballs: { + 'bar@2.0.0': {}, + }, + diff: ['bar', '2.0.0'], + exec: [], }) - libnpmdiff = async ([a, b], opts) => { - t.equal( - a, - `bar@file:${resolve(path, 'node_modules/bar')}`, - 'should target local node_modules pkg' - ) - t.equal(b, 'bar@2.0.0', 'should use package name from first arg') - } - - npm.prefix = path - config.diff = ['bar', '2.0.0'] - diff.exec([], err => { - if (err) { - throw err - } - }) + t.match(output, 'bar') + t.match(output, /-\s*"version": "1\.0\.0"/) + t.match(output, /\+\s*"version": "2\.0\.0"/) }) t.test('second arg is an unknown dependency name', async t => { - t.plan(2) - - const path = t.testdir({ - node_modules: { - bar: { - 'package.json': JSON.stringify({ - name: 'bar', - version: '1.0.0', - }), + const { output } = await mockDiff(t, { + prefixDir: { + node_modules: { + bar: { + 'package.json': { + name: 'bar', + version: '1.0.0', + }, + }, }, - }, - 'package.json': JSON.stringify({ - name: 'my-project', - dependencies: { - bar: '^1.0.0', + 'package.json': { + name: 'my-project', + dependencies: { + bar: '^1.0.0', + }, }, - }), + }, + tarballs: { + 'bar-fork@1.0.0': {}, + }, + diff: ['bar', 'bar-fork'], + exec: [], }) - libnpmdiff = async ([a, b], opts) => { - t.equal( - a, - `bar@file:${resolve(path, 'node_modules/bar')}`, - 'should target local node_modules pkg' - ) - t.equal(b, 'bar-fork@*', 'should set expected second spec') - } - - npm.prefix = path - config.diff = ['bar', 'bar-fork'] - await diff.exec([]) + t.match(output, /-\s*"name": "bar"/) + t.match(output, /\+\s*"name": "bar-fork"/) }) - - t.end() }) -t.test('first arg is a valid semver range', t => { +t.test('first arg is a valid semver range', async t => { t.test('second arg is a qualified spec', async t => { - t.plan(2) - - config.diff = ['1.0.0', 'bar@2.0.0'] - - libnpmdiff = async ([a, b], opts) => { - t.equal(a, 'bar@1.0.0', 'should use name from second arg') - t.equal(b, 'bar@2.0.0', 'should use expected spec') - } + const { output } = await mockDiff(t, { + tarballs: { + 'bar@1.0.0': {}, + 'bar@2.0.0': {}, + }, + diff: ['1.0.0', 'bar@2.0.0'], + times: { bar: 2 }, + exec: [], + }) - await diff.exec([]) + t.match(output, 'bar') + t.match(output, /-\s*"version": "1\.0\.0"/) + t.match(output, /\+\s*"version": "2\.0\.0"/) }) t.test('second arg is a known dependency', async t => { - t.plan(2) - - const path = t.testdir({ - node_modules: { - bar: { - 'package.json': JSON.stringify({ - name: 'bar', - version: '2.0.0', - }), + const { output } = await mockDiff(t, { + prefixDir: { + node_modules: { + bar: { + 'package.json': { + name: 'bar', + version: '2.0.0', + }, + }, }, - }, - 'package.json': JSON.stringify({ - name: 'my-project', - dependencies: { - bar: '^1.0.0', + 'package.json': { + name: 'my-project', + dependencies: { + bar: '^1.0.0', + }, }, - }), + }, + tarballs: { + 'bar@1.0.0': {}, + }, + diff: ['1.0.0', 'bar'], + exec: [], }) - libnpmdiff = async ([a, b], opts) => { - t.equal(a, 'bar@1.0.0', 'should use name from second arg') - t.equal( - b, - `bar@file:${resolve(path, 'node_modules/bar')}`, - 'should set expected second spec from nm' - ) - } - - npm.prefix = path - config.diff = ['1.0.0', 'bar'] - await diff.exec([]) + t.match(output, 'bar') + t.match(output, /-\s*"version": "1\.0\.0"/) + t.match(output, /\+\s*"version": "2\.0\.0"/) }) t.test('second arg is ALSO a semver version', async t => { - t.plan(2) - - libnpmdiff = async ([a, b], opts) => { - t.equal(a, 'foo@1.0.0', 'should use name from project dir') - t.equal(b, 'foo@2.0.0', 'should use name from project dir') - } + const { output } = await mockDiff(t, { + prefixDir: { + 'package.json': { + name: 'bar', + }, + }, + tarballs: { + 'bar@1.0.0': {}, + 'bar@2.0.0': {}, + }, + diff: ['1.0.0', '2.0.0'], + times: { bar: 2 }, + exec: [], + }) - config.diff = ['1.0.0', '2.0.0'] - await diff.exec([]) + t.match(output, 'bar') + t.match(output, /-\s*"version": "1\.0\.0"/) + t.match(output, /\+\s*"version": "2\.0\.0"/) }) t.test('second arg is ALSO a semver version BUT cwd not a project dir', async t => { - const path = t.testdir({}) - config.diff = ['1.0.0', '2.0.0'] - npm.prefix = path + const p = mockDiff(t, { + diff: ['1.0.0', '2.0.0'], + exec: [], + }) await t.rejects( - diff.exec([]), + p, /Needs to be run from a project dir in order to diff two versions./, 'should throw two versions need project dir error usage msg' ) }) t.test('second arg is an unknown dependency name', async t => { - t.plan(2) - - libnpmdiff = async ([a, b], opts) => { - t.equal(a, 'bar@1.0.0', 'should use name from second arg') - t.equal(b, 'bar@*', 'should compare against any version') - } + const { output } = await mockDiff(t, { + prefixDir: { + prefixDir: { + 'package.json': { + name: 'bar', + }, + }, + }, + tarballs: { + 'bar@1.0.0': {}, + 'bar@2.0.0': {}, + }, + diff: ['1.0.0', 'bar'], + times: { bar: 2 }, + exec: [], + }) - config.diff = ['1.0.0', 'bar'] - await diff.exec([]) + t.match(output, 'bar') + t.match(output, /-\s*"version": "1\.0\.0"/) + t.match(output, /\+\s*"version": "2\.0\.0"/) }) t.test('second arg is a qualified spec, missing actual tree', async t => { - t.plan(2) - - const path = t.testdir({ - 'package.json': JSON.stringify({ - name: 'my-project', - }), - }) - - const Diff = t.mock('../../../lib/commands/diff.js', { - ...mocks, - '@npmcli/arborist': class { - constructor () { - throw new Error('ERR') - } + const { output } = await mockDiff(t, { + prefixDir: { + 'package.json': { + name: 'lorem', + version: '2.0.0', + }, }, - libnpmdiff: async ([a, b], opts) => { - t.equal(a, 'lorem@1.0.0', 'should target latest version of pkg name') - t.equal(b, 'lorem@2.0.0', 'should target expected spec') + mocks: { + '@npmcli/arborist': class { + constructor () { + throw new Error('ERR') + } + }, + }, + tarballs: { + 'lorem@1.0.0': {}, + 'lorem@2.0.0': {}, }, + times: { lorem: 2 }, + diff: ['1.0.0', 'lorem@2.0.0'], + exec: [], }) - const diff = new Diff(npm) - - config.diff = ['1.0.0', 'lorem@2.0.0'] - npm.prefix = path - await diff.exec([]) + t.match(output, 'lorem') + t.match(output, /-\s*"version": "1\.0\.0"/) + t.match(output, /\+\s*"version": "2\.0\.0"/) }) - - t.end() }) -t.test('first arg is an unknown dependency name', t => { - t.test('second arg is a qualified spec', t => { - t.plan(4) - - libnpmdiff = async ([a, b], opts) => { - t.equal(a, 'bar@*', 'should set expected first spec') - t.equal(b, 'bar@2.0.0', 'should set expected second spec') - t.match(opts, npm.flatOptions, 'should forward flat options') - t.match(opts, { where: fooPath }, 'should forward pacote options') - } - - config.diff = ['bar', 'bar@2.0.0'] - diff.exec([], err => { - if (err) { - throw err - } +t.test('first arg is an unknown dependency name', async t => { + t.test('second arg is a qualified spec', async t => { + const { output } = await mockDiff(t, { + tarballs: { + 'bar@2.0.0': {}, + 'bar@3.0.0': {}, + }, + times: { bar: 2 }, + diff: ['bar', 'bar@2.0.0'], + exec: [], }) - }) - t.test('second arg is a known dependency', t => { - t.plan(2) + t.match(output, 'bar') + t.match(output, /-\s*"version": "3\.0\.0"/) + t.match(output, /\+\s*"version": "2\.0\.0"/) + }) - const path = t.testdir({ - node_modules: { - bar: { - 'package.json': JSON.stringify({ - name: 'bar', - version: '2.0.0', - }), + t.test('second arg is a known dependency', async t => { + const { output } = await mockDiff(t, { + prefixDir: { + node_modules: { + bar: { + 'package.json': { + name: 'bar', + version: '2.0.0', + }, + }, }, - }, - 'package.json': JSON.stringify({ - name: 'my-project', - dependencies: { - bar: '^1.0.0', + 'package.json': { + name: 'my-project', + dependencies: { + bar: '^1.0.0', + }, }, - }), + }, + tarballs: { + 'bar-fork@2.0.0': {}, + }, + diff: ['bar-fork', 'bar'], + exec: [], }) - libnpmdiff = async ([a, b], opts) => { - t.equal(a, 'bar-fork@*', 'should use any version') - t.equal( - b, - `bar@file:${resolve(path, 'node_modules/bar')}`, - 'should target local node_modules pkg' - ) - } - - npm.prefix = path - config.diff = ['bar-fork', 'bar'] - diff.exec([], err => { - if (err) { - throw err - } - }) + t.match(output, /-\s*"name": "bar-fork"/) + t.match(output, /\+\s*"name": "bar"/) }) - t.test('second arg is a valid semver version', t => { - t.plan(2) - - libnpmdiff = async ([a, b], opts) => { - t.equal(a, 'bar@*', 'should use any version') - t.equal(b, 'bar@^1.0.0', 'should use name from first arg') - } - - config.diff = ['bar', '^1.0.0'] - diff.exec([], err => { - if (err) { - throw err - } - }) - }) - - t.test('second arg is ALSO an unknown dependency name', t => { - t.plan(2) - - libnpmdiff = async ([a, b], opts) => { - t.equal(a, 'bar@*', 'should use any version') - t.equal(b, 'bar-fork@*', 'should use any version') - } - - config.diff = ['bar', 'bar-fork'] - diff.exec([], err => { - if (err) { - throw err - } + t.test('second arg is a valid semver version', async t => { + const { output } = await mockDiff(t, { + tarballs: { + 'bar@1.5.0': {}, + 'bar@2.0.0': {}, + }, + times: { bar: 2 }, + diff: ['bar', '^1.0.0'], + exec: [], }) - }) - - t.test('cwd not a project dir', t => { - t.plan(2) - const path = t.testdir({}) - libnpmdiff = async ([a, b], opts) => { - t.equal(a, 'bar@*', 'should use any version') - t.equal(b, 'bar-fork@*', 'should use any version') - } - - config.diff = ['bar', 'bar-fork'] - npm.prefix = path - - diff.exec([], err => { - if (err) { - throw err - } - }) + t.match(output, 'bar') + t.match(output, /-\s*"version": "2\.0\.0"/) + t.match(output, /\+\s*"version": "1\.5\.0"/) }) - t.end() -}) - -t.test('various options', t => { - t.test('using --name-only option', async t => { - t.plan(1) - - flatOptions.diffNameOnly = true - - libnpmdiff = async ([a, b], opts) => { - t.match( - opts, - { - ...npm.flatOptions, - diffNameOnly: true, + t.test('second arg is ALSO an unknown dependency name', async t => { + const { output } = await mockDiff(t, { + prefixDir: { + 'package.json': { + name: 'my-project', }, - 'should forward nameOnly=true option' - ) - } + }, + tarballs: { + 'bar@1.0.0': {}, + 'bar-fork@1.0.0': {}, + }, + diff: ['bar', 'bar-fork'], + exec: [], + }) - await diff.exec([]) + t.match(output, /-\s*"name": "bar"/) + t.match(output, /\+\s*"name": "bar-fork"/) }) - t.test('set files after both versions', async t => { - t.plan(3) - - config.diff = ['2.1.4', '3.0.0'] - - libnpmdiff = async ([a, b], opts) => { - t.equal(a, 'foo@2.1.4', 'should use expected spec') - t.equal(b, 'foo@3.0.0', 'should use expected spec') - t.match( - opts, - { - ...npm.flatOptions, - diffFiles: ['./foo.js', './bar.js'], - }, - 'should forward diffFiles values' - ) - } + t.test('cwd not a project dir', async t => { + const { output } = await mockDiff(t, { + tarballs: { + 'bar@1.0.0': {}, + 'bar-fork@1.0.0': {}, + }, + diff: ['bar', 'bar-fork'], + exec: [], + }) - await diff.exec(['./foo.js', './bar.js']) + t.match(output, /-\s*"name": "bar"/) + t.match(output, /\+\s*"name": "bar-fork"/) }) +}) - t.test('set files no diff args', async t => { - t.plan(3) - - libnpmdiff = async ([a, b], opts) => { - t.equal(a, 'foo@latest', 'should have default spec') - t.equal(b, `file:${fooPath}`, 'should compare to cwd') - t.match( - opts, - { - ...npm.flatOptions, - diffFiles: ['./foo.js', './bar.js'], - }, - 'should forward all remaining items as filenames' - ) - } +t.test('various options', async t => { + const mockOptions = async (t, config) => { + const file = (v) => new Array(50).fill(0).map((_, i) => `${i}${i === 20 ? v : ''}`).join('\n') + const mock = await mockDiff(t, { + diff: ['bar@2.0.0', 'bar@3.0.0'], + config, + exec: [], + tarballs: { + 'bar@2.0.0': { 'index.js': file('2.0.0') }, + 'bar@3.0.0': { 'index.js': file('3.0.0') }, + }, + times: { bar: 2 }, + }) + + return mock + } - await diff.exec(['./foo.js', './bar.js']) + t.test('using --name-only option', async t => { + const { output } = await mockOptions(t, { + 'diff-name-only': true, + }) + t.matchSnapshot(output) }) t.test('using diff option', async t => { - t.plan(1) - - flatOptions.diffContext = 5 - flatOptions.diffIgnoreWhitespace = true - flatOptions.diffNoPrefix = false - flatOptions.diffSrcPrefix = 'foo/' - flatOptions.diffDstPrefix = 'bar/' - flatOptions.diffText = true - - libnpmdiff = async ([a, b], opts) => { - t.match( - opts, - { - ...npm.flatOptions, - diffContext: 5, - diffIgnoreWhitespace: true, - diffNoPrefix: false, - diffSrcPrefix: 'foo/', - diffDstPrefix: 'bar/', - diffText: true, - }, - 'should forward diff options' - ) - } + const { output } = await mockOptions(t, { + 'diff-context': 5, + 'diff-ignore-whitespace': true, + 'diff-no-prefix': false, + 'diff-drc-prefix': 'foo/', + 'diff-fst-prefix': 'bar/', + 'diff-text': true, - await diff.exec([]) + }) + t.matchSnapshot(output) }) - - t.end() }) t.test('too many args', async t => { - config.diff = ['a', 'b', 'c'] + const { npm } = await mockDiff(t, { + diff: ['a', 'b', 'c'], + }) + await t.rejects( - diff.exec([]), + npm.exec('diff', []), /Can't use more than two --diff arguments./, 'should throw usage error' ) }) -t.test('workspaces', t => { - const path = t.testdir({ - 'package.json': JSON.stringify({ - name: 'workspaces-test', - version: '1.2.3-test', - workspaces: ['workspace-a', 'workspace-b', 'workspace-c'], - }), - 'workspace-a': { - 'package.json': JSON.stringify({ - name: 'workspace-a', - version: '1.2.3-a', - }), - }, - 'workspace-b': { - 'package.json': JSON.stringify({ - name: 'workspace-b', - version: '1.2.3-b', - }), - }, - 'workspace-c': JSON.stringify({ +t.test('workspaces', async t => { + const mockWorkspaces = (t, workspaces = true, opts) => mockDiff(t, { + prefixDir: { 'package.json': { - name: 'workspace-n', - version: '1.2.3-n', + name: 'workspaces-test', + version: '1.2.3', + workspaces: ['workspace-a', 'workspace-b', 'workspace-c'], }, - }), + 'workspace-a': { + 'package.json': { + name: 'workspace-a', + version: '1.2.3-a', + }, + }, + 'workspace-b': { + 'package.json': { + name: 'workspace-b', + version: '1.2.3-b', + }, + }, + 'workspace-c': { + 'package.json': { + name: 'workspace-c', + version: '1.2.3-c', + }, + }, + }, + exec: [], + config: workspaces === true ? { workspaces } : { workspace: workspaces }, + ...opts, }) t.test('all workspaces', async t => { - const diffCalls = [] - libnpmdiff = async ([a, b]) => { - diffCalls.push([a, b]) - } - npm.prefix = path - npm.localPrefix = path - await diff.execWorkspaces([], []) - t.same( - diffCalls, - [ - ['workspace-a@latest', join(`file:${path}`, 'workspace-a')], - ['workspace-b@latest', join(`file:${path}`, 'workspace-b')], - ], - 'should call libnpmdiff with workspaces params' - ) + const { output } = await mockWorkspaces(t, true, { + tarballs: { + 'workspace-a@2.0.0-a': {}, + 'workspace-b@2.0.0-b': {}, + 'workspace-c@2.0.0-c': {}, + }, + }) + + t.match(output, '"name": "workspace-a"') + t.match(output, /-\s*"version": "2\.0\.0-a"/) + t.match(output, /\+\s*"version": "1\.2\.3-a"/) + + t.match(output, '"name": "workspace-b"') + t.match(output, /-\s*"version": "2\.0\.0-b"/) + t.match(output, /\+\s*"version": "1\.2\.3-b"/) + + t.match(output, '"name": "workspace-c"') + t.match(output, /-\s*"version": "2\.0\.0-c"/) + t.match(output, /\+\s*"version": "1\.2\.3-c"/) }) t.test('one workspace', async t => { - const diffCalls = [] - libnpmdiff = async ([a, b]) => { - diffCalls.push([a, b]) - } - npm.prefix = path - npm.localPrefix = path - await diff.execWorkspaces([], ['workspace-a']) - t.same( - diffCalls, - [['workspace-a@latest', join(`file:${path}`, 'workspace-a')]], - 'should call libnpmdiff with workspaces params' - ) + const { output } = await mockWorkspaces(t, 'workspace-a', { + tarballs: { + 'workspace-a@2.0.0-a': {}, + }, + }) + + t.match(output, '"name": "workspace-a"') + t.match(output, /-\s*"version": "2\.0\.0-a"/) + t.match(output, /\+\s*"version": "1\.2\.3-a"/) + + t.notMatch(output, '"name": "workspace-b"') + t.notMatch(output, '"name": "workspace-c"') }) t.test('invalid workspace', async t => { - libnpmdiff = () => { - t.fail('should not call libnpmdiff') - } - npm.prefix = path - npm.localPrefix = path - await t.rejects(diff.execWorkspaces([], ['workspace-x']), /No workspaces found/) - await t.rejects(diff.execWorkspaces([], ['workspace-x']), /workspace-x/) + const p = mockWorkspaces(t, 'workspace-x') + await t.rejects(p, /No workspaces found/) + await t.rejects(p, /workspace-x/) }) - t.end() }) diff --git a/deps/npm/test/lib/commands/dist-tag.js b/deps/npm/test/lib/commands/dist-tag.js index 464f5bc9392d80..4cc241f74582d1 100644 --- a/deps/npm/test/lib/commands/dist-tag.js +++ b/deps/npm/test/lib/commands/dist-tag.js @@ -1,15 +1,36 @@ const t = require('tap') -const { fake: mockNpm } = require('../../fixtures/mock-npm') +const realFetch = require('npm-registry-fetch') +const mockNpm = require('../../fixtures/mock-npm') -let result = '' -let log = '' - -t.afterEach(() => { - result = '' - log = '' -}) +const fixtures = { + workspace: { + 'package.json': JSON.stringify({ + name: 'root', + version: '1.0.0', + workspaces: ['workspace-a', 'workspace-b', 'workspace-c'], + }), + 'workspace-a': { + 'package.json': JSON.stringify({ + name: 'workspace-a', + version: '1.0.0', + }), + }, + 'workspace-b': { + 'package.json': JSON.stringify({ + name: 'workspace-b', + version: '1.0.0', + }), + }, + 'workspace-c': { + 'package.json': JSON.stringify({ + name: 'workspace-c', + version: '1.0.0', + }), + }, + }, +} -const routeMap = { +const tags = { '/-/package/@scoped%2fpkg/dist-tags': { latest: '1.0.0', a: '0.0.1', @@ -40,67 +61,70 @@ const routeMap = { }, } -// XXX overriding this does not appear to do anything, adding t.plan to things -// that use it fails the test -let npmRegistryFetchMock = (url, opts) => { - if (url === '/-/package/foo/dist-tags') { - throw new Error('no package found') - } +const mockDist = async (t, { ...npmOpts } = {}) => { + const getTag = async (url) => ({ ...tags })[url] - return routeMap[url] -} + let fetchOpts + const nrf = async (url, opts) => { + fetchOpts = opts -npmRegistryFetchMock.json = async (url, opts) => { - return routeMap[url] -} + if (url === '/-/package/foo/dist-tags') { + throw new Error('no package found') + } -const logger = (...msgs) => { - for (const msg of [...msgs]) { - log += msg + ' ' + return getTag(url) } - log += '\n' -} + const mock = await mockNpm(t, { + ...npmOpts, + mocks: { + 'npm-registry-fetch': Object.assign(nrf, realFetch, { json: getTag }), + }, + }) -const DistTag = t.mock('../../../lib/commands/dist-tag.js', { - 'proc-log': { - error: logger, - info: logger, - verbose: logger, - warn: logger, - }, - get 'npm-registry-fetch' () { - return npmRegistryFetchMock - }, -}) + const usage = await mock.npm.cmd('dist-tag').then(c => c.usage) -const config = {} -const npm = mockNpm({ - config, - output: msg => { - result = result ? [result, msg].join('\n') : msg - }, -}) -const distTag = new DistTag(npm) + return { + ...mock, + distTag: { + exec: (args) => mock.npm.exec('dist-tag', args), + usage, + completion: (remain) => mock.npm.cmd('dist-tag').then(c => c.completion({ + conf: { argv: { remain } }, + })), + }, + fetchOpts: () => fetchOpts, + result: () => mock.joinedOutput(), + logs: () => { + const distLogs = mock.logs.filter(l => l[1].startsWith('dist-tag')) + return distLogs.map(([, ...parts]) => { + return parts.map(p => p.toString()).join(' ').trim() + }).join('\n').trim() + }, + } +} t.test('ls in current package', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: '@scoped/pkg', - }), + const { distTag, result } = await mockDist(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: '@scoped/pkg', + }), + }, }) await distTag.exec(['ls']) t.matchSnapshot( - result, + result(), 'should list available tags for current package' ) }) t.test('ls global', async t => { - t.teardown(() => { - config.global = false + const { distTag } = await mockDist(t, { + config: { + global: true, + }, }) - config.global = true await t.rejects( distTag.exec(['ls']), distTag.usage, @@ -109,20 +133,22 @@ t.test('ls global', async t => { }) t.test('no args in current package', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: '@scoped/pkg', - }), + const { distTag, result } = await mockDist(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: '@scoped/pkg', + }), + }, }) await distTag.exec([]) t.matchSnapshot( - result, + result(), 'should default to listing available tags for current package' ) }) t.test('borked cmd usage', async t => { - npm.prefix = t.testdir({}) + const { distTag } = await mockDist(t) await t.rejects( distTag.exec(['borked', '@scoped/pkg']), distTag.usage, @@ -131,31 +157,33 @@ t.test('borked cmd usage', async t => { }) t.test('ls on named package', async t => { - npm.prefix = t.testdir({}) + const { distTag, result } = await mockDist(t) await distTag.exec(['ls', '@scoped/another']) t.matchSnapshot( - result, + result(), 'should list tags for the specified package' ) }) t.test('ls on missing package', async t => { - npm.prefix = t.testdir({}) + const { distTag, logs } = await mockDist(t) await t.rejects( distTag.exec(['ls', 'foo']), distTag.usage ) t.matchSnapshot( - log, + logs(), 'should log no dist-tag found msg' ) }) t.test('ls on missing name in current package', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - version: '1.0.0', - }), + const { distTag } = await mockDist(t, { + prefixDir: { + 'package.json': JSON.stringify({ + version: '1.0.0', + }), + }, }) await t.rejects( distTag.exec(['ls']), @@ -165,107 +193,78 @@ t.test('ls on missing name in current package', async t => { }) t.test('only named package arg', async t => { - npm.prefix = t.testdir({}) + const { distTag, result } = await mockDist(t) await distTag.exec(['@scoped/another']) t.matchSnapshot( - result, + result(), 'should default to listing tags for the specified package' ) }) -t.test('workspaces', t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'root', - version: '1.0.0', - workspaces: ['workspace-a', 'workspace-b', 'workspace-c'], - }), - 'workspace-a': { - 'package.json': JSON.stringify({ - name: 'workspace-a', - version: '1.0.0', - }), - }, - 'workspace-b': { - 'package.json': JSON.stringify({ - name: 'workspace-b', - version: '1.0.0', - }), - }, - 'workspace-c': { - 'package.json': JSON.stringify({ - name: 'workspace-c', - version: '1.0.0', - }), - }, - }) +t.test('workspaces', async t => { + const mockWorkspaces = async (t, exec = [], workspaces = true, prefixDir = {}) => { + const mock = await mockDist(t, { + prefixDir: { + ...fixtures.workspace, + ...prefixDir, + }, + config: workspaces === true ? { workspaces } : { workspace: workspaces }, + }) + + await mock.distTag.exec(exec) + + return mock + } t.test('no args', async t => { - await distTag.execWorkspaces([], []) - t.matchSnapshot(result, 'printed the expected output') + const { result } = await mockWorkspaces(t) + t.matchSnapshot(result(), 'printed the expected output') }) t.test('no args, one workspace', async t => { - await distTag.execWorkspaces([], ['workspace-a']) - t.matchSnapshot(result, 'printed the expected output') + const { result } = await mockWorkspaces(t, [], 'workspace-a') + t.matchSnapshot(result(), 'printed the expected output') }) - t.test('one arg -- .', async t => { - await distTag.execWorkspaces(['.'], []) - t.matchSnapshot(result, 'printed the expected output') + t.test('one arg -- cwd', async t => { + const { result } = await mockWorkspaces(t, ['.']) + t.matchSnapshot(result(), 'printed the expected output') }) t.test('one arg -- .@1, ignores version spec', async t => { - await distTag.execWorkspaces(['.@'], []) - t.matchSnapshot(result, 'printed the expected output') + const { result } = await mockWorkspaces(t, ['.@']) + t.matchSnapshot(result(), 'printed the expected output') }) t.test('one arg -- list', async t => { - await distTag.execWorkspaces(['list'], []) - t.matchSnapshot(result, 'printed the expected output') + const { result } = await mockWorkspaces(t, ['list']) + t.matchSnapshot(result(), 'printed the expected output') }) - t.test('two args -- list, .', async t => { - await distTag.execWorkspaces(['list', '.'], []) - t.matchSnapshot(result, 'printed the expected output') + t.test('two args -- list, cwd', async t => { + const { result } = await mockWorkspaces(t, ['list', '.']) + t.matchSnapshot(result(), 'printed the expected output') }) t.test('two args -- list, .@1, ignores version spec', async t => { - await distTag.execWorkspaces(['list', '.@'], []) - t.matchSnapshot(result, 'printed the expected output') + const { result } = await mockWorkspaces(t, ['list', '.@']) + t.matchSnapshot(result(), 'printed the expected output') }) t.test('two args -- list, @scoped/pkg, logs a warning and ignores workspaces', async t => { - await distTag.execWorkspaces(['list', '@scoped/pkg'], []) - t.match(log, 'Ignoring workspaces for specified package', 'logs a warning') - t.matchSnapshot(result, 'printed the expected output') + const { result, logs } = await mockWorkspaces(t, ['list', '@scoped/pkg']) + t.match(logs(), 'Ignoring workspaces for specified package', 'logs a warning') + t.matchSnapshot(result(), 'printed the expected output') }) t.test('no args, one failing workspace sets exitCode to 1', async t => { - npm.localPrefix = t.testdir({ + const { result, logs } = await mockWorkspaces(t, [], true, { 'package.json': JSON.stringify({ name: 'root', version: '1.0.0', workspaces: ['workspace-a', 'workspace-b', 'workspace-c', 'workspace-d'], }), - 'workspace-a': { - 'package.json': JSON.stringify({ - name: 'workspace-a', - version: '1.0.0', - }), - }, - 'workspace-b': { - 'package.json': JSON.stringify({ - name: 'workspace-b', - version: '1.0.0', - }), - }, - 'workspace-c': { - 'package.json': JSON.stringify({ - name: 'workspace-c', - version: '1.0.0', - }), - }, + 'workspace-d': { 'package.json': JSON.stringify({ name: 'workspace-d', @@ -274,52 +273,41 @@ t.test('workspaces', t => { }, }) - await distTag.execWorkspaces([], []) - t.equal(process.exitCode, 1, 'set the error status') - process.exitCode = 0 - t.match(log, 'dist-tag ls Couldn\'t get dist-tag data for workspace-d@*', 'logs the error') - t.matchSnapshot(result, 'printed the expected output') + t.match(logs(), 'dist-tag ls Couldn\'t get dist-tag data for workspace-d@*', 'logs the error') + t.matchSnapshot(result(), 'printed the expected output') }) - - t.end() }) t.test('add new tag', async t => { - const _nrf = npmRegistryFetchMock - t.teardown(() => { - npmRegistryFetchMock = _nrf - }) - - npmRegistryFetchMock = async (url, opts) => { - t.equal(opts.method, 'PUT', 'should trigger request to add new tag') - t.equal(opts.body, '7.7.7', 'should point to expected version') - } - npm.prefix = t.testdir({}) + const { distTag, result, fetchOpts } = await mockDist(t) await distTag.exec(['add', '@scoped/another@7.7.7', 'c']) + const opts = fetchOpts() + t.equal(opts.method, 'PUT', 'should trigger request to add new tag') + t.equal(opts.body, '"7.7.7"', 'should point to expected version') t.matchSnapshot( - result, + result(), 'should return success msg' ) }) t.test('add using valid semver range as name', async t => { - npm.prefix = t.testdir({}) + const { distTag, logs } = await mockDist(t) await t.rejects( distTag.exec(['add', '@scoped/another@7.7.7', '1.0.0']), /Tag name must not be a valid SemVer range: 1.0.0/, 'should exit with semver range error' ) t.matchSnapshot( - log, + logs(), 'should return success msg' ) }) t.test('add missing args', async t => { - npm.prefix = t.testdir({}) - config.tag = '' - t.teardown(() => { - delete config.tag + const { distTag } = await mockDist(t, { + config: { + tag: '', + }, }) await t.rejects( distTag.exec(['add', '@scoped/another@7.7.7']), @@ -329,7 +317,7 @@ t.test('add missing args', async t => { }) t.test('add missing pkg name', async t => { - npm.prefix = t.testdir({}) + const { distTag } = await mockDist(t) await t.rejects( distTag.exec(['add', null]), distTag.usage, @@ -338,41 +326,35 @@ t.test('add missing pkg name', async t => { }) t.test('set existing version', async t => { - npm.prefix = t.testdir({}) + const { distTag, logs } = await mockDist(t) await distTag.exec(['set', '@scoped/another@0.6.0', 'b']) t.matchSnapshot( - log, + logs(), 'should log warn msg' ) }) t.test('remove existing tag', async t => { - const _nrf = npmRegistryFetchMock - t.teardown(() => { - npmRegistryFetchMock = _nrf - }) - - npmRegistryFetchMock = async (url, opts) => { - t.equal(opts.method, 'DELETE', 'should trigger request to remove tag') - } - npm.prefix = t.testdir({}) + const { distTag, result, logs, fetchOpts } = await mockDist(t) await distTag.exec(['rm', '@scoped/another', 'c']) - t.matchSnapshot(log, 'should log remove info') - t.matchSnapshot(result, 'should return success msg') + const opts = fetchOpts() + t.equal(opts.method, 'DELETE', 'should trigger request to remove tag') + t.matchSnapshot(logs(), 'should log remove info') + t.matchSnapshot(result(), 'should return success msg') }) t.test('remove non-existing tag', async t => { - npm.prefix = t.testdir({}) + const { distTag, logs } = await mockDist(t) await t.rejects( distTag.exec(['rm', '@scoped/another', 'nonexistent']), /nonexistent is not a dist-tag on @scoped\/another/, 'should exit with error' ) - t.matchSnapshot(log, 'should log error msg') + t.matchSnapshot(logs(), 'should log error msg') }) t.test('remove missing pkg name', async t => { - npm.prefix = t.testdir({}) + const { distTag } = await mockDist(t) await t.rejects( distTag.exec(['rm', null]), distTag.usage, @@ -381,14 +363,12 @@ t.test('remove missing pkg name', async t => { }) t.test('completion', async t => { - const { completion } = distTag - t.plan(2) + const { distTag } = await mockDist(t) - const match = completion({ conf: { argv: { remain: ['npm', 'dist-tag'] } } }) + const match = distTag.completion(['npm', 'dist-tag']) t.resolveMatch(match, ['add', 'rm', 'ls'], 'should list npm dist-tag commands for completion') - const noMatch = completion({ conf: { argv: { remain: ['npm', 'dist-tag', 'foobar'] } } }) + const noMatch = distTag.completion(['npm', 'dist-tag', 'foobar']) t.resolveMatch(noMatch, []) - t.end() }) diff --git a/deps/npm/test/lib/commands/docs.js b/deps/npm/test/lib/commands/docs.js index b2a65786bf4d8e..e11df6b07bc5e6 100644 --- a/deps/npm/test/lib/commands/docs.js +++ b/deps/npm/test/lib/commands/docs.js @@ -1,46 +1,48 @@ const t = require('tap') -const { fake: mockNpm } = require('../../fixtures/mock-npm.js') -const { join, sep } = require('path') +const mockNpm = require('../../fixtures/mock-npm.js') +const { sep } = require('path') -const pkgDirs = t.testdir({ - 'package.json': JSON.stringify({ - name: 'thispkg', - version: '1.2.3', - homepage: 'https://example.com', - }), - nodocs: { +const fixtures = { + pkg: { 'package.json': JSON.stringify({ - name: 'nodocs', + name: 'thispkg', version: '1.2.3', + homepage: 'https://example.com', }), - }, - docsurl: { - 'package.json': JSON.stringify({ - name: 'docsurl', - version: '1.2.3', - homepage: 'https://bugzilla.localhost/docsurl', - }), - }, - repourl: { - 'package.json': JSON.stringify({ - name: 'repourl', - version: '1.2.3', - repository: 'https://github.com/foo/repourl', - }), - }, - repoobj: { - 'package.json': JSON.stringify({ - name: 'repoobj', - version: '1.2.3', - repository: { url: 'https://github.com/foo/repoobj' }, - }), - }, - repourlobj: { - 'package.json': JSON.stringify({ - name: 'repourlobj', - version: '1.2.3', - repository: { url: { works: false } }, - }), + nodocs: { + 'package.json': JSON.stringify({ + name: 'nodocs', + version: '1.2.3', + }), + }, + docsurl: { + 'package.json': JSON.stringify({ + name: 'docsurl', + version: '1.2.3', + homepage: 'https://bugzilla.localhost/docsurl', + }), + }, + repourl: { + 'package.json': JSON.stringify({ + name: 'repourl', + version: '1.2.3', + repository: 'https://github.com/foo/repourl', + }), + }, + repoobj: { + 'package.json': JSON.stringify({ + name: 'repoobj', + version: '1.2.3', + repository: { url: 'https://github.com/foo/repoobj' }, + }), + }, + repourlobj: { + 'package.json': JSON.stringify({ + name: 'repourlobj', + version: '1.2.3', + repository: { url: { works: false } }, + }), + }, }, workspaces: { 'package.json': JSON.stringify({ @@ -69,26 +71,31 @@ const pkgDirs = t.testdir({ }, }), }, -}) - -// keep a tally of which urls got opened -let opened = {} -const openUrl = async (npm, url, errMsg) => { - opened[url] = opened[url] || 0 - opened[url]++ } -const Docs = t.mock('../../../lib/commands/docs.js', { - '../../../lib/utils/open-url.js': openUrl, -}) -const flatOptions = {} -const npm = mockNpm({ flatOptions }) -const docs = new Docs(npm) +const setup = async (t, { prefixDir = fixtures.pkg, config } = {}) => { + // keep a tally of which urls got opened + const opened = {} + const openUrl = async (_, url) => { + opened[url] = opened[url] || 0 + opened[url]++ + } -t.afterEach(() => opened = {}) + const res = await mockNpm(t, { + prefixDir, + mocks: { + '{LIB}/utils/open-url.js': openUrl, + }, + config, + }) + + return { + ...res, + opened, + } +} -t.test('open docs urls', t => { - npm.localPrefix = pkgDirs +t.test('open docs urls', async t => { const expect = { nodocs: 'https://www.npmjs.com/package/nodocs', docsurl: 'https://bugzilla.localhost/docsurl', @@ -97,51 +104,60 @@ t.test('open docs urls', t => { repourlobj: 'https://www.npmjs.com/package/repourlobj', '.': 'https://example.com', } - const keys = Object.keys(expect) - t.plan(keys.length) - keys.forEach(pkg => { - t.test(pkg, async t => { - await docs.exec([['.', pkg].join(sep)]) - const url = expect[pkg] - t.match({ - [url]: 1, - }, opened, `opened ${url}`, { opened }) + + for (const [key, url] of Object.entries(expect)) { + await t.test(`open ${key} url`, async t => { + const { npm, opened } = await setup(t) + await npm.exec('docs', [['.', key].join(sep)]) + t.strictSame({ [url]: 1 }, opened, `opened ${url}`) }) - }) + } }) t.test('open default package if none specified', async t => { - await docs.exec([]) - t.equal(opened['https://example.com'], 1, 'opened expected url', { opened }) + const { npm, opened } = await setup(t) + + await npm.exec('docs', []) + t.strictSame({ 'https://example.com': 1 }, opened, 'opened expected url') }) -t.test('workspaces', (t) => { - npm.localPrefix = join(pkgDirs, 'workspaces') - t.test('all workspaces', async t => { - await docs.execWorkspaces([], []) - t.match({ +t.test('workspaces', async (t) => { + await t.test('all workspaces', async t => { + const { npm, opened } = await setup(t, { + prefixDir: fixtures.workspaces, + config: { workspaces: true }, + }) + await npm.exec('docs', []) + t.strictSame({ 'http://docs.workspace-a/': 1, 'https://github.com/npm/workspace-b#readme': 1, }, opened, 'opened two valid docs urls') }) - t.test('one workspace', async t => { - await docs.execWorkspaces([], ['workspace-a']) - t.match({ + await t.test('one workspace', async t => { + const { npm, opened } = await setup(t, { + prefixDir: fixtures.workspaces, + config: { workspace: 'workspace-a' }, + }) + await npm.exec('docs', []) + t.strictSame({ 'http://docs.workspace-a/': 1, }, opened, 'opened one requested docs urls') }) - t.test('invalid workspace', async t => { + await t.test('invalid workspace', async t => { + const { npm, opened } = await setup(t, { + prefixDir: fixtures.workspaces, + config: { workspace: 'workspace-x' }, + }) await t.rejects( - docs.execWorkspaces([], ['workspace-x']), + npm.exec('docs', []), /No workspaces found/ ) await t.rejects( - docs.execWorkspaces([], ['workspace-x']), + npm.exec('docs', []), /workspace-x/ ) t.match({}, opened, 'opened no docs urls') }) - t.end() }) diff --git a/deps/npm/test/lib/commands/doctor.js b/deps/npm/test/lib/commands/doctor.js index a4602183e69383..d1a88299e69ae9 100644 --- a/deps/npm/test/lib/commands/doctor.js +++ b/deps/npm/test/lib/commands/doctor.js @@ -46,10 +46,7 @@ const dirs = { }, globalPrefixDir: { bin: {}, - lib: { - node_modules: { - }, - }, + node_modules: {}, }, } @@ -57,26 +54,25 @@ const globals = ({ globalPrefix }) => { return { process: { 'env.PATH': `${globalPrefix}:${path.join(globalPrefix, 'bin')}`, - platform: 'test-not-windows', version: 'v1.0.0', }, } } -// getuid and getgid do not exist in windows, so we shim them -// to return 0, as that is the value that lstat will assign the -// gid and uid properties for fs.Stats objects -if (process.platform === 'win32') { - mockGlobals(t, { - process: { - getuid: () => 0, - getgid: () => 0, - }, - }) -} +mockGlobals(t, { + process: { + // set platform to not-windows before any tests because mockNpm + // sets the platform specific location of node_modules based on it + platform: 'test-not-windows', + // getuid and getgid do not exist in windows, so we shim them + // to return 0, as that is the value that lstat will assign the + // gid and uid properties for fs.Stats objects + ...(process.platform === 'win32' ? { getuid: () => 0, getgid: () => 0 } : {}), + }, +}) const mocks = { - '../../package.json': { version: '1.0.0' }, + '{ROOT}/package.json': { version: '1.0.0' }, which: async () => '/path/to/git', cacache: { verify: () => { @@ -106,13 +102,15 @@ t.test('all clear in color', async t => { mocks, globals, ...dirs, + config: { + color: 'always', + }, }) tnock(t, npm.config.get('registry')) .get('/-/ping?write=true').reply(200, '{}') .get('/npm').reply(200, npmManifest(npm.version)) tnock(t, 'https://nodejs.org') .get('/dist/index.json').reply(200, nodeVersions) - npm.config.set('color', 'always') await npm.exec('doctor', []) t.matchSnapshot(joinedOutput(), 'everything is ok in color') t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') @@ -178,13 +176,15 @@ t.test('ping 404 in color', async t => { mocks, globals, ...dirs, + config: { + color: 'always', + }, }) tnock(t, npm.config.get('registry')) .get('/-/ping?write=true').reply(404, '{}') .get('/npm').reply(200, npmManifest(npm.version)) tnock(t, 'https://nodejs.org') .get('/dist/index.json').reply(200, nodeVersions) - npm.config.set('color', 'always') await t.rejects(npm.exec('doctor', [])) t.matchSnapshot(joinedOutput(), 'ping 404 in color') t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') @@ -247,7 +247,6 @@ t.test('node out of date - lts', async t => { ...g, process: { ...g.process, - platform: 'test-not-windows', version: 'v0.0.1', }, } @@ -358,6 +357,7 @@ t.test('missing global directories', async t => { mocks, globals, prefixDir: dirs.prefixDir, + globalPrefixDir: {}, }) tnock(t, npm.config.get('registry')) .get('/-/ping?write=true').reply(200, '{}') diff --git a/deps/npm/test/lib/commands/edit.js b/deps/npm/test/lib/commands/edit.js index dc7114892970d7..02621f1aef9825 100644 --- a/deps/npm/test/lib/commands/edit.js +++ b/deps/npm/test/lib/commands/edit.js @@ -9,7 +9,7 @@ const npmConfig = { config: { 'ignore-scripts': false, editor: 'testeditor', - scriptShell: process.platform === 'win32' ? process.env.COMSPEC : 'sh', + 'script-shell': process.platform === 'win32' ? process.env.COMSPEC : 'sh', }, prefixDir: { node_modules: { @@ -38,7 +38,7 @@ t.test('npm edit', async t => { const semverPath = path.resolve(npm.prefix, 'node_modules', 'semver') spawk.spawn('testeditor', [semverPath]) - const scriptShell = npm.config.get('scriptShell') + const scriptShell = npm.config.get('script-shell') const scriptArgs = isCmdRe.test(scriptShell) ? ['/d', '/s', '/c', 'testinstall'] : ['-c', 'testinstall'] @@ -54,7 +54,7 @@ t.test('rebuild failure', async t => { const semverPath = path.resolve(npm.prefix, 'node_modules', 'semver') spawk.spawn('testeditor', [semverPath]) - const scriptShell = npm.config.get('scriptShell') + const scriptShell = npm.config.get('script-shell') const scriptArgs = isCmdRe.test(scriptShell) ? ['/d', '/s', '/c', 'testinstall'] : ['-c', 'testinstall'] @@ -89,7 +89,7 @@ t.test('npm edit editor has flags', async t => { const semverPath = path.resolve(npm.prefix, 'node_modules', 'semver') spawk.spawn('testeditor', ['--flag', semverPath]) - const scriptShell = npm.config.get('scriptShell') + const scriptShell = npm.config.get('script-shell') const scriptArgs = isCmdRe.test(scriptShell) ? ['/d', '/s', '/c', 'testinstall'] : ['-c', 'testinstall'] diff --git a/deps/npm/test/lib/commands/exec.js b/deps/npm/test/lib/commands/exec.js index 1a03b1a2e6a5b4..2fd11f40379f1f 100644 --- a/deps/npm/test/lib/commands/exec.js +++ b/deps/npm/test/lib/commands/exec.js @@ -38,9 +38,6 @@ t.test('registry package', async t => { require('fs').writeFileSync('npm-exec-test-success', '')`, }, }, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), }) await registry.package({ @@ -75,9 +72,6 @@ t.test('--prefix', async t => { require('fs').writeFileSync('npm-exec-test-success', '')`, }, }, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), }) // This is what `--prefix` does @@ -125,9 +119,6 @@ t.test('workspaces', async t => { }), }, }, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), }) await registry.package({ manifest, diff --git a/deps/npm/test/lib/commands/explain.js b/deps/npm/test/lib/commands/explain.js index 71bb1752205c36..3262dfdce87af8 100644 --- a/deps/npm/test/lib/commands/explain.js +++ b/deps/npm/test/lib/commands/explain.js @@ -1,37 +1,33 @@ const t = require('tap') -const npm = { - prefix: null, - color: true, - flatOptions: { workspacesEnabled: true }, - output: (...args) => { - OUTPUT.push(args) - }, - config: { - validate: () => {}, - get: (key) => { - if (key === 'location') { - return 'project' - } - }, - isDefault: () => {}, - }, -} const { resolve } = require('path') +const mockNpm = require('../../fixtures/mock-npm.js') -const OUTPUT = [] +const mockExplain = async (t, opts) => { + const mock = await mockNpm(t, { + mocks: { + // keep the snapshots pared down a bit, since this has its own tests. + '{LIB}/utils/explain-dep.js': { + explainNode: (expl, depth, color) => { + return `${expl.name}@${expl.version} depth=${depth} color=${color}` + }, + }, + }, + ...opts, + }) -const Explain = t.mock('../../../lib/commands/explain.js', { + const usage = await mock.npm.cmd('explain').then(c => c.usage) - // keep the snapshots pared down a bit, since this has its own tests. - '../../../lib/utils/explain-dep.js': { - explainNode: (expl, depth, color) => { - return `${expl.name}@${expl.version} depth=${depth} color=${color}` + return { + ...mock, + explain: { + usage, + exec: (args) => mock.npm.exec('explain', args), }, - }, -}) -const explain = new Explain(npm) + } +} t.test('no args throws usage', async t => { + const { explain } = await mockExplain(t) await t.rejects( explain.exec([]), explain.usage @@ -39,7 +35,7 @@ t.test('no args throws usage', async t => { }) t.test('no match throws not found', async t => { - npm.prefix = t.testdir() + const { explain } = await mockExplain(t) await t.rejects( explain.exec(['foo@1.2.3', 'node_modules/baz']), 'No dependencies found matching foo@1.2.3, node_modules/baz' @@ -47,7 +43,7 @@ t.test('no match throws not found', async t => { }) t.test('invalid package name throws not found', async t => { - npm.prefix = t.testdir() + const { explain } = await mockExplain(t) const badName = ' not a valid package name ' await t.rejects( explain.exec([`${badName}@1.2.3`]), @@ -55,96 +51,106 @@ t.test('invalid package name throws not found', async t => { ) }) -t.test('explain some nodes', t => { - t.afterEach(() => { - OUTPUT.length = 0 - npm.flatOptions.json = false - }) - - npm.prefix = t.testdir({ - node_modules: { - foo: { - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.2.3', - dependencies: { - bar: '*', - }, - }), - }, - bar: { - 'package.json': JSON.stringify({ - name: 'bar', - version: '1.2.3', - }), - }, - baz: { - 'package.json': JSON.stringify({ - name: 'baz', - version: '1.2.3', - dependencies: { - foo: '*', - bar: '2', - }, - }), +t.test('explain some nodes', async t => { + const mockNodes = async (t, config = {}) => { + const mock = await mockExplain(t, { + prefixDir: { node_modules: { + foo: { + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.2.3', + dependencies: { + bar: '*', + }, + }), + }, bar: { 'package.json': JSON.stringify({ name: 'bar', - version: '2.3.4', + version: '1.2.3', }), }, - extra: { + baz: { 'package.json': JSON.stringify({ - name: 'extra', - version: '99.9999.999999', - description: 'extraneous package', + name: 'baz', + version: '1.2.3', + dependencies: { + foo: '*', + bar: '2', + }, }), + node_modules: { + bar: { + 'package.json': JSON.stringify({ + name: 'bar', + version: '2.3.4', + }), + }, + extra: { + 'package.json': JSON.stringify({ + name: 'extra', + version: '99.9999.999999', + description: 'extraneous package', + }), + }, + }, }, }, + 'package.json': JSON.stringify({ + dependencies: { + baz: '1', + }, + }), }, - }, - 'package.json': JSON.stringify({ - dependencies: { - baz: '1', + config: { + color: 'always', + ...config, }, - }), - }) + }) + + return mock + } t.test('works with the location', async t => { const path = 'node_modules/foo' + const { explain, joinedOutput } = await mockNodes(t) await explain.exec([path]) - t.strictSame(OUTPUT, [['foo@1.2.3 depth=Infinity color=true']]) + t.strictSame(joinedOutput(), 'foo@1.2.3 depth=Infinity color=true') }) t.test('works with a full actual path', async t => { + const { npm, explain, joinedOutput } = await mockNodes(t) const path = resolve(npm.prefix, 'node_modules/foo') await explain.exec([path]) - t.strictSame(OUTPUT, [['foo@1.2.3 depth=Infinity color=true']]) + t.strictSame(joinedOutput(), 'foo@1.2.3 depth=Infinity color=true') }) t.test('finds all nodes by name', async t => { + const { explain, joinedOutput } = await mockNodes(t) await explain.exec(['bar']) - t.strictSame(OUTPUT, [[ + t.strictSame(joinedOutput(), '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' + ) }) t.test('finds only nodes that match the spec', async t => { + const { explain, joinedOutput } = await mockNodes(t) await explain.exec(['bar@1']) - t.strictSame(OUTPUT, [['bar@1.2.3 depth=Infinity color=true']]) + t.strictSame(joinedOutput(), 'bar@1.2.3 depth=Infinity color=true') }) t.test('finds extraneous nodes', async t => { + const { explain, joinedOutput } = await mockNodes(t) await explain.exec(['extra']) - t.strictSame(OUTPUT, [['extra@99.9999.999999 depth=Infinity color=true']]) + t.strictSame(joinedOutput(), 'extra@99.9999.999999 depth=Infinity color=true') }) t.test('json output', async t => { - npm.flatOptions.json = true + const { explain, joinedOutput } = await mockNodes(t, { json: true }) await explain.exec(['node_modules/foo']) - t.match(JSON.parse(OUTPUT[0][0]), [{ + t.match(JSON.parse(joinedOutput()), [{ name: 'foo', version: '1.2.3', dependents: Array, @@ -152,182 +158,126 @@ t.test('explain some nodes', t => { }) t.test('report if no nodes found', async t => { + const { explain } = await mockNodes(t) await t.rejects( explain.exec(['asdf/foo/bar', 'quux@1.x']), 'No dependencies found matching asdf/foo/bar, quux@1.x' ) }) - t.end() }) t.test('workspaces', async t => { - npm.localPrefix = npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'workspaces-project', - version: '1.0.0', - workspaces: ['packages/*'], - dependencies: { - abbrev: '^1.0.0', - }, - }), - node_modules: { - a: t.fixture('symlink', '../packages/a'), - b: t.fixture('symlink', '../packages/b'), - c: t.fixture('symlink', '../packages/c'), - once: { + const mockWorkspaces = async (t, exec = [], workspaces = true) => { + const mock = await mockExplain(t, { + prefixDir: { 'package.json': JSON.stringify({ - name: 'once', + name: 'workspaces-project', version: '1.0.0', + workspaces: ['packages/*'], dependencies: { - wrappy: '2.0.0', + abbrev: '^1.0.0', }, }), - }, - abbrev: { - 'package.json': JSON.stringify({ - name: 'abbrev', - version: '1.0.0', - }), - }, - wrappy: { - 'package.json': JSON.stringify({ - name: 'wrappy', - version: '2.0.0', - }), - }, - }, - packages: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - dependencies: { - once: '1.0.0', + node_modules: { + a: t.fixture('symlink', '../packages/a'), + b: t.fixture('symlink', '../packages/b'), + c: t.fixture('symlink', '../packages/c'), + once: { + 'package.json': JSON.stringify({ + name: 'once', + version: '1.0.0', + dependencies: { + wrappy: '2.0.0', + }, + }), }, - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'b', - version: '1.0.0', - dependencies: { - abbrev: '^1.0.0', + abbrev: { + 'package.json': JSON.stringify({ + name: 'abbrev', + version: '1.0.0', + }), }, - }), + wrappy: { + 'package.json': JSON.stringify({ + name: 'wrappy', + version: '2.0.0', + }), + }, + }, + packages: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + dependencies: { + once: '1.0.0', + }, + }), + }, + b: { + 'package.json': JSON.stringify({ + name: 'b', + version: '1.0.0', + dependencies: { + abbrev: '^1.0.0', + }, + }), + }, + c: { + 'package.json': JSON.stringify({ + name: 'c', + version: '1.0.0', + }), + }, + }, }, - c: { - 'package.json': JSON.stringify({ - name: 'c', - version: '1.0.0', - }), + config: { + ...(typeof workspaces === 'boolean' ? { workspaces } : { workspace: workspaces }), + color: 'always', }, - }, - }) + }) - await explain.exec(['wrappy']) - t.strictSame( - OUTPUT, - [['wrappy@2.0.0 depth=Infinity color=true']], - 'should explain workspaces deps' - ) - OUTPUT.length = 0 + await mock.explain.exec(exec) - await explain.execWorkspaces(['wrappy'], ['a']) + return mock.joinedOutput() + } - t.strictSame( - OUTPUT, - [ - ['wrappy@2.0.0 depth=Infinity color=true'], - ], - 'should explain deps when filtering to a single ws' - ) - OUTPUT.length = 0 + t.test('should explain workspaces deps', async t => { + const OUTPUT = await mockWorkspaces(t, ['wrappy']) + t.strictSame( + OUTPUT, + 'wrappy@2.0.0 depth=Infinity color=true' + ) + }) - await explain.execWorkspaces(['abbrev'], []) - t.strictSame( - OUTPUT, - [ - ['abbrev@1.0.0 depth=Infinity color=true'], - ], - 'should explain deps of workspaces only' - ) - OUTPUT.length = 0 + t.test('should explain deps when filtering to a single ws', async t => { + const OUTPUT = await mockWorkspaces(t, ['wrappy'], ['a']) + t.strictSame( + OUTPUT, + 'wrappy@2.0.0 depth=Infinity color=true' + ) + }) - await t.rejects( - explain.execWorkspaces(['abbrev'], ['a']), - 'No dependencies found matching abbrev', - 'should throw usage if dep not found within filtered ws' - ) -}) + t.test('should explain deps of workspaces only', async t => { + const OUTPUT = await mockWorkspaces(t, ['abbrev']) + t.strictSame( + OUTPUT, + 'abbrev@1.0.0 depth=Infinity color=true' + ) + }) -t.test('workspaces disabled', async t => { - npm.localPrefix = npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'workspaces-project', - version: '1.0.0', - workspaces: ['packages/*'], - dependencies: { - abbrev: '^1.0.0', - }, - }), - node_modules: { - a: t.fixture('symlink', '../packages/a'), - b: t.fixture('symlink', '../packages/b'), - c: t.fixture('symlink', '../packages/c'), - once: { - 'package.json': JSON.stringify({ - name: 'once', - version: '1.0.0', - dependencies: { - wrappy: '2.0.0', - }, - }), - }, - abbrev: { - 'package.json': JSON.stringify({ - name: 'abbrev', - version: '1.0.0', - }), - }, - wrappy: { - 'package.json': JSON.stringify({ - name: 'wrappy', - version: '2.0.0', - }), - }, - }, - packages: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - dependencies: { - once: '1.0.0', - }, - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'b', - version: '1.0.0', - dependencies: { - abbrev: '^1.0.0', - }, - }), - }, - c: { - 'package.json': JSON.stringify({ - name: 'c', - version: '1.0.0', - }), - }, - }, + t.test('should throw usage if dep not found within filtered ws', async t => { + await t.rejects( + mockWorkspaces(t, ['abbrev'], ['a']), + 'No dependencies found matching abbrev' + ) }) - npm.flatOptions.workspacesEnabled = false - await t.rejects( - explain.exec(['once']), - 'No dependencies found matching once', - 'should throw usage if dep not found when excluding ws' - ) + t.test('workspaces disabled', async t => { + await t.rejects( + mockWorkspaces(t, ['once'], false), + 'No dependencies found matching once', + 'should throw usage if dep not found when excluding ws' + ) + }) }) diff --git a/deps/npm/test/lib/commands/explore.js b/deps/npm/test/lib/commands/explore.js index af6f4df908677b..786a34a8e29882 100644 --- a/deps/npm/test/lib/commands/explore.js +++ b/deps/npm/test/lib/commands/explore.js @@ -1,300 +1,149 @@ const t = require('tap') - -let RPJ_ERROR = null -let RPJ_CALLED = '' -const mockRPJ = async path => { - if (RPJ_ERROR) { - try { +const mockNpm = require('../../fixtures/mock-npm') +const { cleanCwd } = require('../../fixtures/clean-snapshot') + +const mockExplore = async (t, exec, { + RPJ_ERROR = null, + RUN_SCRIPT_ERROR = null, + RUN_SCRIPT_EXIT_CODE = 0, + RUN_SCRIPT_SIGNAL = null, +} = {}) => { + let RPJ_CALLED = '' + const mockRPJ = async path => { + if (RPJ_ERROR) { throw RPJ_ERROR - } finally { - RPJ_ERROR = null } + RPJ_CALLED = cleanCwd(path) + return { some: 'package' } } - RPJ_CALLED = path - return { some: 'package' } -} -let RUN_SCRIPT_ERROR = null -let RUN_SCRIPT_EXIT_CODE = 0 -let RUN_SCRIPT_SIGNAL = null -let RUN_SCRIPT_EXEC = null -const mockRunScript = ({ pkg, banner, path, event, stdio }) => { - if (event !== '_explore') { - throw new Error('got wrong event name') - } + let RUN_SCRIPT_EXEC = null + const mockRunScript = ({ pkg, event }) => { + if (event !== '_explore') { + throw new Error('got wrong event name') + } - RUN_SCRIPT_EXEC = pkg.scripts._explore + RUN_SCRIPT_EXEC = pkg.scripts._explore - if (RUN_SCRIPT_ERROR) { - try { + if (RUN_SCRIPT_ERROR) { return Promise.reject(RUN_SCRIPT_ERROR) - } finally { - RUN_SCRIPT_ERROR = null } - } - if (RUN_SCRIPT_EXIT_CODE || RUN_SCRIPT_SIGNAL) { - return Promise.reject(Object.assign(new Error('command failed'), { - code: RUN_SCRIPT_EXIT_CODE, - signal: RUN_SCRIPT_SIGNAL, - })) - } + if (RUN_SCRIPT_EXIT_CODE || RUN_SCRIPT_SIGNAL) { + return Promise.reject(Object.assign(new Error('command failed'), { + code: RUN_SCRIPT_EXIT_CODE, + signal: RUN_SCRIPT_SIGNAL, + })) + } - return Promise.resolve({ code: 0, signal: null }) -} + return Promise.resolve({ code: 0, signal: null }) + } -const output = [] -const logs = [] -const getExplore = (windows) => { - const Explore = t.mock('../../../lib/commands/explore.js', { - path: require('path')[windows ? 'win32' : 'posix'], - 'read-package-json-fast': mockRPJ, - '@npmcli/run-script': mockRunScript, - 'proc-log': { - error: (...msg) => logs.push(msg), - warn: () => {}, - }, - npmlog: { - disableProgress: () => {}, - enableProgress: () => {}, - }, - }) - const npm = { - dir: windows ? 'c:\\npm\\dir' : '/npm/dir', - flatOptions: { - shell: 'shell-command', - }, - output: out => { - output.push(out) + const mock = await mockNpm(t, { + mocks: { + 'read-package-json-fast': mockRPJ, + '@npmcli/run-script': mockRunScript, }, config: { - validate: () => {}, + shell: 'shell-command', }, - } - return new Explore(npm) -} - -const windowsExplore = getExplore(true) -const posixExplore = getExplore(false) - -t.test('basic interactive', t => { - t.afterEach(() => output.length = 0) - - t.test('windows', async t => { - await windowsExplore.exec(['pkg']) - - t.strictSame({ - RPJ_CALLED, - RUN_SCRIPT_EXEC, - }, { - RPJ_CALLED: 'c:\\npm\\dir\\pkg\\package.json', - RUN_SCRIPT_EXEC: 'shell-command', - }) - t.strictSame(output, [ - "\nExploring c:\\npm\\dir\\pkg\nType 'exit' or ^D when finished\n", - ]) }) - t.test('posix', async t => { - await posixExplore.exec(['pkg']) + await mock.npm.exec('explore', exec) - t.strictSame({ - RPJ_CALLED, - RUN_SCRIPT_EXEC, - }, { - RPJ_CALLED: '/npm/dir/pkg/package.json', - RUN_SCRIPT_EXEC: 'shell-command', - }) - t.strictSame(output, [ - "\nExploring /npm/dir/pkg\nType 'exit' or ^D when finished\n", - ]) - }) - - t.end() -}) + return { + ...mock, + RPJ_CALLED, + RUN_SCRIPT_EXEC, + output: cleanCwd(mock.joinedOutput()).trim(), + } +} -t.test('interactive tracks exit code', t => { - const { exitCode } = process - t.beforeEach(() => { - process.exitCode = exitCode - RUN_SCRIPT_EXIT_CODE = 99 - }) - t.afterEach(() => { - RUN_SCRIPT_EXIT_CODE = 0 - output.length = 0 - process.exitCode = exitCode - }) +t.test('basic interactive', async t => { + const { + output, + RPJ_CALLED, + RUN_SCRIPT_EXEC, + } = await mockExplore(t, ['pkg']) - t.test('windows', async t => { - await windowsExplore.exec(['pkg']) + t.match(RPJ_CALLED, /\/pkg\/package.json$/) + t.strictSame(RUN_SCRIPT_EXEC, 'shell-command') + t.match(output, /Exploring \{CWD\}\/[\w-_/]+\nType 'exit' or \^D when finished/) +}) - t.strictSame({ +t.test('interactive tracks exit code', async t => { + t.test('code', async t => { + const { + output, RPJ_CALLED, RUN_SCRIPT_EXEC, - }, { - RPJ_CALLED: 'c:\\npm\\dir\\pkg\\package.json', - RUN_SCRIPT_EXEC: 'shell-command', - }) - t.strictSame(output, [ - "\nExploring c:\\npm\\dir\\pkg\nType 'exit' or ^D when finished\n", - ]) - t.equal(process.exitCode, 99) - }) + } = await mockExplore(t, ['pkg'], { RUN_SCRIPT_EXIT_CODE: 99 }) - t.test('posix', async t => { - await posixExplore.exec(['pkg']) + t.match(RPJ_CALLED, /\/pkg\/package.json$/) + t.strictSame(RUN_SCRIPT_EXEC, 'shell-command') + t.match(output, /Exploring \{CWD\}\/[\w-_/]+\nType 'exit' or \^D when finished/) - t.strictSame({ - RPJ_CALLED, - RUN_SCRIPT_EXEC, - }, { - RPJ_CALLED: '/npm/dir/pkg/package.json', - RUN_SCRIPT_EXEC: 'shell-command', - }) - t.strictSame(output, [ - "\nExploring /npm/dir/pkg\nType 'exit' or ^D when finished\n", - ]) t.equal(process.exitCode, 99) }) - t.test('posix spawn fail', async t => { - RUN_SCRIPT_ERROR = Object.assign(new Error('glorb'), { + t.test('spawn fail', async t => { + const RUN_SCRIPT_ERROR = Object.assign(new Error('glorb'), { code: 33, }) await t.rejects( - posixExplore.exec(['pkg']), + mockExplore(t, ['pkg'], { RUN_SCRIPT_ERROR }), { message: 'glorb', code: 33 } ) - t.strictSame(output, [ - "\nExploring /npm/dir/pkg\nType 'exit' or ^D when finished\n", - ]) t.equal(process.exitCode, 33) }) - t.test('posix spawn fail, 0 exit code', async t => { - RUN_SCRIPT_ERROR = Object.assign(new Error('glorb'), { + t.test('spawn fail, 0 exit code', async t => { + const RUN_SCRIPT_ERROR = Object.assign(new Error('glorb'), { code: 0, }) await t.rejects( - posixExplore.exec(['pkg']), + mockExplore(t, ['pkg'], { RUN_SCRIPT_ERROR }), { message: 'glorb', code: 0 } ) - t.strictSame(output, [ - "\nExploring /npm/dir/pkg\nType 'exit' or ^D when finished\n", - ]) t.equal(process.exitCode, 1) }) - t.test('posix spawn fail, no exit code', async t => { - RUN_SCRIPT_ERROR = Object.assign(new Error('command failed'), { + t.test('spawn fail, no exit code', async t => { + const RUN_SCRIPT_ERROR = Object.assign(new Error('command failed'), { code: 'EPROBLEM', }) await t.rejects( - posixExplore.exec(['pkg']), + mockExplore(t, ['pkg'], { RUN_SCRIPT_ERROR }), { message: 'command failed', code: 'EPROBLEM' } ) - t.strictSame(output, [ - "\nExploring /npm/dir/pkg\nType 'exit' or ^D when finished\n", - ]) t.equal(process.exitCode, 1) }) - - t.end() }) -t.test('basic non-interactive', t => { - t.afterEach(() => output.length = 0) - - t.test('windows', async t => { - await windowsExplore.exec(['pkg', 'ls']) - - t.strictSame({ - RPJ_CALLED, - RUN_SCRIPT_EXEC, - }, { - RPJ_CALLED: 'c:\\npm\\dir\\pkg\\package.json', - RUN_SCRIPT_EXEC: 'ls', - }) - t.strictSame(output, []) - }) - - t.test('posix', async t => { - await posixExplore.exec(['pkg', 'ls']) +t.test('basic non-interactive', async t => { + const { + output, + RPJ_CALLED, + RUN_SCRIPT_EXEC, + } = await mockExplore(t, ['pkg', 'ls']) - t.strictSame({ - RPJ_CALLED, - RUN_SCRIPT_EXEC, - }, { - RPJ_CALLED: '/npm/dir/pkg/package.json', - RUN_SCRIPT_EXEC: 'ls', - }) - t.strictSame(output, []) - t.end() - }) + t.match(RPJ_CALLED, /\/pkg\/package.json$/) + t.strictSame(RUN_SCRIPT_EXEC, 'ls') - t.end() + t.strictSame(output, '') }) -t.test('signal fails non-interactive', t => { - const { exitCode } = process - t.afterEach(() => { - output.length = 0 - logs.length = 0 - }) - - t.beforeEach(() => { - RUN_SCRIPT_SIGNAL = 'SIGPROBLEM' - RUN_SCRIPT_EXIT_CODE = null - process.exitCode = exitCode - }) - t.afterEach(() => process.exitCode = exitCode) - - t.test('windows', async t => { - await t.rejects( - windowsExplore.exec(['pkg', 'ls']), - { - message: 'command failed', - signal: 'SIGPROBLEM', - } - ) - - t.strictSame({ - RPJ_CALLED, - RUN_SCRIPT_EXEC, - }, { - RPJ_CALLED: 'c:\\npm\\dir\\pkg\\package.json', - RUN_SCRIPT_EXEC: 'ls', - }) - t.strictSame(output, []) - }) - - t.test('posix', async t => { - await t.rejects( - posixExplore.exec(['pkg', 'ls']), - { - message: 'command failed', - signal: 'SIGPROBLEM', - } - ) - - t.strictSame({ - RPJ_CALLED, - RUN_SCRIPT_EXEC, - }, { - RPJ_CALLED: '/npm/dir/pkg/package.json', - RUN_SCRIPT_EXEC: 'ls', - }) - t.strictSame(output, []) - t.end() - }) - - t.end() +t.test('signal fails non-interactive', async t => { + await t.rejects( + mockExplore(t, ['pkg', 'ls'], { RUN_SCRIPT_SIGNAL: 'SIGPROBLEM' }), + { + message: 'command failed', + signal: 'SIGPROBLEM', + } + ) }) -t.test('usage if no pkg provided', t => { - t.teardown(() => { - output.length = 0 - }) +t.test('usage if no pkg provided', async t => { const noPkg = [ [], ['foo/../..'], @@ -303,41 +152,22 @@ t.test('usage if no pkg provided', t => { ['..'], ['../..'], ] - t.plan(noPkg.length) + for (const args of noPkg) { t.test(JSON.stringify(args), async t => { await t.rejects( - posixExplore.exec(args), + mockExplore(t, args), 'Usage:' ) - t.strictSame({ - RPJ_CALLED, - RUN_SCRIPT_EXEC, - }, { - RPJ_CALLED: '/npm/dir/pkg/package.json', - RUN_SCRIPT_EXEC: 'ls', - }) }) } }) t.test('pkg not installed', async t => { - t.teardown(() => { - logs.length = 0 - }) - RPJ_ERROR = new Error('plurple') + const RPJ_ERROR = new Error('plurple') await t.rejects( - posixExplore.exec(['pkg', 'ls']), + mockExplore(t, ['pkg', 'ls'], { RPJ_ERROR }), { message: 'plurple' } ) - t.strictSame({ - RPJ_CALLED, - RUN_SCRIPT_EXEC, - }, { - RPJ_CALLED: '/npm/dir/pkg/package.json', - RUN_SCRIPT_EXEC: 'ls', - }) - t.strictSame(output, []) - t.match(logs, [['explore', `It doesn't look like pkg is installed.`]]) }) diff --git a/deps/npm/test/lib/commands/fund.js b/deps/npm/test/lib/commands/fund.js index b82ed93fe5c7ea..277190e7a1a481 100644 --- a/deps/npm/test/lib/commands/fund.js +++ b/deps/npm/test/lib/commands/fund.js @@ -1,7 +1,8 @@ const t = require('tap') -const { fake: mockNpm } = require('../../fixtures/mock-npm') +const mockNpm = require('../../fixtures/mock-npm') const version = '1.0.0' + const funding = { type: 'individual', url: 'http://example.com/donate', @@ -172,78 +173,64 @@ const conflictingFundingPackages = { }, } -let result = '' -let printUrl = '' -const config = { - color: false, - json: false, - global: false, - unicode: false, - which: null, -} -const openUrl = async (npm, url, msg) => { - if (url === 'http://npmjs.org') { - throw new Error('ERROR') - } +const setup = async (t, { openUrl, ...opts } = {}) => { + const openedUrls = [] + + const res = await mockNpm(t, { + ...opts, + mocks: { + '@npmcli/promise-spawn': { open: openUrl || (async url => openedUrls.push(url)) }, + pacote: { + manifest: arg => + arg.name === 'ntl' + ? Promise.resolve({ funding: 'http://example.com/pacote' }) + : Promise.reject(new Error('ERROR')), + }, + ...opts.mocks, + }, + }) - if (config.json) { - printUrl = JSON.stringify({ - title: msg, - url: url, - }) - } else { - printUrl = `${msg}:\n ${url}` + return { + ...res, + openedUrls: () => openedUrls, + fund: (...args) => res.npm.exec('fund', args), } } -const Fund = t.mock('../../../lib/commands/fund.js', { - '../../../lib/utils/open-url.js': openUrl, - pacote: { - manifest: arg => - arg.name === 'ntl' - ? Promise.resolve({ - funding: 'http://example.com/pacote', - }) - : Promise.reject(new Error('ERROR')), - }, -}) -const npm = mockNpm({ - config, - output: msg => { - result += msg + '\n' - }, -}) -const fund = new Fund(npm) -t.afterEach(() => { - printUrl = '' - result = '' -}) t.test('fund with no package containing funding', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'no-funding-package', - version: '0.0.0', - }), + const { fund, joinedOutput } = await setup(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'no-funding-package', + version: '0.0.0', + }), + }, + config: {}, }) - await fund.exec([]) - t.matchSnapshot(result, 'should print empty funding info') + await fund() + t.matchSnapshot(joinedOutput(), 'should print empty funding info') }) t.test('fund in which same maintainer owns all its deps', async t => { - npm.prefix = t.testdir(maintainerOwnsAllDeps) + const { fund, joinedOutput } = await setup(t, { + prefixDir: maintainerOwnsAllDeps, + config: {}, + }) - await fund.exec([]) - t.matchSnapshot(result, 'should print stack packages together') + await fund() + t.matchSnapshot(joinedOutput(), 'should print stack packages together') }) t.test('fund in which same maintainer owns all its deps, using --json option', async t => { - config.json = true - npm.prefix = t.testdir(maintainerOwnsAllDeps) + const { fund, joinedOutput } = await setup(t, { + prefixDir: maintainerOwnsAllDeps, + config: { json: true }, + }) - await fund.exec([]) + await fund() t.same( - JSON.parse(result), + JSON.parse(joinedOutput()), { length: 3, name: 'maintainer-owns-all-deps', @@ -268,24 +255,27 @@ t.test('fund in which same maintainer owns all its deps, using --json option', a }, 'should print stack packages together' ) - config.json = false }) t.test('fund containing multi-level nested deps with no funding', async t => { - npm.prefix = t.testdir(nestedNoFundingPackages) + const { fund, joinedOutput } = await setup(t, { + prefixDir: nestedNoFundingPackages, + config: {}, + }) - await fund.exec([]) - t.matchSnapshot(result, 'should omit dependencies with no funding declared') - t.end() + await fund() + t.matchSnapshot(joinedOutput(), 'should omit dependencies with no funding declared') }) t.test('fund containing multi-level nested deps with no funding, using --json option', async t => { - npm.prefix = t.testdir(nestedNoFundingPackages) - config.json = true + const { fund, joinedOutput } = await setup(t, { + prefixDir: nestedNoFundingPackages, + config: { json: true }, + }) - await fund.exec([]) + await fund() t.same( - JSON.parse(result), + JSON.parse(joinedOutput()), { length: 2, name: 'nested-no-funding-packages', @@ -303,16 +293,17 @@ t.test('fund containing multi-level nested deps with no funding, using --json op }, 'should omit dependencies with no funding declared in json output' ) - config.json = false }) t.test('fund containing multi-level nested deps with no funding, using --json option', async t => { - npm.prefix = t.testdir(nestedMultipleFundingPackages) - config.json = true + const { fund, joinedOutput } = await setup(t, { + prefixDir: nestedMultipleFundingPackages, + config: { json: true }, + }) - await fund.exec([]) + await fund() t.same( - JSON.parse(result), + JSON.parse(joinedOutput()), { length: 2, name: 'nested-multiple-funding-packages', @@ -355,376 +346,337 @@ t.test('fund containing multi-level nested deps with no funding, using --json op }, 'should list multiple funding entries in json output' ) - config.json = false }) t.test('fund does not support global', async t => { - npm.prefix = t.testdir({}) - config.global = true + const { fund } = await setup(t, { + config: { global: true }, + }) - await t.rejects(fund.exec([]), { code: 'EFUNDGLOBAL' }, 'should throw EFUNDGLOBAL error') - config.global = false + await t.rejects(fund(), { code: 'EFUNDGLOBAL' }, 'should throw EFUNDGLOBAL error') }) t.test('fund using package argument', async t => { - npm.prefix = t.testdir(maintainerOwnsAllDeps) + const { fund, openedUrls, joinedOutput } = await setup(t, { + prefixDir: maintainerOwnsAllDeps, + config: {}, + }) - await fund.exec(['.']) - t.matchSnapshot(printUrl, 'should open funding url') + await fund('.') + t.equal(joinedOutput(), '') + t.strictSame(openedUrls(), ['http://example.com/donate'], 'should open funding url') }) t.test('fund does not support global, using --json option', async t => { - npm.prefix = t.testdir({}) - config.global = true - config.json = true + const { fund } = await setup(t, { + prefixDir: {}, + config: { global: true, json: true }, + }) await t.rejects( - fund.exec([]), + fund(), { code: 'EFUNDGLOBAL', message: '`npm fund` does not support global packages' }, 'should use expected error msg' ) - config.global = false - config.json = false }) t.test('fund using string shorthand', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'funding-string-shorthand', - version: '0.0.0', - funding: 'https://example.com/sponsor', - }), + const { fund, openedUrls } = await setup(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'funding-string-shorthand', + version: '0.0.0', + funding: 'https://example.com/sponsor', + }), + }, + config: {}, }) - await fund.exec(['.']) - t.matchSnapshot(printUrl, 'should open string-only url') + await fund('.') + t.strictSame(openedUrls(), ['https://example.com/sponsor'], 'should open string-only url') }) t.test('fund using nested packages with multiple sources', async t => { - npm.prefix = t.testdir(nestedMultipleFundingPackages) + const { fund, joinedOutput } = await setup(t, { + prefixDir: nestedMultipleFundingPackages, + config: {}, + }) - await fund.exec(['.']) - t.matchSnapshot(result, 'should prompt with all available URLs') + await fund('.') + t.matchSnapshot(joinedOutput(), 'should prompt with all available URLs') }) t.test('fund using symlink ref', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'using-symlink-ref', - version: '1.0.0', - }), - a: { + const f = 'http://example.com/a' + const { fund, openedUrls } = await setup(t, { + prefixDir: { 'package.json': JSON.stringify({ - name: 'a', + name: 'using-symlink-ref', version: '1.0.0', - funding: 'http://example.com/a', }), + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + funding: f, + }), + }, + node_modules: { + a: t.fixture('symlink', '../a'), + }, }, - node_modules: { - a: t.fixture('symlink', '../a'), - }, + config: {}, }) // using symlinked ref - await fund.exec(['./node_modules/a']) - t.match(printUrl, 'http://example.com/a', 'should retrieve funding url from symlink') - - printUrl = '' - result = '' + await fund('./node_modules/a') + t.strictSame(openedUrls(), [f], 'should retrieve funding url from symlink') // using target ref - await fund.exec(['./a']) - - t.match(printUrl, 'http://example.com/a', 'should retrieve funding url from symlink target') + await fund('./a') + t.strictSame(openedUrls(), [f, f], 'should retrieve funding url from symlink target') }) t.test('fund using data from actual tree', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'using-actual-tree', - version: '1.0.0', - }), - node_modules: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - funding: 'http://example.com/a', - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - funding: 'http://example.com/b', - }), - node_modules: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.1', - funding: 'http://example.com/_AAA', - }), + const { fund, openedUrls } = await setup(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'using-actual-tree', + version: '1.0.0', + }), + node_modules: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + funding: 'http://example.com/a', + }), + }, + b: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + funding: 'http://example.com/b', + }), + node_modules: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.1', + funding: 'http://example.com/_AAA', + }), + }, }, }, }, }, + config: {}, }) // using symlinked ref - await fund.exec(['a']) - t.match( - printUrl, - 'http://example.com/_AAA', + await fund('a') + t.strictSame( + openedUrls(), + ['http://example.com/_AAA'], 'should retrieve fund info from actual tree, using greatest version found' ) }) t.test('fund using nested packages with multiple sources, with a source number', async t => { - npm.prefix = t.testdir(nestedMultipleFundingPackages) - config.which = '1' + const { fund, openedUrls } = await setup(t, { + prefixDir: nestedMultipleFundingPackages, + config: { which: '1' }, + }) - await fund.exec(['.']) - t.matchSnapshot(printUrl, 'should open the numbered URL') - config.which = null + await fund('.') + t.strictSame(openedUrls(), ['https://one.example.com'], 'should open the numbered URL') }) t.test('fund using pkg name while having conflicting versions', async t => { - npm.prefix = t.testdir(conflictingFundingPackages) - config.which = '1' + const { fund, openedUrls } = await setup(t, { + prefixDir: conflictingFundingPackages, + config: { which: '1' }, + }) - await fund.exec(['foo']) - t.matchSnapshot(printUrl, 'should open greatest version') + await fund('foo') + t.strictSame(openedUrls(), ['http://example.com/2'], 'should open greatest version') +}) + +t.test('fund using bad which value: index too high', async t => { + const { fund, joinedOutput } = await setup(t, { + prefixDir: nestedMultipleFundingPackages, + config: { which: '100' }, + }) + + await fund('foo') + t.match(joinedOutput(), 'not a valid index') + t.matchSnapshot(joinedOutput(), 'should print message about invalid which') }) t.test('fund using package argument with no browser, using --json option', async t => { - npm.prefix = t.testdir(maintainerOwnsAllDeps) - config.json = true + const { fund, openedUrls, joinedOutput } = await setup(t, { + prefixDir: maintainerOwnsAllDeps, + config: { json: true }, + }) - await fund.exec(['.']) + await fund('.') + t.equal(joinedOutput(), '', 'no output') t.same( - JSON.parse(printUrl), - { - title: 'individual funding available at the following URL', - url: 'http://example.com/donate', - }, + openedUrls(), + ['http://example.com/donate'], 'should open funding url using json output' ) - config.json = false }) t.test('fund using package info fetch from registry', async t => { - npm.prefix = t.testdir({}) + const { fund, openedUrls } = await setup(t, { + prefixDir: {}, + config: {}, + }) - await fund.exec(['ntl']) + await fund('ntl') t.match( - printUrl, + openedUrls(), /http:\/\/example.com\/pacote/, 'should open funding url that was loaded from registry manifest' ) }) t.test('fund tries to use package info fetch from registry but registry has nothing', async t => { - npm.prefix = t.testdir({}) + const { fund } = await setup(t, { + prefixDir: {}, + config: {}, + }) await t.rejects( - fund.exec(['foo']), + fund('foo'), { code: 'ENOFUND', message: 'No valid funding method available for: foo' }, 'should have no valid funding message' ) }) t.test('fund but target module has no funding info', async t => { - npm.prefix = t.testdir(nestedNoFundingPackages) + const { fund } = await setup(t, { + prefixDir: nestedNoFundingPackages, + config: {}, + }) await t.rejects( - fund.exec(['foo']), + fund('foo'), { code: 'ENOFUND', message: 'No valid funding method available for: foo' }, 'should have no valid funding message' ) }) t.test('fund using bad which value', async t => { - npm.prefix = t.testdir(nestedMultipleFundingPackages) - config.which = 3 + const { fund } = await setup(t, { + prefixDir: nestedMultipleFundingPackages, + config: { which: '0' }, + }) await t.rejects( - fund.exec(['bar']), + fund('bar'), { code: 'EFUNDNUMBER', - /* eslint-disable-next-line max-len */ - message: '`npm fund [<@scope>/] [--which=fundingSourceNumber]` must be given a positive integer', + message: /must be given a positive integer/, }, 'should have bad which option error message' ) - config.which = null }) t.test('fund pkg missing version number', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'foo', - funding: 'http://example.com/foo', - }), + const { fund, joinedOutput } = await setup(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'foo', + funding: 'http://example.com/foo', + }), + }, + config: {}, }) - await fund.exec([]) - t.matchSnapshot(result, 'should print name only') + await fund() + t.matchSnapshot(joinedOutput(), 'should print name only') }) t.test('fund a package throws on openUrl', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.0.0', - funding: 'http://npmjs.org', - }), + const { fund } = await setup(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.0.0', + funding: 'http://npmjs.org', + }), + }, + config: {}, + openUrl: () => { + throw new Error('ERROR') + }, }) - await t.rejects(fund.exec(['.']), { message: 'ERROR' }, 'should throw unknown error') + await t.rejects(fund('.'), { message: 'ERROR' }, 'should throw unknown error') }) t.test('fund a package with type and multiple sources', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'foo', - funding: [ - { - type: 'Foo', - url: 'http://example.com/foo', - }, - { - type: 'Lorem', - url: 'http://example.com/foo-lorem', - }, - ], - }), - }) - - await fund.exec(['.']) - t.matchSnapshot(result, 'should print prompt select message') -}) - -t.test('fund colors', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-fund-colors', - version: '1.0.0', - dependencies: { - a: '^1.0.0', - b: '^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', - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'b', - version: '1.0.0', - funding: 'http://example.com/b', - dependencies: { - d: '^1.0.0', - e: '^1.0.0', + const { fund, joinedOutput } = await setup(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'foo', + funding: [ + { + type: 'Foo', + url: 'http://example.com/foo', }, - }), - }, - c: { - 'package.json': JSON.stringify({ - name: 'c', - version: '1.0.0', - funding: 'http://example.com/b', - }), - }, - d: { - 'package.json': JSON.stringify({ - name: 'd', - version: '1.0.0', - funding: 'http://example.com/d', - }), - }, - e: { - 'package.json': JSON.stringify({ - name: 'e', - version: '1.0.0', - funding: 'http://example.com/e', - }), - }, - }, - }) - npm.color = true - - await fund.exec([]) - t.matchSnapshot(result, 'should print output with color info') - npm.color = false -}) - -t.test('sub dep with fund info and a parent with no funding info', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-multiple-funding-sources', - version: '1.0.0', - dependencies: { - a: '^1.0.0', - b: '^1.0.0', - }, - }), - node_modules: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - dependencies: { - c: '^1.0.0', + { + type: 'Lorem', + url: 'http://example.com/foo-lorem', }, - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'b', - version: '1.0.0', - funding: 'http://example.com/b', - }), - }, - c: { - 'package.json': JSON.stringify({ - name: 'c', - version: '1.0.0', - funding: ['http://example.com/c', 'http://example.com/c-other'], - }), - }, + ], + }), }, + config: {}, }) - await fund.exec([]) - t.matchSnapshot(result, 'should nest sub dep as child of root') + await fund('.') + t.matchSnapshot(joinedOutput(), 'should print prompt select message') }) -t.test('workspaces', async t => { - t.test('filter funding info by a specific workspace', async t => { - npm.localPrefix = npm.prefix = t.testdir({ +t.test('fund colors', async t => { + const { fund, joinedOutput } = await setup(t, { + prefixDir: { 'package.json': JSON.stringify({ - name: 'workspaces-support', + name: 'test-fund-colors', version: '1.0.0', - workspaces: ['packages/*'], dependencies: { - d: '^1.0.0', + a: '^1.0.0', + b: '^1.0.0', + c: '^1.0.0', }, }), node_modules: { - a: t.fixture('symlink', '../packages/a'), - b: t.fixture('symlink', '../packages/b'), + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + funding: 'http://example.com/a', + }), + }, + b: { + 'package.json': JSON.stringify({ + name: 'b', + version: '1.0.0', + funding: 'http://example.com/b', + dependencies: { + d: '^1.0.0', + e: '^1.0.0', + }, + }), + }, c: { 'package.json': JSON.stringify({ name: 'c', version: '1.0.0', - funding: ['http://example.com/c', 'http://example.com/c-other'], + funding: 'http://example.com/b', }), }, d: { @@ -734,13 +686,38 @@ t.test('workspaces', async t => { funding: 'http://example.com/d', }), }, + e: { + 'package.json': JSON.stringify({ + name: 'e', + version: '1.0.0', + funding: 'http://example.com/e', + }), + }, }, - packages: { + }, + config: { color: 'always' }, + }) + + await fund() + t.matchSnapshot(joinedOutput(), 'should print output with color info') +}) + +t.test('sub dep with fund info and a parent with no funding info', async t => { + const { fund, joinedOutput } = await setup(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-multiple-funding-sources', + version: '1.0.0', + dependencies: { + a: '^1.0.0', + b: '^1.0.0', + }, + }), + node_modules: { a: { 'package.json': JSON.stringify({ name: 'a', version: '1.0.0', - funding: 'https://example.com/a', dependencies: { c: '^1.0.0', }, @@ -751,22 +728,97 @@ t.test('workspaces', async t => { name: 'b', version: '1.0.0', funding: 'http://example.com/b', - dependencies: { - d: '^1.0.0', - }, + }), + }, + c: { + 'package.json': JSON.stringify({ + name: 'c', + version: '1.0.0', + funding: ['http://example.com/c', 'http://example.com/c-other'], }), }, }, - }) + }, + config: {}, + }) - await fund.execWorkspaces([], ['a']) + await fund() + t.matchSnapshot(joinedOutput(), 'should nest sub dep as child of root') +}) - t.matchSnapshot(result, 'should display only filtered workspace name and its deps') +t.test('workspaces', async t => { + const wsPrefixDir = { + 'package.json': JSON.stringify({ + name: 'workspaces-support', + version: '1.0.0', + workspaces: ['packages/*'], + dependencies: { + d: '^1.0.0', + }, + }), + node_modules: { + a: t.fixture('symlink', '../packages/a'), + b: t.fixture('symlink', '../packages/b'), + c: { + 'package.json': JSON.stringify({ + name: 'c', + version: '1.0.0', + funding: ['http://example.com/c', 'http://example.com/c-other'], + }), + }, + d: { + 'package.json': JSON.stringify({ + name: 'd', + version: '1.0.0', + funding: 'http://example.com/d', + }), + }, + }, + packages: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + funding: 'https://example.com/a', + dependencies: { + c: '^1.0.0', + }, + }), + }, + b: { + 'package.json': JSON.stringify({ + name: 'b', + version: '1.0.0', + funding: 'http://example.com/b', + dependencies: { + d: '^1.0.0', + }, + }), + }, + }, + } - result = '' + t.test('filter funding info by a specific workspace name', async t => { + const { fund, joinedOutput } = await setup(t, { + prefixDir: wsPrefixDir, + config: { + workspace: 'a', + }, + }) - await fund.execWorkspaces([], ['./packages/a']) + await fund() + t.matchSnapshot(joinedOutput(), 'should display only filtered workspace name and its deps') + }) + + t.test('filter funding info by a specific workspace path', async t => { + const { fund, joinedOutput } = await setup(t, { + prefixDir: wsPrefixDir, + config: { + workspace: './packages/a', + }, + }) - t.matchSnapshot(result, 'should display only filtered workspace path and its deps') + await fund() + t.matchSnapshot(joinedOutput(), 'should display only filtered workspace name and its deps') }) }) diff --git a/deps/npm/test/lib/commands/help-search.js b/deps/npm/test/lib/commands/help-search.js index 7fbeb195d23c7d..ce6e5f7cf00b01 100644 --- a/deps/npm/test/lib/commands/help-search.js +++ b/deps/npm/test/lib/commands/help-search.js @@ -1,130 +1,89 @@ const t = require('tap') -const { join } = require('path') -const { fake: mockNpm } = require('../../fixtures/mock-npm') +const { load: loadMockNpm } = require('../../fixtures/mock-npm.js') const chalk = require('chalk') -const OUTPUT = [] -const output = msg => { - OUTPUT.push(msg) -} - -const config = { - long: false, -} -const npmHelpErr = null -const npm = mockNpm({ - color: false, - config, - flatOptions: { - long: false, +/* eslint-disable max-len */ +const docsFixtures = { + dir1: { + 'npm-exec.md': 'the exec command\nhelp has multiple lines of exec help\none of them references exec', }, - usage: 'npm test usage', - exec: async () => { - if (npmHelpErr) { - throw npmHelpErr - } + dir2: { + 'npm-something.md': 'another\ncommand you run\nthat\nreferences exec\nand has multiple lines\nwith no matches\nthat will be ignored\nand another line\nthat does have exec as well', + 'npm-run-script.md': 'the scripted run-script command runs scripts\nand has lines\nsome of which dont match the string run\nor script\nscript', + 'npm-install.md': 'does a thing in a script\nif a thing does not exist in a thing you run\nto install it and run it maybe in a script', + }, + dir3: { + 'npm-help.md': 'will run the `help-search` command if you need to run it to help you search', + 'npm-help-search.md': 'is the help search command\nthat you get if you run help-search', + 'npm-useless.md': 'exec\nexec', + 'npm-more-useless.md': 'exec exec', + 'npm-extra-useless.md': 'exec\nexec\nexec', }, - output, -}) - -let globRoot = null -const globDir = { - 'npm-exec.md': - 'the exec command\nhelp has multiple lines of exec help\none of them references exec', - /* eslint-disable-next-line max-len */ - 'npm-something.md': 'another\ncommand you run\nthat\nreferences exec\nand has multiple lines\nwith no matches\nthat will be ignored\nand another line\nthat does have exec as well', - /* eslint-disable-next-line max-len */ - 'npm-run-script.md': 'the scripted run-script command runs scripts\nand has lines\nsome of which dont match the string run\nor script\nscript', - /* eslint-disable-next-line max-len */ - 'npm-install.md': 'does a thing in a script\nif a thing does not exist in a thing you run\nto install it and run it maybe in a script', - 'npm-help.md': 'will run the `help-search` command if you need to run it to help you search', - 'npm-help-search.md': 'is the help search command\nthat you get if you run help-search', - 'npm-useless.md': 'exec\nexec', - 'npm-more-useless.md': 'exec exec', - 'npm-extra-useless.md': 'exec\nexec\nexec', } -const glob = (p, cb) => - cb( - null, - Object.keys(globDir).map(file => join(globRoot, file)) - ) +/* eslint-enable max-len */ + +const execHelpSearch = async (t, exec = [], opts) => { + const { npm, ...rest } = await loadMockNpm(t, { + npm: ({ other }) => ({ npmRoot: other }), + // docs/content is hardcoded into the glob path in the command + otherDirs: { + docs: { + content: docsFixtures, + }, + }, + ...opts, + }) -const HelpSearch = t.mock('../../../lib/commands/help-search.js', { - glob, -}) -const helpSearch = new HelpSearch(npm) + await npm.exec('help-search', exec) -t.test('npm help-search', async t => { - globRoot = t.testdir(globDir) - t.teardown(() => { - OUTPUT.length = 0 - globRoot = null - }) + return { npm, output: rest.joinedOutput(), ...rest } +} - await helpSearch.exec(['exec']) +t.test('npm help-search', async t => { + const { output } = await execHelpSearch(t, ['exec']) - t.match(OUTPUT, /Top hits for "exec"/, 'outputs results') + t.match(output, /Top hits for "exec"/, 'outputs results') }) t.test('npm help-search multiple terms', async t => { - globRoot = t.testdir(globDir) - t.teardown(() => { - OUTPUT.length = 0 - globRoot = null - }) + const { output } = await execHelpSearch(t, ['run', 'script']) - await helpSearch.exec(['run', 'script']) - - t.match(OUTPUT, /Top hits for/, 'outputs results') - t.match(OUTPUT, /run:\d+ script:\d+/, 'shows hit counts for both terms') + t.match(output, /Top hits for/, 'outputs results') + t.match(output, /run:\d+ script:\d+/, 'shows hit counts for both terms') }) t.test('npm help-search long output', async t => { - globRoot = t.testdir(globDir) - config.long = true - t.teardown(() => { - OUTPUT.length = 0 - config.long = false - globRoot = null + const { output } = await execHelpSearch(t, ['exec'], { + config: { + long: true, + }, }) - await helpSearch.exec(['exec']) - - t.match(OUTPUT, /has multiple lines of exec help/, 'outputs detailed results') + t.match(output, /has multiple lines of exec help/, 'outputs detailed results') }) t.test('npm help-search long output with color', async t => { - globRoot = t.testdir(globDir) - config.long = true - npm.color = true - t.teardown(() => { - OUTPUT.length = 0 - config.long = false - npm.color = false - globRoot = null + const { output } = await execHelpSearch(t, ['help-search'], { + config: { + long: true, + color: 'always', + }, }) - await helpSearch.exec(['help-search']) - const highlightedText = chalk.bgBlack.red('help-search') t.equal( - OUTPUT.some(line => line.includes(highlightedText)), + output.split('\n').some(line => line.includes(highlightedText)), true, 'returned highlighted search terms' ) }) t.test('npm help-search no args', async t => { - t.rejects(helpSearch.exec([]), /npm help-search/, 'outputs usage') + await t.rejects(execHelpSearch(t), /npm help-search/, 'outputs usage') }) t.test('npm help-search no matches', async t => { - globRoot = t.testdir(globDir) - t.teardown(() => { - OUTPUT.length = 0 - globRoot = null - }) + const { output } = await execHelpSearch(t, ['asdfasdf']) - await helpSearch.exec(['asdfasdf']) - t.match(OUTPUT, /No matches/) + t.match(output, /No matches/) }) diff --git a/deps/npm/test/lib/commands/help.js b/deps/npm/test/lib/commands/help.js index 1e623dab9386e0..d4e7a81f84a4cd 100644 --- a/deps/npm/test/lib/commands/help.js +++ b/deps/npm/test/lib/commands/help.js @@ -1,351 +1,231 @@ const t = require('tap') -const { EventEmitter } = require('events') - -const npmConfig = { - usage: false, - viewer: undefined, - loglevel: undefined, -} - -let helpSearchArgs = null -const OUTPUT = [] -const npm = { - usage: 'test npm usage', - config: { - get: key => npmConfig[key], - set: (key, value) => { - npmConfig[key] = value - }, - parsedArgv: { - cooked: [], - }, - validate: () => {}, - }, - exec: async (cmd, args) => { - if (cmd === 'help-search') { - helpSearchArgs = args - } else if (cmd === 'help') { - return { usage: 'npm help ' } +const localeCompare = require('@isaacs/string-locale-compare')('en') +const { load: loadMockNpm } = require('../../fixtures/mock-npm.js') +const { cleanCwd } = require('../../fixtures/clean-snapshot') + +const genManPages = (obj) => { + const man = {} + const resPages = new Set() + + for (const [section, pages] of Object.entries(obj)) { + const num = parseInt(section, 10) + man[`man${num}`] = {} + + const sectionPages = [] + for (const name of pages) { + man[`man${num}`][`${name}.${section}`] = `.TH "${name.toUpperCase()}" "${num}"` + sectionPages.push(name.replace(/^npm-/, '')) } - }, - deref: cmd => {}, - output: msg => { - OUTPUT.push(msg) - }, -} -const globDefaults = [ - '/root/man/man1/npm-whoami.1', - '/root/man/man5/npmrc.5', - '/root/man/man7/disputes.7', -] - -let globErr = null -let globResult = globDefaults -let globParam -const glob = (p, cb) => { - globParam = p - return cb(globErr, globResult) -} - -let spawnBin = null -let spawnArgs = null -let spawnCode = 0 -const spawn = (bin, args) => { - spawnBin = bin - spawnArgs = args - const spawnEmitter = new EventEmitter() - process.nextTick(() => { - spawnEmitter.emit('exit', spawnCode) - }) - return spawnEmitter -} + // return a sorted list of uniq pages in order to test completion + for (const p of sectionPages.sort(localeCompare)) { + resPages.add(p) + } + } -let openUrlArg = null -const openUrl = async (npm, url, msg) => { - openUrlArg = url + // man directory name is hardcoded in the command + return { fixtures: { man }, pages: [...resPages.values()] } } -const Help = t.mock('../../../lib/commands/help.js', { - '../../../lib/utils/open-url.js': openUrl, - child_process: { - spawn, +const mockHelp = async (t, { + man = { + 1: ['whoami', 'install', 'star', 'unstar', 'uninstall', 'unpublish'].map(p => `npm-${p}`), + 5: ['npmrc', 'install', 'package-json'], + 7: ['disputes', 'config'], }, - glob, -}) -const help = new Help(npm) + browser = false, + woman = false, + exec: execArgs = null, + spawnErr, + ...opts +} = {}) => { + const config = { + // always set viewer to test the same on all platforms + viewer: browser ? 'browser' : woman ? 'woman' : 'man', + ...opts.config, + } + + let args = null + const mockSpawn = async (...a) => { + args = a + if (spawnErr) { + throw spawnErr + } + } + mockSpawn.open = async (url) => args = [cleanCwd(decodeURI(url))] + + const manPages = genManPages(man) + + const { npm, ...rest } = await loadMockNpm(t, { + npm: ({ other }) => ({ npmRoot: other }), + mocks: { '@npmcli/promise-spawn': mockSpawn }, + otherDirs: { ...manPages.fixtures }, + config, + ...opts, + }) + + const help = await npm.cmd('help') + const exec = execArgs + ? await npm.exec('help', execArgs) + : (...a) => npm.exec('help', a) + + return { + npm, + help, + exec, + manPages: manPages.pages, + getArgs: () => args, + ...rest, + } +} t.test('npm help', async t => { - await help.exec([]) + const { exec, joinedOutput } = await mockHelp(t) + await exec() - t.match(OUTPUT, ['test npm usage'], 'showed npm usage') + t.match(joinedOutput(), 'npm ', 'showed npm usage') }) t.test('npm help completion', async t => { - t.teardown(() => { - globErr = null - }) + const { help, manPages } = await mockHelp(t) const noArgs = await help.completion({ conf: { argv: { remain: [] } } }) - t.strictSame(noArgs, ['help', 'whoami', 'npmrc', 'disputes'], 'outputs available help pages') + t.strictSame(noArgs, ['help', ...manPages], 'outputs available help pages') const threeArgs = await help.completion({ conf: { argv: { remain: ['one', 'two', 'three'] } } }) t.strictSame(threeArgs, [], 'outputs no results when more than 2 args are provided') - globErr = new Error('glob failed') - t.rejects( - help.completion({ conf: { argv: { remain: [] } } }), - /glob failed/, - 'glob errors propagate' - ) }) t.test('npm help multiple args calls search', async t => { - t.teardown(() => { - helpSearchArgs = null - }) - - await help.exec(['run', 'script']) + const { joinedOutput } = await mockHelp(t, { exec: ['run', 'script'] }) - t.strictSame(helpSearchArgs, ['run', 'script'], 'passed the args to help-search') + t.match(joinedOutput(), 'No matches in help for: run script', 'calls help-search') }) t.test('npm help no matches calls search', async t => { - globResult = [] - t.teardown(() => { - helpSearchArgs = null - globResult = globDefaults - }) - - await help.exec(['asdfasdf']) - t.strictSame(helpSearchArgs, ['asdfasdf'], 'passed the args to help-search') -}) - -t.test('npm help glob errors propagate', async t => { - globErr = new Error('glob failed') - t.teardown(() => { - globErr = null - spawnBin = null - spawnArgs = null - }) + const { joinedOutput } = await mockHelp(t, { exec: ['asdfasdf'] }) - await t.rejects(help.exec(['whoami']), /glob failed/, 'glob error propagates') + t.match(joinedOutput(), 'No matches in help for: asdfasdf', 'passed the args to help-search') }) t.test('npm help whoami', async t => { - globResult = ['/root/man/man1/npm-whoami.1.xz'] - t.teardown(() => { - globResult = globDefaults - spawnBin = null - spawnArgs = null - }) - - await help.exec(['whoami']) + const { getArgs } = await mockHelp(t, { exec: ['whoami'] }) + const [spawnBin, spawnArgs] = getArgs() t.equal(spawnBin, 'man', 'calls man by default') - t.strictSame(spawnArgs, [globResult[0]], 'passes the correct arguments') + t.equal(spawnArgs.length, 1) + t.match(spawnArgs[0], /\/man\/man1\/npm-whoami\.1$/) }) t.test('npm help 1 install', async t => { - npmConfig.viewer = 'browser' - globResult = ['/root/man/man5/install.5', '/root/man/man1/npm-install.1'] - - t.teardown(() => { - npmConfig.viewer = undefined - globResult = globDefaults - spawnBin = null - spawnArgs = null + const { getArgs } = await mockHelp(t, { + exec: ['1', 'install'], + browser: true, }) - await help.exec(['1', 'install']) - - t.match(openUrlArg, /commands(\/|\\)npm-install.html$/, 'attempts to open the correct url') - t.ok(openUrlArg.startsWith('file:///'), 'opens with the correct uri schema') + const [url] = getArgs() + t.match(url, /commands\/npm-install.html$/, 'attempts to open the correct url') + t.ok(url.startsWith('file:///'), 'opens with the correct uri schema') }) t.test('npm help 5 install', async t => { - npmConfig.viewer = 'browser' - globResult = ['/root/man/man5/install.5'] - - t.teardown(() => { - npmConfig.viewer = undefined - globResult = globDefaults - globParam = null - spawnBin = null - spawnArgs = null + const { getArgs } = await mockHelp(t, { + exec: ['5', 'install'], + browser: true, }) - await help.exec(['5', 'install']) - - t.match(globParam, /man5/, 'searches only in man5 folder') - t.match(openUrlArg, /configuring-npm(\/|\\)install.html$/, 'attempts to open the correct url') + const [url] = getArgs() + t.match(url, /configuring-npm\/install.html$/, 'attempts to open the correct url') }) t.test('npm help 7 config', async t => { - npmConfig.viewer = 'browser' - globResult = ['/root/man/man7/config.7'] - t.teardown(() => { - npmConfig.viewer = undefined - globParam = null - globResult = globDefaults - spawnBin = null - spawnArgs = null + const { getArgs } = await mockHelp(t, { + exec: ['7', 'config'], + browser: true, }) - await help.exec(['7', 'config']) - - t.match(globParam, /man7/, 'searches only in man5 folder') - t.match(openUrlArg, /using-npm(\/|\\)config.html$/, 'attempts to open the correct url') + const [url] = getArgs() + t.match(url, /using-npm\/config.html$/, 'attempts to open the correct url') }) t.test('npm help package.json redirects to package-json', async t => { - globResult = ['/root/man/man5/package-json.5'] - t.teardown(() => { - globResult = globDefaults - spawnBin = null - spawnArgs = null + const { getArgs } = await mockHelp(t, { + exec: ['package.json'], }) - await help.exec(['package.json']) - + const [spawnBin, spawnArgs] = getArgs() t.equal(spawnBin, 'man', 'calls man by default') - t.match(globParam, /package-json/, 'glob was asked to find package-json') - t.strictSame(spawnArgs, [globResult[0]], 'passes the correct arguments') + t.equal(spawnArgs.length, 1) + t.match(spawnArgs[0], /\/man\/man5\/package-json\.5$/) }) t.test('npm help ?(un)star', async t => { - npmConfig.viewer = 'woman' - globResult = ['/root/man/man1/npm-star.1', '/root/man/man1/npm-unstar.1'] - t.teardown(() => { - npmConfig.viewer = undefined - globResult = globDefaults - spawnBin = null - spawnArgs = null - }) - - await help.exec(['?(un)star']) - - t.equal(spawnBin, 'emacsclient', 'maps woman to emacs correctly') - t.strictSame( - spawnArgs, - ['-e', `(woman-find-file '/root/man/man1/npm-star.1')`], - 'passes the correct arguments' - ) -}) - -t.test('npm help - woman viewer propagates errors', async t => { - npmConfig.viewer = 'woman' - spawnCode = 1 - globResult = ['/root/man/man1/npm-star.1', '/root/man/man1/npm-unstar.1'] - t.teardown(() => { - npmConfig.viewer = undefined - spawnCode = 0 - globResult = globDefaults - spawnBin = null - spawnArgs = null + const { getArgs } = await mockHelp(t, { + exec: ['?(un)star'], + woman: true, }) - await t.rejects( - help.exec(['?(un)star']), - /help process exited with code: 1/, - 'received the correct error' - ) + const [spawnBin, spawnArgs] = getArgs() t.equal(spawnBin, 'emacsclient', 'maps woman to emacs correctly') - t.strictSame( - spawnArgs, - ['-e', `(woman-find-file '/root/man/man1/npm-star.1')`], - 'passes the correct arguments' - ) + t.equal(spawnArgs.length, 2) + t.match(spawnArgs[1], /^\(woman-find-file '/) + t.match(spawnArgs[1], /\/man\/man1\/npm-star.1'\)$/) }) t.test('npm help un*', async t => { - globResult = [ - '/root/man/man1/npm-unstar.1', - '/root/man/man1/npm-uninstall.1', - '/root/man/man1/npm-unpublish.1', - ] - t.teardown(() => { - globResult = globDefaults - spawnBin = null - spawnArgs = null + const { getArgs } = await mockHelp(t, { + exec: ['un*'], }) - await help.exec(['un*']) - + const [spawnBin, spawnArgs] = getArgs() t.equal(spawnBin, 'man', 'calls man by default') - t.strictSame(spawnArgs, ['/root/man/man1/npm-uninstall.1'], 'passes the correct arguments') + t.equal(spawnArgs.length, 1) + t.match(spawnArgs[0], /\/man\/man1\/npm-uninstall\.1$/) }) -t.test('npm help - man viewer propagates errors', async t => { - spawnCode = 1 - globResult = [ - '/root/man/man1/npm-unstar.1', - '/root/man/man1/npm-uninstall.1', - '/root/man/man1/npm-unpublish.1', - ] - t.teardown(() => { - spawnCode = 0 - globResult = globDefaults - spawnBin = null - spawnArgs = null +t.test('npm help - prefers npm help pages', async t => { + const { getArgs } = await mockHelp(t, { + man: { + 6: ['npm-install'], + 1: ['install'], + 5: ['install', 'npm-install'], + }, + exec: ['install'], }) - await t.rejects(help.exec(['un*']), /help process exited with code: 1/, 'received correct error') + const [spawnBin, spawnArgs] = getArgs() t.equal(spawnBin, 'man', 'calls man by default') - t.strictSame(spawnArgs, ['/root/man/man1/npm-uninstall.1'], 'passes the correct arguments') + t.equal(spawnArgs.length, 1) + t.match(spawnArgs[0], /\/man\/man5\/npm-install\.5$/) }) -t.test('npm help with complex installation path finds proper help file', async t => { - npmConfig.viewer = 'browser' - globResult = [ - 'C:/Program Files/node-v14.15.5-win-x64/node_modules/npm/man/man1/npm-install.1', - // glob always returns forward slashes, even on Windows - ] - - t.teardown(() => { - npmConfig.viewer = undefined - globResult = globDefaults - spawnBin = null - spawnArgs = null +t.test('npm help - works in the presence of strange man pages', async t => { + const { getArgs } = await mockHelp(t, { + man: { + '6strange': ['config'], + 1: ['config'], + '5ssl': ['config'], + }, + exec: ['config'], }) - await help.exec(['1', 'install']) - - t.match(openUrlArg, /commands(\/|\\)npm-install.html$/, 'attempts to open the correct url') + const [spawnBin, spawnArgs] = getArgs() + t.equal(spawnBin, 'man', 'calls man by default') + t.equal(spawnArgs.length, 1) + t.match(spawnArgs[0], /\/man\/man1\/config\.1$/) }) -t.test('npm help - prefers npm help pages', async t => { - // Unusual ordering is to get full test coverage of all branches inside the - // sort function. - globResult = [ - '/root/man/man6/npm-install.6', - '/root/man/man1/install.1', - '/root/man/man5/npm-install.5', - ] - t.teardown(() => { - globResult = globDefaults - spawnBin = null - spawnArgs = null +t.test('rejects with code', async t => { + const { exec } = await mockHelp(t, { + spawnErr: Object.assign(new Error('errrrr'), { code: 'SPAWN_ERR' }), }) - await help.exec(['install']) - t.equal(spawnBin, 'man', 'calls man by default') - t.strictSame(spawnArgs, ['/root/man/man5/npm-install.5'], 'passes the correct arguments') + await t.rejects(exec('whoami'), /help process exited with code: SPAWN_ERR/) }) -t.test('npm help - works in the presence of strange man pages', async t => { - // Unusual ordering is to get full test coverage of all branches inside the - // sort function. - globResult = [ - '/root/man/man6/config.6strange', - '/root/man/man1/config.1', - '/root/man/man5/config.5ssl', - ] - t.teardown(() => { - globResult = globDefaults - spawnBin = null - spawnArgs = null +t.test('rejects with no code', async t => { + const { exec } = await mockHelp(t, { + spawnErr: new Error('errrrr'), }) - await help.exec(['config']) - t.equal(spawnBin, 'man', 'calls man by default') - t.strictSame(spawnArgs, ['/root/man/man1/config.1'], 'passes the correct arguments') + await t.rejects(exec('whoami'), /errrrr/) }) diff --git a/deps/npm/test/lib/commands/hook.js b/deps/npm/test/lib/commands/hook.js index 0cd6a7490dda25..01da9dc720dae5 100644 --- a/deps/npm/test/lib/commands/hook.js +++ b/deps/npm/test/lib/commands/hook.js @@ -1,86 +1,81 @@ const t = require('tap') -const { fake: mockNpm } = require('../../fixtures/mock-npm') - -const output = [] -const npm = mockNpm({ - flatOptions: { - json: false, - parseable: false, - unicode: false, - }, - config: { - loglevel: 'info', - }, - output: msg => { - output.push(msg) - }, -}) +const mockNpm = require('../../fixtures/mock-npm') -const pkgTypes = { - semver: 'package', - '@npmcli': 'scope', - npm: 'owner', -} +const mockHook = async (t, { hookResponse, ...npmOpts } = {}) => { + const now = Date.now() -const now = Date.now() -let hookResponse = null -let hookArgs = null -const libnpmhook = { - add: async (pkg, uri, secret, opts) => { - hookArgs = { pkg, uri, secret, opts } - return { id: 1, name: pkg, type: pkgTypes[pkg], endpoint: uri } - }, - ls: async opts => { - hookArgs = opts - let id = 0 - if (hookResponse) { - return hookResponse - } - - return Object.keys(pkgTypes).map(name => ({ - id: ++id, - name, - type: pkgTypes[name], - endpoint: 'https://google.com', - last_delivery: id % 2 === 0 ? now : undefined, - })) - }, - rm: async (id, opts) => { - hookArgs = { id, opts } - const pkg = Object.keys(pkgTypes)[0] - return { - id: 1, - name: pkg, - type: pkgTypes[pkg], - endpoint: 'https://google.com', - } - }, - update: async (id, uri, secret, opts) => { - hookArgs = { id, uri, secret, opts } - const pkg = Object.keys(pkgTypes)[0] - return { id, name: pkg, type: pkgTypes[pkg], endpoint: uri } - }, -} + let hookArgs = null -const Hook = t.mock('../../../lib/commands/hook.js', { - libnpmhook, -}) -const hook = new Hook(npm) + const pkgTypes = { + semver: 'package', + '@npmcli': 'scope', + npm: 'owner', + } + + const libnpmhook = { + add: async (pkg, uri, secret, opts) => { + hookArgs = { pkg, uri, secret, opts } + return { id: 1, name: pkg, type: pkgTypes[pkg], endpoint: uri } + }, + ls: async opts => { + hookArgs = opts + let id = 0 + if (hookResponse) { + return hookResponse + } + + return Object.keys(pkgTypes).map(name => ({ + id: ++id, + name, + type: pkgTypes[name], + endpoint: 'https://google.com', + last_delivery: id % 2 === 0 ? now : undefined, + })) + }, + rm: async (id, opts) => { + hookArgs = { id, opts } + const pkg = Object.keys(pkgTypes)[0] + return { + id: 1, + name: pkg, + type: pkgTypes[pkg], + endpoint: 'https://google.com', + } + }, + update: async (id, uri, secret, opts) => { + hookArgs = { id, uri, secret, opts } + const pkg = Object.keys(pkgTypes)[0] + return { id, name: pkg, type: pkgTypes[pkg], endpoint: uri } + }, + } + + const mock = await mockNpm(t, { + ...npmOpts, + mocks: { + libnpmhook, + ...npmOpts.mocks, + }, + }) + + return { + ...mock, + now, + hook: { exec: (args) => mock.npm.exec('hook', args) }, + hookArgs: () => hookArgs, + } +} t.test('npm hook no args', async t => { + const { hook } = await mockHook(t) await t.rejects(hook.exec([]), hook.usage, 'throws usage with no arguments') }) t.test('npm hook add', async t => { - t.teardown(() => { - hookArgs = null - output.length = 0 - }) - + const { npm, hook, outputs, hookArgs } = await mockHook(t) await hook.exec(['add', 'semver', 'https://google.com', 'some-secret']) t.match( - hookArgs, + hookArgs(), { pkg: 'semver', uri: 'https://google.com', @@ -89,19 +84,15 @@ t.test('npm hook add', async t => { }, 'provided the correct arguments to libnpmhook' ) - t.strictSame(output, ['+ semver -> https://google.com'], 'prints the correct output') + t.strictSame(outputs[0], ['+ semver -> https://google.com'], 'prints the correct output') }) t.test('npm hook add - correct owner hook output', async t => { - t.teardown(() => { - hookArgs = null - output.length = 0 - }) - + const { npm, hook, outputs, hookArgs } = await mockHook(t) await hook.exec(['add', '~npm', 'https://google.com', 'some-secret']) t.match( - hookArgs, + hookArgs(), { pkg: '~npm', uri: 'https://google.com', @@ -110,19 +101,15 @@ t.test('npm hook add - correct owner hook output', async t => { }, 'provided the correct arguments to libnpmhook' ) - t.strictSame(output, ['+ ~npm -> https://google.com'], 'prints the correct output') + t.strictSame(outputs[0], ['+ ~npm -> https://google.com'], 'prints the correct output') }) t.test('npm hook add - correct scope hook output', async t => { - t.teardown(() => { - hookArgs = null - output.length = 0 - }) - + const { npm, hook, outputs, hookArgs } = await mockHook(t) await hook.exec(['add', '@npmcli', 'https://google.com', 'some-secret']) t.match( - hookArgs, + hookArgs(), { pkg: '@npmcli', uri: 'https://google.com', @@ -131,21 +118,21 @@ t.test('npm hook add - correct scope hook output', async t => { }, 'provided the correct arguments to libnpmhook' ) - t.strictSame(output, ['+ @npmcli -> https://google.com'], 'prints the correct output') + t.strictSame(outputs[0], ['+ @npmcli -> https://google.com'], 'prints the correct output') }) t.test('npm hook add - unicode output', async t => { - npm.flatOptions.unicode = true - t.teardown(() => { - npm.flatOptions.unicode = false - hookArgs = null - output.length = 0 + const config = { + unicode: true, + } + const { npm, hook, outputs, hookArgs } = await mockHook(t, { + config, }) await hook.exec(['add', 'semver', 'https://google.com', 'some-secret']) t.match( - hookArgs, + hookArgs(), { pkg: 'semver', uri: 'https://google.com', @@ -154,21 +141,21 @@ t.test('npm hook add - unicode output', async t => { }, 'provided the correct arguments to libnpmhook' ) - t.strictSame(output, ['+ semver ➜ https://google.com'], 'prints the correct output') + t.strictSame(outputs[0], ['+ semver ➜ https://google.com'], 'prints the correct output') }) t.test('npm hook add - json output', async t => { - npm.flatOptions.json = true - t.teardown(() => { - npm.flatOptions.json = false - hookArgs = null - output.length = 0 + const config = { + json: true, + } + const { npm, hook, outputs, hookArgs } = await mockHook(t, { + config, }) await hook.exec(['add', '@npmcli', 'https://google.com', 'some-secret']) t.match( - hookArgs, + hookArgs(), { pkg: '@npmcli', uri: 'https://google.com', @@ -178,7 +165,7 @@ t.test('npm hook add - json output', async t => { 'provided the correct arguments to libnpmhook' ) t.strictSame( - JSON.parse(output[0]), + JSON.parse(outputs[0][0]), { id: 1, name: '@npmcli', @@ -190,17 +177,17 @@ t.test('npm hook add - json output', async t => { }) t.test('npm hook add - parseable output', async t => { - npm.flatOptions.parseable = true - t.teardown(() => { - npm.flatOptions.parseable = false - hookArgs = null - output.length = 0 + const config = { + parseable: true, + } + const { npm, hook, outputs, hookArgs } = await mockHook(t, { + config, }) await hook.exec(['add', '@npmcli', 'https://google.com', 'some-secret']) t.match( - hookArgs, + hookArgs(), { pkg: '@npmcli', uri: 'https://google.com', @@ -209,30 +196,29 @@ t.test('npm hook add - parseable output', async t => { }, 'provided the correct arguments to libnpmhook' ) + t.strictSame( - output[0].split(/\t/), + outputs[0][0].split(/\t/), ['id', 'name', 'type', 'endpoint'], 'prints the correct parseable output headers' ) t.strictSame( - output[1].split(/\t/), + outputs[1][0].split(/\t/), ['1', '@npmcli', 'scope', 'https://google.com'], 'prints the correct parseable values' ) }) t.test('npm hook add - silent output', async t => { - npm.config.set('loglevel', 'silent') - t.teardown(() => { - npm.config.set('loglevel', 'info') - hookArgs = null - output.length = 0 + const config = { loglevel: 'silent' } + const { npm, hook, outputs, hookArgs } = await mockHook(t, { + config, }) await hook.exec(['add', '@npmcli', 'https://google.com', 'some-secret']) t.match( - hookArgs, + hookArgs(), { pkg: '@npmcli', uri: 'https://google.com', @@ -241,55 +227,49 @@ t.test('npm hook add - silent output', async t => { }, 'provided the correct arguments to libnpmhook' ) - t.strictSame(output, [], 'printed no output') + t.strictSame(outputs, [], 'printed no output') }) t.test('npm hook ls', async t => { - t.teardown(() => { - hookArgs = null - output.length = 0 - }) - + const { npm, hook, outputs, hookArgs } = await mockHook(t) await hook.exec(['ls']) t.match( - hookArgs, + hookArgs(), { ...npm.flatOptions, package: undefined, }, 'received the correct arguments' ) - t.equal(output[0], 'You have 3 hooks configured.', 'prints the correct header') - const out = require('../../../lib/utils/ansi-trim')(output[1]) + t.equal(outputs[0][0], 'You have 3 hooks configured.', 'prints the correct header') + const out = require('../../../lib/utils/ansi-trim')(outputs[1][0]) t.match(out, /semver.*https:\/\/google.com.*\n.*\n.*never triggered/, 'prints package hook') t.match(out, /@npmcli.*https:\/\/google.com.*\n.*\n.*triggered just now/, 'prints scope hook') t.match(out, /~npm.*https:\/\/google.com.*\n.*\n.*never triggered/, 'prints owner hook') }) t.test('npm hook ls, no results', async t => { - hookResponse = [] - t.teardown(() => { - hookResponse = null - hookArgs = null - output.length = 0 + const hookResponse = [] + const { npm, hook, outputs, hookArgs } = await mockHook(t, { + hookResponse, }) await hook.exec(['ls']) t.match( - hookArgs, + hookArgs(), { ...npm.flatOptions, package: undefined, }, 'received the correct arguments' ) - t.equal(output[0], "You don't have any hooks configured yet.", 'prints the correct result') + t.equal(outputs[0][0], "You don't have any hooks configured yet.", 'prints the correct result') }) t.test('npm hook ls, single result', async t => { - hookResponse = [ + const hookResponse = [ { id: 1, name: 'semver', @@ -297,47 +277,44 @@ t.test('npm hook ls, single result', async t => { endpoint: 'https://google.com', }, ] - - t.teardown(() => { - hookResponse = null - hookArgs = null - output.length = 0 + const { npm, hook, outputs, hookArgs } = await mockHook(t, { + hookResponse, }) await hook.exec(['ls']) t.match( - hookArgs, + hookArgs(), { ...npm.flatOptions, package: undefined, }, 'received the correct arguments' ) - t.equal(output[0], 'You have one hook configured.', 'prints the correct header') - const out = require('../../../lib/utils/ansi-trim')(output[1]) + t.equal(outputs[0][0], 'You have one hook configured.', 'prints the correct header') + const out = require('../../../lib/utils/ansi-trim')(outputs[1][0]) t.match(out, /semver.*https:\/\/google.com.*\n.*\n.*never triggered/, 'prints package hook') }) t.test('npm hook ls - json output', async t => { - npm.flatOptions.json = true - t.teardown(() => { - npm.flatOptions.json = false - hookArgs = null - output.length = 0 + const config = { + json: true, + } + const { npm, hook, outputs, hookArgs } = await mockHook(t, { + config, }) await hook.exec(['ls']) t.match( - hookArgs, + hookArgs(), { ...npm.flatOptions, package: undefined, }, 'received the correct arguments' ) - const out = JSON.parse(output[0]) + const out = JSON.parse(outputs[0]) t.match( out, [ @@ -365,17 +342,17 @@ t.test('npm hook ls - json output', async t => { }) t.test('npm hook ls - parseable output', async t => { - npm.flatOptions.parseable = true - t.teardown(() => { - npm.flatOptions.parseable = false - hookArgs = null - output.length = 0 + const config = { + parseable: true, + } + const { npm, hook, outputs, hookArgs, now } = await mockHook(t, { + config, }) await hook.exec(['ls']) t.match( - hookArgs, + hookArgs(), { ...npm.flatOptions, package: undefined, @@ -383,7 +360,7 @@ t.test('npm hook ls - parseable output', async t => { 'received the correct arguments' ) t.strictSame( - output.map(line => line.split(/\t/)), + outputs.map(line => line[0].split(/\t/)), [ ['id', 'name', 'type', 'endpoint', 'last_delivery'], ['1', 'semver', 'package', 'https://google.com', ''], @@ -395,99 +372,92 @@ t.test('npm hook ls - parseable output', async t => { }) t.test('npm hook ls - silent output', async t => { - npm.config.set('loglevel', 'silent') - t.teardown(() => { - npm.config.set('loglevel', 'info') - hookArgs = null - output.length = 0 + const config = { loglevel: 'silent' } + const { npm, hook, outputs, hookArgs } = await mockHook(t, { + config, }) await hook.exec(['ls']) t.match( - hookArgs, + hookArgs(), { ...npm.flatOptions, package: undefined, }, 'received the correct arguments' ) - t.strictSame(output, [], 'printed no output') + t.strictSame(outputs, [], 'printed no output') }) t.test('npm hook rm', async t => { - t.teardown(() => { - hookArgs = null - output.length = 0 + const { npm, hook, outputs, hookArgs } = await mockHook(t, { }) - await hook.exec(['rm', '1']) t.match( - hookArgs, + hookArgs(), { id: '1', opts: npm.flatOptions, }, 'received the correct arguments' ) - t.strictSame(output, ['- semver X https://google.com'], 'printed the correct output') + t.strictSame(outputs[0], ['- semver X https://google.com'], 'printed the correct output') }) t.test('npm hook rm - unicode output', async t => { - npm.flatOptions.unicode = true - t.teardown(() => { - npm.flatOptions.unicode = false - hookArgs = null - output.length = 0 + const config = { + unicode: true, + } + const { npm, hook, outputs, hookArgs } = await mockHook(t, { + config, }) await hook.exec(['rm', '1']) t.match( - hookArgs, + hookArgs(), { id: '1', opts: npm.flatOptions, }, 'received the correct arguments' ) - t.strictSame(output, ['- semver ✘ https://google.com'], 'printed the correct output') + t.strictSame(outputs[0], ['- semver ✘ https://google.com'], 'printed the correct output') }) t.test('npm hook rm - silent output', async t => { - npm.config.set('loglevel', 'silent') - t.teardown(() => { - npm.config.set('loglevel', 'info') - hookArgs = null - output.length = 0 + const config = { loglevel: 'silent' } + const { npm, hook, outputs, hookArgs } = await mockHook(t, { + config, }) await hook.exec(['rm', '1']) t.match( - hookArgs, + hookArgs(), { id: '1', opts: npm.flatOptions, }, 'received the correct arguments' ) - t.strictSame(output, [], 'printed no output') + t.strictSame(outputs, [], 'printed no output') }) t.test('npm hook rm - json output', async t => { - npm.flatOptions.json = true - t.teardown(() => { - npm.flatOptions.json = false - hookArgs = null - output.length = 0 + const config = { + json: true, + } + const { npm, hook, outputs, hookArgs } = await mockHook(t, { + config, }) await hook.exec(['rm', '1']) t.match( - hookArgs, + hookArgs(), { id: '1', opts: npm.flatOptions, @@ -495,7 +465,7 @@ t.test('npm hook rm - json output', async t => { 'received the correct arguments' ) t.strictSame( - JSON.parse(output[0]), + JSON.parse(outputs[0]), { id: 1, name: 'semver', @@ -507,17 +477,17 @@ t.test('npm hook rm - json output', async t => { }) t.test('npm hook rm - parseable output', async t => { - npm.flatOptions.parseable = true - t.teardown(() => { - npm.flatOptions.parseable = false - hookArgs = null - output.length = 0 + const config = { + parseable: true, + } + const { npm, hook, outputs, hookArgs } = await mockHook(t, { + config, }) await hook.exec(['rm', '1']) t.match( - hookArgs, + hookArgs(), { id: '1', opts: npm.flatOptions, @@ -525,7 +495,7 @@ t.test('npm hook rm - parseable output', async t => { 'received the correct arguments' ) t.strictSame( - output.map(line => line.split(/\t/)), + outputs.map(line => line[0].split(/\t/)), [ ['id', 'name', 'type', 'endpoint'], ['1', 'semver', 'package', 'https://google.com'], @@ -535,15 +505,12 @@ t.test('npm hook rm - parseable output', async t => { }) t.test('npm hook update', async t => { - t.teardown(() => { - hookArgs = null - output.length = 0 + const { npm, hook, outputs, hookArgs } = await mockHook(t, { }) - await hook.exec(['update', '1', 'https://google.com', 'some-secret']) t.match( - hookArgs, + hookArgs(), { id: '1', uri: 'https://google.com', @@ -552,21 +519,21 @@ t.test('npm hook update', async t => { }, 'received the correct arguments' ) - t.strictSame(output, ['+ semver -> https://google.com'], 'printed the correct output') + t.strictSame(outputs[0], ['+ semver -> https://google.com'], 'printed the correct output') }) t.test('npm hook update - unicode', async t => { - npm.flatOptions.unicode = true - t.teardown(() => { - npm.flatOptions.unicode = false - hookArgs = null - output.length = 0 + const config = { + unicode: true, + } + const { npm, hook, outputs, hookArgs } = await mockHook(t, { + config, }) await hook.exec(['update', '1', 'https://google.com', 'some-secret']) t.match( - hookArgs, + hookArgs(), { id: '1', uri: 'https://google.com', @@ -575,21 +542,21 @@ t.test('npm hook update - unicode', async t => { }, 'received the correct arguments' ) - t.strictSame(output, ['+ semver ➜ https://google.com'], 'printed the correct output') + t.strictSame(outputs[0], ['+ semver ➜ https://google.com'], 'printed the correct output') }) t.test('npm hook update - json output', async t => { - npm.flatOptions.json = true - t.teardown(() => { - npm.flatOptions.json = false - hookArgs = null - output.length = 0 + const config = { + json: true, + } + const { npm, hook, outputs, hookArgs } = await mockHook(t, { + config, }) await hook.exec(['update', '1', 'https://google.com', 'some-secret']) t.match( - hookArgs, + hookArgs(), { id: '1', uri: 'https://google.com', @@ -599,7 +566,7 @@ t.test('npm hook update - json output', async t => { 'received the correct arguments' ) t.strictSame( - JSON.parse(output[0]), + JSON.parse(outputs[0]), { id: '1', name: 'semver', @@ -611,17 +578,17 @@ t.test('npm hook update - json output', async t => { }) t.test('npm hook update - parseable output', async t => { - npm.flatOptions.parseable = true - t.teardown(() => { - npm.flatOptions.parseable = false - hookArgs = null - output.length = 0 + const config = { + parseable: true, + } + const { npm, hook, outputs, hookArgs } = await mockHook(t, { + config, }) await hook.exec(['update', '1', 'https://google.com', 'some-secret']) t.match( - hookArgs, + hookArgs(), { id: '1', uri: 'https://google.com', @@ -631,7 +598,7 @@ t.test('npm hook update - parseable output', async t => { 'received the correct arguments' ) t.strictSame( - output.map(line => line.split(/\t/)), + outputs.map(line => line[0].split(/\t/)), [ ['id', 'name', 'type', 'endpoint'], ['1', 'semver', 'package', 'https://google.com'], @@ -641,17 +608,15 @@ t.test('npm hook update - parseable output', async t => { }) t.test('npm hook update - silent output', async t => { - npm.config.set('loglevel', 'silent') - t.teardown(() => { - npm.config.set('loglevel', 'info') - hookArgs = null - output.length = 0 + const config = { loglevel: 'silent' } + const { npm, hook, outputs, hookArgs } = await mockHook(t, { + config, }) await hook.exec(['update', '1', 'https://google.com', 'some-secret']) t.match( - hookArgs, + hookArgs(), { id: '1', uri: 'https://google.com', @@ -660,5 +625,5 @@ t.test('npm hook update - silent output', async t => { }, 'received the correct arguments' ) - t.strictSame(output, [], 'printed no output') + t.strictSame(outputs, [], 'printed no output') }) diff --git a/deps/npm/test/lib/commands/init.js b/deps/npm/test/lib/commands/init.js index d11e0091b7cff3..2d59f47d9842de 100644 --- a/deps/npm/test/lib/commands/init.js +++ b/deps/npm/test/lib/commands/init.js @@ -1,108 +1,88 @@ const t = require('tap') -const fs = require('fs') -const { resolve } = require('path') -const { fake: mockNpm } = require('../../fixtures/mock-npm') - -const config = { - cache: 'bad-cache-dir', - 'init-module': '~/.npm-init.js', - yes: true, -} -const flatOptions = { - cache: 'test-config-dir/_cacache', - npxCache: 'test-config-dir/_npx', -} -const npm = mockNpm({ - flatOptions, - config, -}) -const mocks = { - npmlog: { - disableProgress: () => null, - enableProgress: () => null, - }, - 'proc-log': { - info: () => null, - pause: () => null, - resume: () => null, - silly: () => null, - }, +const fs = require('fs/promises') +const { resolve, basename } = require('path') +const _mockNpm = require('../../fixtures/mock-npm') +const { cleanTime } = require('../../fixtures/clean-snapshot') + +t.cleanSnapshot = cleanTime + +const mockNpm = async (t, { noLog, libnpmexec, initPackageJson, packageJson, ...opts } = {}) => { + const res = await _mockNpm(t, { + ...opts, + mocks: { + ...(libnpmexec ? { libnpmexec } : {}), + ...(initPackageJson ? { 'init-package-json': initPackageJson } : {}), + ...(packageJson ? { '@npmcli/package-json': packageJson } : {}), + }, + globals: { + // init-package-json prints directly to console.log + // this avoids poluting test output with those logs + ...(noLog ? { 'console.log': () => {} } : {}), + }, + }) + + return res } -const Init = t.mock('../../../lib/commands/init.js', mocks) -const init = new Init(npm) -const _cwd = process.cwd() -const _consolelog = console.log -const noop = () => {} - -t.afterEach(() => { - config.yes = true - config.package = undefined - process.chdir(_cwd) - console.log = _consolelog + +t.test('displays output', async t => { + const { npm, joinedOutput } = await mockNpm(t, { + initPackageJson: (...args) => args[3](), + }) + + await npm.exec('init', []) + t.matchSnapshot(joinedOutput(), 'displays helper info') }) t.test('classic npm init -y', async t => { - npm.localPrefix = t.testdir({}) - - // init-package-json prints directly to console.log - // this avoids poluting test output with those logs - console.log = noop + const { npm, prefix } = await mockNpm(t, { + config: { yes: true }, + noLog: true, + }) - process.chdir(npm.localPrefix) - await init.exec([]) + await npm.exec('init', []) - const pkg = require(resolve(npm.localPrefix, 'package.json')) + const pkg = require(resolve(prefix, 'package.json')) t.equal(pkg.version, '1.0.0') t.equal(pkg.license, 'ISC') }) t.test('classic interactive npm init', async t => { - npm.localPrefix = t.testdir({}) - config.yes = undefined + t.plan(1) - const Init = t.mock('../../../lib/commands/init.js', { - ...mocks, - 'init-package-json': (path, initFile, config, cb) => { + const { npm } = await mockNpm(t, { + initPackageJson: (...args) => { t.equal( - path, + args[0], resolve(npm.localPrefix), 'should start init package.json in expected path' ) - cb() + args[3]() }, }) - const init = new Init(npm) - process.chdir(npm.localPrefix) - await init.exec([]) + await npm.exec('init', []) }) t.test('npm init ', async t => { - t.plan(3) - npm.localPrefix = t.testdir({}) + t.plan(1) - const Init = t.mock('../../../lib/commands/init.js', { - libnpmexec: ({ args, cache, npxCache }) => { + const { npm } = await mockNpm(t, { + libnpmexec: ({ args }) => { t.same( args, ['create-react-app@*'], 'should npx with listed packages' ) - t.same(cache, flatOptions.cache) - t.same(npxCache, flatOptions.npxCache) }, }) - const init = new Init(npm) - process.chdir(npm.localPrefix) - await init.exec(['react-app']) + await npm.exec('init', ['react-app']) }) t.test('npm init -- other-args', async t => { t.plan(1) - npm.localPrefix = t.testdir({}) - const Init = t.mock('../../../lib/commands/init.js', { + const { npm } = await mockNpm(t, { libnpmexec: ({ args }) => { t.same( args, @@ -110,18 +90,16 @@ t.test('npm init -- other-args', async t => { 'should npm exec with expected args' ) }, + }) - const init = new Init(npm) - process.chdir(npm.localPrefix) - await init.exec(['react-app', 'my-path', '--some-option', 'some-value']) + await npm.exec('init', ['react-app', 'my-path', '--some-option', 'some-value']) }) t.test('npm init @scope/name', async t => { t.plan(1) - npm.localPrefix = t.testdir({}) - const Init = t.mock('../../../lib/commands/init.js', { + const { npm } = await mockNpm(t, { libnpmexec: ({ args }) => { t.same( args, @@ -130,17 +108,14 @@ t.test('npm init @scope/name', async t => { ) }, }) - const init = new Init(npm) - process.chdir(npm.localPrefix) - await init.exec(['@npmcli/something']) + await npm.exec('init', ['@npmcli/something']) }) t.test('npm init @scope@spec', async t => { t.plan(1) - npm.localPrefix = t.testdir({}) - const Init = t.mock('../../../lib/commands/init.js', { + const { npm } = await mockNpm(t, { libnpmexec: ({ args }) => { t.same( args, @@ -149,17 +124,14 @@ t.test('npm init @scope@spec', async t => { ) }, }) - const init = new Init(npm) - process.chdir(npm.localPrefix) - await init.exec(['@npmcli@foo']) + await npm.exec('init', ['@npmcli@foo']) }) t.test('npm init @scope/name@spec', async t => { t.plan(1) - npm.localPrefix = t.testdir({}) - const Init = t.mock('../../../lib/commands/init.js', { + const { npm } = await mockNpm(t, { libnpmexec: ({ args }) => { t.same( args, @@ -168,17 +140,13 @@ t.test('npm init @scope/name@spec', async t => { ) }, }) - const init = new Init(npm) - process.chdir(npm.localPrefix) - await init.exec(['@npmcli/something@foo']) + await npm.exec('init', ['@npmcli/something@foo']) }) t.test('npm init git spec', async t => { t.plan(1) - npm.localPrefix = t.testdir({}) - - const Init = t.mock('../../../lib/commands/init.js', { + const { npm } = await mockNpm(t, { libnpmexec: ({ args }) => { t.same( args, @@ -187,17 +155,14 @@ t.test('npm init git spec', async t => { ) }, }) - const init = new Init(npm) - process.chdir(npm.localPrefix) - await init.exec(['npm/something']) + await npm.exec('init', ['npm/something']) }) t.test('npm init @scope', async t => { t.plan(1) - npm.localPrefix = t.testdir({}) - const Init = t.mock('../../../lib/commands/init.js', { + const { npm } = await mockNpm(t, { libnpmexec: ({ args }) => { t.same( args, @@ -206,18 +171,15 @@ t.test('npm init @scope', async t => { ) }, }) - const init = new Init(npm) - process.chdir(npm.localPrefix) - await init.exec(['@npmcli']) + await npm.exec('init', ['@npmcli']) }) t.test('npm init tgz', async t => { - npm.localPrefix = t.testdir({}) + const { npm } = await mockNpm(t) - process.chdir(npm.localPrefix) await t.rejects( - init.exec(['something.tgz']), + npm.exec('init', ['something.tgz']), /Unrecognized initializer: something.tgz/, 'should throw error when using an unsupported spec' ) @@ -225,9 +187,8 @@ t.test('npm init tgz', async t => { t.test('npm init @next', async t => { t.plan(1) - npm.localPrefix = t.testdir({}) - const Init = t.mock('../../../lib/commands/init.js', { + const { npm } = await mockNpm(t, { libnpmexec: ({ args }) => { t.same( args, @@ -236,25 +197,19 @@ t.test('npm init @next', async t => { ) }, }) - const init = new Init(npm) - process.chdir(npm.localPrefix) - await init.exec(['something@next']) + await npm.exec('init', ['something@next']) }) t.test('npm init exec error', async t => { - npm.localPrefix = t.testdir({}) - - const Init = t.mock('../../../lib/commands/init.js', { - libnpmexec: async ({ args }) => { + const { npm } = await mockNpm(t, { + libnpmexec: async () => { throw new Error('ERROR') }, }) - const init = new Init(npm) - process.chdir(npm.localPrefix) await t.rejects( - init.exec(['something@next']), + npm.exec('init', ['something@next']), /ERROR/, 'should exit with exec error' ) @@ -262,9 +217,8 @@ t.test('npm init exec error', async t => { t.test('should not rewrite flatOptions', async t => { t.plan(1) - npm.localPrefix = t.testdir({}) - const Init = t.mock('../../../lib/commands/init.js', { + const { npm } = await mockNpm(t, { libnpmexec: async ({ args }) => { t.same( args, @@ -273,270 +227,217 @@ t.test('should not rewrite flatOptions', async t => { ) }, }) - const init = new Init(npm) - process.chdir(npm.localPrefix) - await init.exec(['react-app', 'my-app']) + await npm.exec('init', ['react-app', 'my-app']) }) t.test('npm init cancel', async t => { - t.plan(2) - npm.localPrefix = t.testdir({}) - - const Init = t.mock('../../../lib/commands/init.js', { - ...mocks, - 'init-package-json': (dir, initFile, config, cb) => cb( + const { npm, logs } = await mockNpm(t, { + initPackageJson: (...args) => args[3]( new Error('canceled') ), - 'proc-log': { - ...mocks['proc-log'], - warn: (title, msg) => { - t.equal(title, 'init', 'should have init title') - t.equal(msg, 'canceled', 'should log canceled') - }, - }, }) - const init = new Init(npm) - process.chdir(npm.localPrefix) - await init.exec([]) + await npm.exec('init', []) + + t.equal(logs.warn[0][0], 'init', 'should have init title') + t.equal(logs.warn[0][1], 'canceled', 'should log canceled') }) t.test('npm init error', async t => { - npm.localPrefix = t.testdir({}) - - const Init = t.mock('../../../lib/commands/init.js', { - ...mocks, - 'init-package-json': (dir, initFile, config, cb) => cb( + const { npm } = await mockNpm(t, { + initPackageJson: (...args) => args[3]( new Error('Unknown Error') ), }) - const init = new Init(npm) - process.chdir(npm.localPrefix) await t.rejects( - init.exec([]), + npm.exec('init', []), /Unknown Error/, 'should throw error' ) }) -t.test('workspaces', t => { - t.test('no args', async t => { - t.teardown(() => { - npm._mockOutputs.length = 0 - }) - npm._mockOutputs.length = 0 - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'top-level', - }), - }) - - const Init = t.mock('../../../lib/commands/init.js', { - ...mocks, - 'init-package-json': (dir, initFile, config, cb) => { - t.equal(dir, resolve(npm.localPrefix, 'a'), 'should use the ws path') - cb() +t.test('workspaces', async t => { + await t.test('no args -- yes', async t => { + const { npm, prefix, joinedOutput } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'top-level', + }), }, + config: { workspace: 'a', yes: true }, + noLog: true, }) - const init = new Init(npm) - await init.execWorkspaces([], ['a']) - t.matchSnapshot(npm._mockOutputs, 'should print helper info') - }) - t.test('post workspace-init reify', async t => { - const _consolelog = console.log - console.log = () => null - t.teardown(() => { - console.log = _consolelog - npm._mockOutputs.length = 0 - delete npm.flatOptions.workspacesUpdate - }) - npm.started = Date.now() - npm._mockOutputs.length = 0 - npm.flatOptions.workspacesUpdate = true - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'top-level', - }), - }) + await npm.exec('init', []) - const Init = t.mock('../../../lib/commands/init.js', { - ...mocks, - 'init-package-json': (dir, initFile, config, cb) => { - t.equal(dir, resolve(npm.localPrefix, 'a'), 'should use the ws path') - return require('init-package-json')(dir, initFile, config, cb) - }, - }) - const init = new Init(npm) - await init.execWorkspaces([], ['a']) - const output = npm._mockOutputs.map(arr => arr.map(i => i.replace(/[0-9]*m?s$/, '100ms'))) - t.matchSnapshot(output, 'should print helper info') - const lockFilePath = resolve(npm.localPrefix, 'package-lock.json') - const lockFile = fs.readFileSync(lockFilePath, { encoding: 'utf8' }) - t.matchSnapshot(lockFile, 'should reify tree on init ws complete') - }) - - t.test('no args, existing folder', async t => { - t.teardown(() => { - npm._mockOutputs.length = 0 - }) - // init-package-json prints directly to console.log - // this avoids poluting test output with those logs - console.log = noop + const pkg = require(resolve(prefix, 'a/package.json')) + t.equal(pkg.name, 'a') + t.equal(pkg.version, '1.0.0') + t.equal(pkg.license, 'ISC') - npm.localPrefix = t.testdir({ - packages: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - }), - }, - }, - 'package.json': JSON.stringify({ - name: 'top-level', - workspaces: ['packages/a'], - }), - }) + t.matchSnapshot(joinedOutput(), 'should print helper info') - await init.execWorkspaces([], ['packages/a']) - - t.matchSnapshot(npm._mockOutputs, 'should print helper info') + const lock = require(resolve(prefix, 'package-lock.json')) + t.ok(lock.packages.a) }) - t.test('with arg but missing workspace folder', async t => { - t.teardown(() => { - npm._mockOutputs.length = 0 - }) - // init-package-json prints directly to console.log - // this avoids poluting test output with those logs - console.log = noop - - npm.localPrefix = t.testdir({ - node_modules: { - a: t.fixture('symlink', '../a'), - 'create-index': { - 'index.js': ``, + await t.test('no args, existing folder', async t => { + const { npm, prefix } = await mockNpm(t, { + prefixDir: { + packages: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '2.0.0', + }), + }, }, - }, - a: { 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', + name: 'top-level', + workspaces: ['packages/a'], }), }, - 'package.json': JSON.stringify({ - name: 'top-level', - }), + config: { workspace: 'packages/a', yes: true }, + noLog: true, }) - await init.execWorkspaces([], ['packages/a']) + await npm.exec('init', []) - t.matchSnapshot(npm._mockOutputs, 'should print helper info') + const pkg = require(resolve(prefix, 'packages/a/package.json')) + t.equal(pkg.name, 'a') + t.equal(pkg.version, '2.0.0') + t.equal(pkg.license, 'ISC') }) - t.test('fail parsing top-level package.json to set workspace', async t => { - // init-package-json prints directly to console.log - // this avoids poluting test output with those logs - console.log = noop - - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'top-level', - }), - }) - - const Init = t.mock('../../../lib/commands/init.js', { - ...mocks, - '@npmcli/package-json': { + await t.test('fail parsing top-level package.json to set workspace', async t => { + const { npm } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'top-level', + }), + }, + packageJson: { async load () { throw new Error('ERR') }, }, + config: { workspace: 'a', yes: true }, + noLog: true, }) - const init = new Init(npm) await t.rejects( - init.execWorkspaces([], ['a']), + npm.exec('init', []), /ERR/, 'should exit with error' ) }) - t.test('missing top-level package.json when settting workspace', async t => { - // init-package-json prints directly to console.log - // this avoids poluting test output with those logs - console.log = noop - - npm.localPrefix = t.testdir({}) - - const Init = require('../../../lib/commands/init.js') - const init = new Init(npm) + await t.test('missing top-level package.json when settting workspace', async t => { + const { npm, logs } = await mockNpm(t, { + config: { workspace: 'a' }, + }) await t.rejects( - init.execWorkspaces([], ['a']), + npm.exec('init', []), { code: 'ENOENT' }, 'should exit with missing package.json file error' ) + + t.equal(logs.warn[0][0], 'Missing package.json. Try with `--include-workspace-root`.') + }) + + await t.test('bad package.json when settting workspace', async t => { + const { npm, logs } = await mockNpm(t, { + prefixDir: { + 'package.json': '{{{{', + }, + config: { workspace: 'a' }, + }) + + await t.rejects( + npm.exec('init', []), + { code: 'EJSONPARSE' }, + 'should exit with parse file error' + ) + + t.strictSame(logs.warn, []) }) - t.test('using args', async t => { - npm.localPrefix = t.testdir({ - b: { + await t.test('using args - no package.json', async t => { + const { npm, prefix } = await mockNpm(t, { + prefixDir: { + b: { + 'package.json': JSON.stringify({ + name: 'b', + }), + }, 'package.json': JSON.stringify({ - name: 'b', + name: 'top-level', + workspaces: ['b'], }), }, - 'package.json': JSON.stringify({ - name: 'top-level', - workspaces: ['b'], - }), + // Important: exec did not write a package.json here + libnpmexec: async () => {}, + config: { workspace: 'a', yes: true }, }) - const Init = t.mock('../../../lib/commands/init.js', { - ...mocks, - libnpmexec: ({ args, path }) => { - t.same( - args, - ['create-react-app@*'], - 'should npx with listed packages' - ) - t.same( - path, - resolve(npm.localPrefix, 'a'), - 'should use workspace path' - ) - fs.writeFileSync( - resolve(npm.localPrefix, 'a/package.json'), - JSON.stringify({ name: 'a' }) - ) + await npm.exec('init', ['react-app']) + + const pkg = require(resolve(prefix, 'package.json')) + t.strictSame(pkg.workspaces, ['b'], 'pkg workspaces did not get updated') + }) + + await t.test('init template - bad package.json', async t => { + const { npm, prefix } = await mockNpm(t, { + prefixDir: { + b: { + 'package.json': JSON.stringify({ + name: 'b', + }), + }, + 'package.json': JSON.stringify({ + name: 'top-level', + workspaces: ['b'], + }), + }, + initPackageJson: async (...args) => { + const [dir] = args + if (dir.endsWith('c')) { + await fs.writeFile(resolve(dir, 'package.json'), JSON.stringify({ + name: basename(dir), + }), 'utf-8') + } + args[3]() }, + config: { yes: true, workspace: ['a', 'c'] }, }) - const init = new Init(npm) - await init.execWorkspaces(['react-app'], ['a']) - }) + await npm.exec('init', []) - t.end() -}) + const pkg = require(resolve(prefix, 'package.json')) + t.strictSame(pkg.workspaces, ['b', 'c']) -t.test('npm init workspces with root', async t => { - t.teardown(() => { - npm._mockOutputs.length = 0 + const lock = require(resolve(prefix, 'package-lock.json')) + t.notOk(lock.packages.a) }) - npm.localPrefix = t.testdir({}) - npm.flatOptions.includeWorkspaceRoot = true - // init-package-json prints directly to console.log - // this avoids poluting test output with those logs - console.log = noop + t.test('workspace root', async t => { + const { npm } = await mockNpm(t, { + config: { workspace: 'packages/a', 'include-workspace-root': true, yes: true }, + noLog: true, + }) + + await npm.exec('init', []) - process.chdir(npm.localPrefix) - await init.execWorkspaces([], ['packages/a']) - const pkg = require(resolve(npm.localPrefix, 'package.json')) - t.equal(pkg.version, '1.0.0') - t.equal(pkg.license, 'ISC') - t.matchSnapshot(npm._mockOutputs, 'does not print helper info') + const pkg = require(resolve(npm.localPrefix, 'package.json')) + t.equal(pkg.version, '1.0.0') + t.equal(pkg.license, 'ISC') + t.strictSame(pkg.workspaces, ['packages/a']) + + const ws = require(resolve(npm.localPrefix, 'packages/a/package.json')) + t.equal(ws.version, '1.0.0') + t.equal(ws.license, 'ISC') + }) }) diff --git a/deps/npm/test/lib/commands/install.js b/deps/npm/test/lib/commands/install.js index 4c3251f52fbc04..1be42d6e6125f0 100644 --- a/deps/npm/test/lib/commands/install.js +++ b/deps/npm/test/lib/commands/install.js @@ -1,9 +1,5 @@ const t = require('tap') - -const { load: _loadMockNpm } = require('../../fixtures/mock-npm') - -// Make less churn in the test to pass in mocks only signature -const loadMockNpm = (t, mocks) => _loadMockNpm(t, { mocks }) +const { load: loadMockNpm } = require('../../fixtures/mock-npm') t.test('exec commands', async t => { await t.test('with args, dev=true', async t => { @@ -13,29 +9,32 @@ t.test('exec commands', async t => { let ARB_OBJ = null const { npm } = await loadMockNpm(t, { - '@npmcli/run-script': ({ event }) => { - SCRIPTS.push(event) - }, - '@npmcli/arborist': function (args) { - ARB_ARGS = args - ARB_OBJ = this - this.reify = () => { - REIFY_CALLED = true - } + mocks: { + '@npmcli/run-script': ({ event }) => { + SCRIPTS.push(event) + }, + '@npmcli/arborist': function (args) { + ARB_ARGS = args + ARB_OBJ = this + this.reify = () => { + REIFY_CALLED = true + } + }, + '{LIB}/utils/reify-finish.js': (_, arb) => { + if (arb !== ARB_OBJ) { + throw new Error('got wrong object passed to reify-finish') + } + }, }, - '../../lib/utils/reify-finish.js': (npm, arb) => { - if (arb !== ARB_OBJ) { - throw new Error('got wrong object passed to reify-finish') - } + config: { + // This is here because CI calls tests with `--ignore-scripts`, which config + // picks up from argv + 'ignore-scripts': false, + 'audit-level': 'low', + dev: true, }, }) - // This is here because CI calls tests with `--ignore-scripts`, which config - // picks up from argv - npm.config.set('ignore-scripts', false) - npm.config.set('audit-level', 'low') - npm.config.set('dev', true) - await npm.exec('install', ['fizzbuzz']) t.match( @@ -54,24 +53,28 @@ t.test('exec commands', async t => { let ARB_OBJ = null const { npm } = await loadMockNpm(t, { - '@npmcli/run-script': ({ event }) => { - SCRIPTS.push(event) - }, - '@npmcli/arborist': function (args) { - ARB_ARGS = args - ARB_OBJ = this - this.reify = () => { - REIFY_CALLED = true - } + mocks: { + '@npmcli/run-script': ({ event }) => { + SCRIPTS.push(event) + }, + '@npmcli/arborist': function (args) { + ARB_ARGS = args + ARB_OBJ = this + this.reify = () => { + REIFY_CALLED = true + } + }, + '{LIB}/utils/reify-finish.js': (_, arb) => { + if (arb !== ARB_OBJ) { + throw new Error('got wrong object passed to reify-finish') + } + }, }, - '../../lib/utils/reify-finish.js': (npm, arb) => { - if (arb !== ARB_OBJ) { - throw new Error('got wrong object passed to reify-finish') - } + config: { + }, }) - npm.config.set('ignore-scripts', false) await npm.exec('install', []) t.match(ARB_ARGS, { global: false, path: npm.prefix }) t.equal(REIFY_CALLED, true, 'called reify') @@ -90,17 +93,22 @@ t.test('exec commands', async t => { const SCRIPTS = [] let REIFY_CALLED = false const { npm } = await loadMockNpm(t, { - '../../lib/utils/reify-finish.js': async () => {}, - '@npmcli/run-script': ({ event }) => { - SCRIPTS.push(event) + mocks: { + '{LIB}/utils/reify-finish.js': async () => {}, + '@npmcli/run-script': ({ event }) => { + SCRIPTS.push(event) + }, + '@npmcli/arborist': function () { + this.reify = () => { + REIFY_CALLED = true + } + }, }, - '@npmcli/arborist': function () { - this.reify = () => { - REIFY_CALLED = true - } + config: { + 'ignore-scripts': true, }, }) - npm.config.set('ignore-scripts', true) + await npm.exec('install', []) t.equal(REIFY_CALLED, true, 'called reify') t.strictSame(SCRIPTS, [], 'no scripts when adding dep') @@ -111,18 +119,22 @@ t.test('exec commands', async t => { let ARB_ARGS = null let REIFY_CALLED const { npm } = await loadMockNpm(t, { - '@npmcli/run-script': ({ event }) => { - SCRIPTS.push(event) + mocks: { + '@npmcli/run-script': ({ event }) => { + SCRIPTS.push(event) + }, + '{LIB}/utils/reify-finish.js': async () => {}, + '@npmcli/arborist': function (args) { + ARB_ARGS = args + this.reify = () => { + REIFY_CALLED = true + } + }, }, - '../../lib/utils/reify-finish.js': async () => {}, - '@npmcli/arborist': function (args) { - ARB_ARGS = args - this.reify = () => { - REIFY_CALLED = true - } + config: { + global: true, }, }) - npm.config.set('global', true) await npm.exec('install', []) t.match( ARB_ARGS, @@ -130,18 +142,22 @@ t.test('exec commands', async t => { ) t.equal(REIFY_CALLED, true, 'called reify') t.strictSame(SCRIPTS, [], 'no scripts when installing globally') - t.equal(npm.config.get('audit', 'cli'), false) + t.notOk(npm.config.get('audit', 'cli')) }) await t.test('should not install invalid global package name', async t => { const { npm } = await loadMockNpm(t, { - '@npmcli/run-script': () => {}, - '../../lib/utils/reify-finish.js': async () => {}, - '@npmcli/arborist': function (args) { - throw new Error('should not reify') + mocks: { + '@npmcli/run-script': () => {}, + '{LIB}/utils/reify-finish.js': async () => {}, + '@npmcli/arborist': function (args) { + throw new Error('should not reify') + }, + }, + config: { + global: true, }, }) - npm.config.set('global', true) await t.rejects( npm.exec('install', ['']), /Usage:/, @@ -151,41 +167,49 @@ t.test('exec commands', async t => { await t.test('npm i -g npm engines check success', async t => { const { npm } = await loadMockNpm(t, { - '../../lib/utils/reify-finish.js': async () => {}, - '@npmcli/arborist': function () { - this.reify = () => {} - }, - pacote: { - manifest: () => { - return { - version: '100.100.100', - engines: { - node: '>1', - }, - } + mocks: { + '{LIB}/utils/reify-finish.js': async () => {}, + '@npmcli/arborist': function () { + this.reify = () => {} + }, + pacote: { + manifest: () => { + return { + version: '100.100.100', + engines: { + node: '>1', + }, + } + }, }, }, + config: { + global: true, + }, }) - npm.config.set('global', true) await npm.exec('install', ['npm']) t.ok('No exceptions happen') }) await t.test('npm i -g npm engines check failure', async t => { const { npm } = await loadMockNpm(t, { - pacote: { - manifest: () => { - return { - _id: 'npm@1.2.3', - version: '100.100.100', - engines: { - node: '>1000', - }, - } + mocks: { + pacote: { + manifest: () => { + return { + _id: 'npm@1.2.3', + version: '100.100.100', + engines: { + node: '>1000', + }, + } + }, }, }, + config: { + global: true, + }, }) - npm.config.set('global', true) await t.rejects( npm.exec('install', ['npm']), { @@ -205,43 +229,55 @@ t.test('exec commands', async t => { await t.test('npm i -g npm engines check failure forced override', async t => { const { npm } = await loadMockNpm(t, { - '../../lib/utils/reify-finish.js': async () => {}, - '@npmcli/arborist': function () { - this.reify = () => {} - }, - pacote: { - manifest: () => { - return { - _id: 'npm@1.2.3', - version: '100.100.100', - engines: { - node: '>1000', - }, - } + mocks: { + '{LIB}/utils/reify-finish.js': async () => {}, + '@npmcli/arborist': function () { + this.reify = () => {} + }, + pacote: { + manifest: () => { + return { + _id: 'npm@1.2.3', + version: '100.100.100', + engines: { + node: '>1000', + }, + } + }, }, }, + config: { + global: true, + force: true, + }, }) - npm.config.set('global', true) - npm.config.set('force', true) await npm.exec('install', ['npm']) t.ok('Does not throw') }) await t.test('npm i -g npm@version engines check failure', async t => { const { npm } = await loadMockNpm(t, { - pacote: { - manifest: () => { - return { - _id: 'npm@1.2.3', - version: '100.100.100', - engines: { - node: '>1000', - }, - } + mocks: { + '{LIB}/utils/reify-finish.js': async () => {}, + '@npmcli/arborist': function () { + this.reify = () => {} + }, + pacote: { + manifest: () => { + return { + _id: 'npm@1.2.3', + version: '100.100.100', + engines: { + node: '>1000', + }, + } + }, }, }, + config: { + global: true, + }, }) - npm.config.set('global', true) await t.rejects( npm.exec('install', ['npm@100']), { @@ -261,138 +297,129 @@ t.test('exec commands', async t => { }) t.test('completion', async t => { - const cwd = process.cwd() - const testdir = t.testdir({ - arborist: { - 'package.json': '{}', + const mockComp = async (t, { noChdir } = {}) => loadMockNpm(t, { + command: 'install', + prefixDir: { + arborist: { + 'package.json': '{}', + }, + 'arborist.txt': 'just a file', + 'other-dir': { a: 'a' }, }, - 'arborist.txt': 'just a file', - other: {}, - }) - t.afterEach(() => { - process.chdir(cwd) + ...(noChdir ? { chdir: false } : {}), }) - t.test('completion to folder - has a match', async t => { - const { npm } = await _loadMockNpm(t, { load: false }) - const install = await npm.cmd('install') - process.chdir(testdir) + await t.test('completion to folder - has a match', async t => { + const { install } = await mockComp(t) const res = await install.completion({ partialWord: './ar' }) t.strictSame(res, ['arborist'], 'package dir match') }) - t.test('completion to folder - invalid dir', async t => { - const { npm } = await _loadMockNpm(t, { load: false }) - const install = await npm.cmd('install') + await t.test('completion to folder - invalid dir', async t => { + const { install } = await mockComp(t, { noChdir: true }) const res = await install.completion({ partialWord: '/does/not/exist' }) t.strictSame(res, [], 'invalid dir: no matching') }) - t.test('completion to folder - no matches', async t => { - const { npm } = await _loadMockNpm(t, { load: false }) - const install = await npm.cmd('install') - process.chdir(testdir) + await t.test('completion to folder - no matches', async t => { + const { install } = await mockComp(t) const res = await install.completion({ partialWord: './pa' }) t.strictSame(res, [], 'no name match') }) - t.test('completion to folder - match is not a package', async t => { - const { npm } = await _loadMockNpm(t, { load: false }) - const install = await npm.cmd('install') - process.chdir(testdir) + await t.test('completion to folder - match is not a package', async t => { + const { install } = await mockComp(t) const res = await install.completion({ partialWord: './othe' }) t.strictSame(res, [], 'no name match') }) - t.test('completion to url', async t => { - const { npm } = await _loadMockNpm(t, { load: false }) - const install = await npm.cmd('install') - process.chdir(testdir) + await t.test('completion to url', async t => { + const { install } = await mockComp(t) const res = await install.completion({ partialWord: 'http://path/to/url' }) t.strictSame(res, []) }) - t.test('no /', async t => { - const { npm } = await _loadMockNpm(t, { load: false }) - const install = await npm.cmd('install') - process.chdir(testdir) + await t.test('no /', async t => { + const { install } = await mockComp(t) const res = await install.completion({ partialWord: 'toto' }) t.notOk(res) }) - t.test('only /', async t => { - const { npm } = await _loadMockNpm(t, { load: false }) - const install = await npm.cmd('install') - process.chdir(testdir) + await t.test('only /', async t => { + const { install } = await mockComp(t) const res = await install.completion({ partialWord: '/' }) t.strictSame(res, []) }) }) -t.test('location detection and audit', async () => { - t.test('audit false without package.json', async t => { - const { npm } = await _loadMockNpm(t, { +t.test('location detection and audit', async (t) => { + await t.test('audit false without package.json', async t => { + const { npm } = await loadMockNpm(t, { prefixDir: { // no package.json 'readme.txt': 'just a file', - other: {}, + 'other-dir': { a: 'a' }, }, }) const install = await npm.cmd('install') t.equal(install.npm.config.get('location'), 'user') t.equal(install.npm.config.get('audit'), false) }) - t.test('audit true with package.json', async t => { - const { npm } = await _loadMockNpm(t, { + + await t.test('audit true with package.json', async t => { + const { npm } = await loadMockNpm(t, { prefixDir: { 'package.json': '{ "name": "testpkg", "version": "1.0.0" }', 'readme.txt': 'just a file', }, }) const install = await npm.cmd('install') - t.equal(install.npm.config.get('location'), 'project') + t.equal(install.npm.config.get('location'), 'user') t.equal(install.npm.config.get('audit'), true) }) - t.test('audit true without package.json when set', async t => { - const { npm } = await _loadMockNpm(t, { + + await t.test('audit true without package.json when set', async t => { + const { npm } = await loadMockNpm(t, { prefixDir: { // no package.json 'readme.txt': 'just a file', - other: {}, + 'other-dir': { a: 'a' }, }, config: { - audit: { value: true, where: 'cli' }, + audit: true, }, }) const install = await npm.cmd('install') t.equal(install.npm.config.get('location'), 'user') t.equal(install.npm.config.get('audit'), true) }) - t.test('audit true in root config without package.json', async t => { - const { npm } = await _loadMockNpm(t, { + + await t.test('audit true in root config without package.json', async t => { + const { npm } = await loadMockNpm(t, { prefixDir: { // no package.json 'readme.txt': 'just a file', - other: {}, - }, - config: { - audit: { value: true, where: 'builtin' }, + 'other-dir': { a: 'a' }, }, + // change npmRoot to get it to use a builtin rc file + otherDirs: { npmrc: 'audit=true' }, + npm: ({ other }) => ({ npmRoot: other }), }) const install = await npm.cmd('install') t.equal(install.npm.config.get('location'), 'user') t.equal(install.npm.config.get('audit'), true) }) - t.test('test for warning when --global & --audit', async t => { - const { npm, logs } = await _loadMockNpm(t, { + + await t.test('test for warning when --global & --audit', async t => { + const { npm, logs } = await loadMockNpm(t, { prefixDir: { // no package.json 'readme.txt': 'just a file', - other: {}, + 'other-dir': { a: 'a' }, }, config: { - audit: { value: true, where: 'cli' }, - global: { value: true, where: 'cli' }, + audit: true, + global: true, }, }) const install = await npm.cmd('install') diff --git a/deps/npm/test/lib/commands/link.js b/deps/npm/test/lib/commands/link.js index d908fa025fbde7..feae75a4b9096f 100644 --- a/deps/npm/test/lib/commands/link.js +++ b/deps/npm/test/lib/commands/link.js @@ -1,95 +1,86 @@ const t = require('tap') const { resolve, join } = require('path') const fs = require('fs') - const Arborist = require('@npmcli/arborist') -const { fake: mockNpm, load: fullMockNpm } = require('../../fixtures/mock-npm') - -const redactCwd = (path) => { - const normalizePath = p => p - .replace(/\\+/g, '/') - .replace(/\r\n/g, '\n') - return normalizePath(path) - .replace(new RegExp(normalizePath(process.cwd()), 'g'), '{CWD}') -} - -t.cleanSnapshot = (str) => redactCwd(str) - -const config = {} -const npm = mockNpm({ - globalDir: null, - prefix: null, - config, -}) +const { cleanCwd } = require('../../fixtures/clean-snapshot.js') +const mockNpm = require('../../fixtures/mock-npm') + +t.cleanSnapshot = (str) => cleanCwd(str) + +const mockLink = async (t, { globalPrefixDir, ...opts } = {}) => { + const mock = await mockNpm(t, { + ...opts, + globalPrefixDir, + mocks: { + ...opts.mocks, + '{LIB}/utils/reify-output.js': async () => {}, + }, + }) -const printLinks = async (opts) => { - let res = '' - const arb = new Arborist(opts) - const tree = await arb.loadActual() - const linkedItems = [...tree.inventory.values()] - .sort((a, b) => a.pkgid.localeCompare(b.pkgid, 'en')) - for (const item of linkedItems) { - if (item.isLink) { - res += `${item.path} -> ${item.target.path}\n` + const printLinks = async ({ global = false } = {}) => { + let res = '' + const arb = new Arborist(global ? { + path: resolve(mock.npm.globalDir, '..'), + global: true, + } : { path: mock.prefix }) + const tree = await arb.loadActual() + const linkedItems = [...tree.inventory.values()] + .sort((a, b) => a.pkgid.localeCompare(b.pkgid, 'en')) + for (const item of linkedItems) { + if (item.isLink) { + res += `${item.path} -> ${item.target.path}\n` + } } + return res } - return res -} -const mocks = { - '../../../lib/utils/reify-output.js': async () => {}, + return { + ...mock, + link: { + exec: (args = []) => mock.npm.exec('link', args), + completion: (o) => mock.npm.cmd('link').then(c => c.completion(o)), + }, + printLinks, + } } -const Link = t.mock('../../../lib/commands/link.js', mocks) -const link = new Link(npm) - t.test('link to globalDir when in current working dir of pkg and no args', async t => { - const testdir = t.testdir({ - 'global-prefix': { - lib: { - node_modules: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - }), - }, + const { link, printLinks } = await mockLink(t, { + globalPrefixDir: { + node_modules: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + }), }, }, }, - 'test-pkg-link': { + prefixDir: { 'package.json': JSON.stringify({ name: 'test-pkg-link', version: '1.0.0', }), }, }) - npm.globalDir = resolve(testdir, 'global-prefix', 'lib', 'node_modules') - npm.prefix = resolve(testdir, 'test-pkg-link') - await link.exec([]) - const links = await printLinks({ - path: resolve(npm.globalDir, '..'), - global: true, - }) - t.matchSnapshot(links, 'should create a global link to current pkg') + await link.exec() + t.matchSnapshot(await printLinks({ global: true }), 'should create a global link to current pkg') }) t.test('link ws to globalDir when workspace specified and no args', async t => { - const testdir = t.testdir({ - 'global-prefix': { - lib: { - node_modules: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - }), - }, + const { link, printLinks } = await mockLink(t, { + globalPrefixDir: { + node_modules: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + }), }, }, }, - 'test-pkg-link': { + prefixDir: { 'package.json': JSON.stringify({ name: 'test-pkg-link', version: '1.0.0', @@ -104,77 +95,68 @@ t.test('link ws to globalDir when workspace specified and no args', async t => { }, }, }, - }) - npm.globalDir = resolve(testdir, 'global-prefix', 'lib', 'node_modules') - npm.prefix = resolve(testdir, 'test-pkg-link') - npm.localPrefix = resolve(testdir, 'test-pkg-link') - - // link.workspaces = ['a'] - // link.workspacePaths = [resolve(testdir, 'test-pkg-link/packages/a')] - await link.execWorkspaces([], ['a']) - const links = await printLinks({ - path: resolve(npm.globalDir, '..'), - global: true, + config: { workspace: 'a' }, }) - t.matchSnapshot(links, 'should create a global link to current pkg') + await link.exec() + t.matchSnapshot(await printLinks({ global: true }), 'should create a global link to current pkg') }) t.test('link global linked pkg to local nm when using args', async t => { - const testdir = t.testdir({ - 'global-prefix': { - lib: { - node_modules: { - '@myscope': { - foo: { - 'package.json': JSON.stringify({ - name: '@myscope/foo', - version: '1.0.0', - }), - }, - bar: { - 'package.json': JSON.stringify({ - name: '@myscope/bar', - version: '1.0.0', - }), - }, - linked: t.fixture('symlink', '../../../../scoped-linked'), - }, - a: { + const { link, printLinks } = await mockLink(t, { + globalPrefixDir: { + node_modules: { + '@myscope': { + foo: { 'package.json': JSON.stringify({ - name: 'a', + name: '@myscope/foo', version: '1.0.0', }), }, - b: { + bar: { 'package.json': JSON.stringify({ - name: 'b', + name: '@myscope/bar', version: '1.0.0', }), }, - 'test-pkg-link': t.fixture('symlink', '../../../test-pkg-link'), + linked: t.fixture('symlink', '../../../other/scoped-linked'), + }, + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + }), + }, + b: { + 'package.json': JSON.stringify({ + name: 'b', + version: '1.0.0', + }), }, + 'test-pkg-link': t.fixture('symlink', '../../other/test-pkg-link'), }, }, - 'test-pkg-link': { - 'package.json': JSON.stringify({ - name: 'test-pkg-link', - version: '1.0.0', - }), - }, - 'link-me-too': { - 'package.json': JSON.stringify({ - name: 'link-me-too', - version: '1.0.0', - }), - }, - 'scoped-linked': { - 'package.json': JSON.stringify({ - name: '@myscope/linked', - version: '1.0.0', - }), + otherDirs: { + 'test-pkg-link': { + 'package.json': JSON.stringify({ + name: 'test-pkg-link', + version: '1.0.0', + }), + }, + 'link-me-too': { + 'package.json': JSON.stringify({ + name: 'link-me-too', + version: '1.0.0', + }), + }, + 'scoped-linked': { + 'package.json': JSON.stringify({ + name: '@myscope/linked', + version: '1.0.0', + }), + }, }, - 'my-project': { + prefixDir: { 'package.json': JSON.stringify({ name: 'my-project', version: '1.0.0', @@ -192,11 +174,6 @@ t.test('link global linked pkg to local nm when using args', async t => { }, }, }) - npm.globalDir = resolve(testdir, 'global-prefix', 'lib', 'node_modules') - npm.prefix = resolve(testdir, 'my-project') - - const _cwd = process.cwd() - process.chdir(npm.prefix) // installs examples for: // - test-pkg-link: pkg linked to globalDir from local fs @@ -209,71 +186,67 @@ t.test('link global linked pkg to local nm when using args', async t => { '@myscope/linked', '@myscope/bar', 'a', - 'file:../link-me-too', + 'file:../other/link-me-too', ]) - process.chdir(_cwd) - const links = await printLinks({ - path: npm.prefix, - }) - t.matchSnapshot(links, 'should create a local symlink to global pkg') + t.matchSnapshot(await printLinks(), 'should create a local symlink to global pkg') }) t.test('link global linked pkg to local workspace using args', async t => { - const testdir = t.testdir({ - 'global-prefix': { - lib: { - node_modules: { - '@myscope': { - foo: { - 'package.json': JSON.stringify({ - name: '@myscope/foo', - version: '1.0.0', - }), - }, - bar: { - 'package.json': JSON.stringify({ - name: '@myscope/bar', - version: '1.0.0', - }), - }, - linked: t.fixture('symlink', '../../../../scoped-linked'), - }, - a: { + const { link, printLinks } = await mockLink(t, { + globalPrefixDir: { + node_modules: { + '@myscope': { + foo: { 'package.json': JSON.stringify({ - name: 'a', + name: '@myscope/foo', version: '1.0.0', }), }, - b: { + bar: { 'package.json': JSON.stringify({ - name: 'b', + name: '@myscope/bar', version: '1.0.0', }), }, - 'test-pkg-link': t.fixture('symlink', '../../../test-pkg-link'), + linked: t.fixture('symlink', '../../../other/scoped-linked'), }, + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + }), + }, + b: { + 'package.json': JSON.stringify({ + name: 'b', + version: '1.0.0', + }), + }, + 'test-pkg-link': t.fixture('symlink', '../../other/test-pkg-link'), }, }, - 'test-pkg-link': { - 'package.json': JSON.stringify({ - name: 'test-pkg-link', - version: '1.0.0', - }), - }, - 'link-me-too': { - 'package.json': JSON.stringify({ - name: 'link-me-too', - version: '1.0.0', - }), - }, - 'scoped-linked': { - 'package.json': JSON.stringify({ - name: '@myscope/linked', - version: '1.0.0', - }), + otherDirs: { + 'test-pkg-link': { + 'package.json': JSON.stringify({ + name: 'test-pkg-link', + version: '1.0.0', + }), + }, + 'link-me-too': { + 'package.json': JSON.stringify({ + name: 'link-me-too', + version: '1.0.0', + }), + }, + 'scoped-linked': { + 'package.json': JSON.stringify({ + name: '@myscope/linked', + version: '1.0.0', + }), + }, }, - 'my-project': { + prefixDir: { 'package.json': JSON.stringify({ name: 'my-project', version: '1.0.0', @@ -299,13 +272,8 @@ t.test('link global linked pkg to local workspace using args', async t => { }, }, }, + config: { workspace: 'x' }, }) - npm.globalDir = resolve(testdir, 'global-prefix', 'lib', 'node_modules') - npm.prefix = resolve(testdir, 'my-project') - npm.localPrefix = resolve(testdir, 'my-project') - - const _cwd = process.cwd() - process.chdir(npm.prefix) // installs examples for: // - test-pkg-link: pkg linked to globalDir from local fs @@ -313,143 +281,113 @@ t.test('link global linked pkg to local workspace using args', async t => { // - @myscope/bar: prev installed scoped package available in globalDir // - a: prev installed package available in globalDir // - file:./link-me-too: pkg that needs to be reified in globalDir first - await link.execWorkspaces([ + await link.exec([ 'test-pkg-link', '@myscope/linked', '@myscope/bar', 'a', - 'file:../link-me-too', - ], ['x']) - process.chdir(_cwd) - - const links = await printLinks({ - path: npm.prefix, - }) + 'file:../other/link-me-too', + ]) - t.matchSnapshot(links, 'should create a local symlink to global pkg') + t.matchSnapshot(await printLinks(), 'should create a local symlink to global pkg') }) t.test('link pkg already in global space', async t => { - const testdir = t.testdir({ - 'global-prefix': { - lib: { - node_modules: { - '@myscope': { - linked: t.fixture('symlink', '../../../../scoped-linked'), - }, + const { npm, link, printLinks, prefix } = await mockLink(t, { + globalPrefixDir: { + node_modules: { + '@myscope': { + linked: t.fixture('symlink', '../../../other/scoped-linked'), }, }, }, - 'scoped-linked': { - 'package.json': JSON.stringify({ - name: '@myscope/linked', - version: '1.0.0', - }), + otherDirs: { + 'scoped-linked': { + 'package.json': JSON.stringify({ + name: '@myscope/linked', + version: '1.0.0', + }), + }, }, - 'my-project': { + prefixDir: { 'package.json': JSON.stringify({ name: 'my-project', version: '1.0.0', }), }, }) - npm.globalDir = resolve(testdir, 'global-prefix', 'lib', 'node_modules') - npm.prefix = resolve(testdir, 'my-project') + // XXX: how to convert this to a config that gets passed in? npm.config.find = () => 'default' - const _cwd = process.cwd() - process.chdir(npm.prefix) - - // installs examples for: - // - test-pkg-link: pkg linked to globalDir from local fs - // - @myscope/linked: scoped pkg linked to globalDir from local fs - // - @myscope/bar: prev installed scoped package available in globalDir - // - a: prev installed package available in globalDir - // - file:./link-me-too: pkg that needs to be reified in globalDir first await link.exec(['@myscope/linked']) - process.chdir(_cwd) - npm.config.find = () => null - - const links = await printLinks({ - path: npm.prefix, - }) t.equal( - require(resolve(testdir, 'my-project', 'package.json')).dependencies, + require(resolve(prefix, 'package.json')).dependencies, undefined, 'should not save to package.json upon linking' ) - t.matchSnapshot(links, 'should create a local symlink to global pkg') + t.matchSnapshot(await printLinks(), 'should create a local symlink to global pkg') }) t.test('link pkg already in global space when prefix is a symlink', async t => { - const testdir = t.testdir({ - 'global-prefix': t.fixture('symlink', './real-global-prefix'), - 'real-global-prefix': { - lib: { + const { npm, link, printLinks, prefix } = await mockLink(t, { + globalPrefixDir: t.fixture('symlink', './other/real-global-prefix'), + otherDirs: { + // mockNpm does this automatically but only for globalPrefixDir so here we + // need to do it manually since we are making a symlink somewhere else + 'real-global-prefix': mockNpm.setGlobalNodeModules({ 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', }), + 'scoped-linked': { + 'package.json': JSON.stringify({ + name: '@myscope/linked', + version: '1.0.0', + }), + }, }, - 'my-project': { + prefixDir: { 'package.json': JSON.stringify({ name: 'my-project', version: '1.0.0', }), }, }) - npm.globalDir = resolve(testdir, 'global-prefix', 'lib', 'node_modules') - npm.prefix = resolve(testdir, 'my-project') npm.config.find = () => 'default' - const _cwd = process.cwd() - process.chdir(npm.prefix) - await link.exec(['@myscope/linked']) - process.chdir(_cwd) - npm.config.find = () => null - - const links = await printLinks({ - path: npm.prefix, - }) t.equal( - require(resolve(testdir, 'my-project', 'package.json')).dependencies, + require(resolve(prefix, 'package.json')).dependencies, undefined, 'should not save to package.json upon linking' ) - t.matchSnapshot(links, 'should create a local symlink to global pkg') + t.matchSnapshot(await printLinks(), 'should create a local symlink to global pkg') }) t.test('should not prune dependencies when linking packages', async t => { - const testdir = t.testdir({ - 'global-prefix': { - lib: { - node_modules: { - linked: t.fixture('symlink', '../../../linked'), - }, + const { link, prefix } = await mockLink(t, { + globalPrefixDir: { + node_modules: { + linked: t.fixture('symlink', '../../other/linked'), }, }, - linked: { - 'package.json': JSON.stringify({ - name: 'linked', - version: '1.0.0', - }), + otherDirs: { + linked: { + 'package.json': JSON.stringify({ + name: 'linked', + version: '1.0.0', + }), + }, }, - 'my-project': { + prefixDir: { node_modules: { foo: { 'package.json': JSON.stringify({ name: 'foo', version: '1.0.0' }), @@ -461,37 +399,29 @@ t.test('should not prune dependencies when linking packages', async t => { }), }, }) - npm.globalDir = resolve(testdir, 'global-prefix', 'lib', 'node_modules') - npm.prefix = resolve(testdir, 'my-project') - - const _cwd = process.cwd() - process.chdir(npm.prefix) await link.exec(['linked']) t.ok( - fs.statSync(resolve(testdir, 'my-project/node_modules/foo')), + fs.statSync(resolve(prefix, 'node_modules/foo')), 'should not prune any extraneous dep when running npm link' ) - process.chdir(_cwd) }) t.test('completion', async t => { - const testdir = t.testdir({ - 'global-prefix': { - lib: { - node_modules: { - foo: {}, - bar: {}, - lorem: {}, - ipsum: {}, - }, + const { link } = await mockLink(t, { + globalPrefixDir: { + node_modules: { + foo: {}, + bar: {}, + lorem: {}, + ipsum: {}, }, }, }) - npm.globalDir = resolve(testdir, 'global-prefix', 'lib', 'node_modules') const words = await link.completion({}) + t.same( words, ['bar', 'foo', 'ipsum', 'lorem'], @@ -500,13 +430,9 @@ t.test('completion', async t => { }) t.test('--global option', async t => { - t.teardown(() => { - npm.config = _config + const { link } = await mockLink(t, { + config: { global: true }, }) - const _config = npm.config - npm.config = { get () { - return true - } } await t.rejects( link.exec([]), /link should never be --global/, @@ -515,44 +441,37 @@ t.test('--global option', async t => { }) t.test('hash character in working directory path', async t => { - const testdir = t.testdir({ - 'global-prefix': { - lib: { - node_modules: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - }), - }, + const { link, printLinks } = await mockLink(t, { + globalPrefixDir: { + node_modules: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + }), }, }, }, - 'i_like_#_in_my_paths': { - 'test-pkg-link': { - 'package.json': JSON.stringify({ - name: 'test-pkg-link', - version: '1.0.0', - }), + otherDirs: { + 'i_like_#_in_my_paths': { + 'test-pkg-link': { + 'package.json': JSON.stringify({ + name: 'test-pkg-link', + version: '1.0.0', + }), + }, }, }, + chdir: ({ other }) => join(other, 'i_like_#_in_my_paths', 'test-pkg-link'), }) - npm.globalDir = resolve(testdir, 'global-prefix', 'lib', 'node_modules') - npm.prefix = resolve(testdir, 'i_like_#_in_my_paths', 'test-pkg-link') - - link.workspacePaths = null await link.exec([]) - const links = await printLinks({ - path: resolve(npm.globalDir, '..'), - global: true, - }) - t.matchSnapshot(links, 'should create a global link to current pkg, even within path with hash') + t.matchSnapshot(await printLinks({ global: true }), + 'should create a global link to current pkg, even within path with hash') }) t.test('test linked installed as symlinks', async t => { - // fakeMock is insufficient due to lack of flatOptions - const { npm } = await fullMockNpm(t, { + const { link, prefix, printLinks } = await mockLink(t, { otherDirs: { mylink: { 'package.json': JSON.stringify({ @@ -563,20 +482,13 @@ t.test('test linked installed as symlinks', async t => { }, }) - const _cwd = process.cwd() - process.chdir(npm.prefix) - - await npm.exec('link', [ + await link.exec([ join('file:../other/mylink'), ]) - process.chdir(_cwd) - const links = await printLinks({ - path: npm.prefix, - }) - t.ok(fs.lstatSync(join(npm.prefix, 'node_modules', 'mylink')).isSymbolicLink(), + t.ok(fs.lstatSync(join(prefix, 'node_modules', 'mylink')).isSymbolicLink(), 'linked path should by symbolic link' ) - t.matchSnapshot(links, 'linked package should not be installed') + t.matchSnapshot(await printLinks(), 'linked package should not be installed') }) diff --git a/deps/npm/test/lib/commands/ll.js b/deps/npm/test/lib/commands/ll.js index c39d4338120d46..0977ef4ac5eae9 100644 --- a/deps/npm/test/lib/commands/ll.js +++ b/deps/npm/test/lib/commands/ll.js @@ -1,4 +1,5 @@ const t = require('tap') +const tmock = require('../../fixtures/tmock') t.test('ll', t => { t.plan(3) @@ -13,8 +14,8 @@ t.test('ll', t => { } } - const LL = t.mock('../../../lib/commands/ll.js', { - '../../../lib/commands/ls.js': LS, + const LL = tmock(t, '{LIB}/commands/ll.js', { + '{LIB}/commands/ls.js': LS, }) const ll = new LL({ config: { diff --git a/deps/npm/test/lib/commands/logout.js b/deps/npm/test/lib/commands/logout.js index 73fe8028c7853b..0043bb4c57922a 100644 --- a/deps/npm/test/lib/commands/logout.js +++ b/deps/npm/test/lib/commands/logout.js @@ -1,69 +1,53 @@ const t = require('tap') -const { fake: mockNpm } = require('../../fixtures/mock-npm') - -const config = { - registry: 'https://registry.npmjs.org/', - scope: '', -} -const flatOptions = { - registry: 'https://registry.npmjs.org/', - scope: '', -} -const npm = mockNpm({ config, flatOptions }) -let result = null - -const mockLogout = (otherMocks) => { - const Logout = t.mock('../../../lib/commands/logout.js', { - 'npm-registry-fetch': (url, opts) => { - result = { url, opts } +const fs = require('fs/promises') +const npmFetch = require('npm-registry-fetch') +const mockNpm = require('../../fixtures/mock-npm') +const { join } = require('path') + +const mockLogout = async (t, { userRc = [], ...npmOpts } = {}) => { + let result = null + + const mock = await mockNpm(t, { + mocks: { + // XXX: refactor to use mock registry + 'npm-registry-fetch': Object.assign(async (url, opts) => { + result = { url, opts } + }, npmFetch), + }, + ...npmOpts, + homeDir: { + '.npmrc': userRc.join('\n'), }, - ...otherMocks, }) - return new Logout(npm) -} - -t.afterEach(() => { - delete flatOptions.token - result = null - config.clearCredentialsByURI = null - config.delete = null - config.save = null -}) - -t.test('token logout', async t => { - t.plan(5) - - flatOptions['//registry.npmjs.org/:_authToken'] = '@foo/' - - npm.config.clearCredentialsByURI = registry => { - t.equal( - registry, - 'https://registry.npmjs.org/', - 'should clear credentials from the expected registry' - ) - } - npm.config.save = type => { - t.equal(type, 'user', 'should save to user config') + return { + ...mock, + logout: { exec: (args) => mock.npm.exec('logout', args) }, + result: () => result, + // get only the message portion of the verbose log from the command + logMsg: () => mock.logs.verbose.find(l => l[0] === 'logout')[1], + userRc: () => fs.readFile(join(mock.home, '.npmrc'), 'utf-8').then(r => r.trim()), } +} - const logout = mockLogout({ - 'proc-log': { - verbose: (title, msg) => { - t.equal(title, 'logout', 'should have correcct log prefix') - t.equal( - msg, - 'clearing token for https://registry.npmjs.org/', - 'should log message with correct registry' - ) - }, - }, +t.test('token logout', async t => { + const { logout, logMsg, result, userRc } = await mockLogout(t, { + userRc: [ + '//registry.npmjs.org/:_authToken=@foo/', + 'other-config=true', + ], }) await logout.exec([]) + t.equal( + logMsg(), + 'clearing token for https://registry.npmjs.org/', + 'should log message with correct registry' + ) + t.match( - result, + result(), { url: '/-/user/token/%40foo%2F', opts: { @@ -76,64 +60,30 @@ t.test('token logout', async t => { }, 'should call npm-registry-fetch with expected values' ) + + t.equal(await userRc(), 'other-config=true') }) t.test('token scoped logout', async t => { - t.teardown(() => { - config.scope = '' - delete flatOptions['//diff-registry.npmjs.com/:_authToken'] - delete flatOptions['//registry.npmjs.org/:_authToken'] - delete config['@myscope:registry'] - delete flatOptions.scope - result = null - config.clearCredentialsByURI = null - config.delete = null - config.save = null - }) - - t.plan(7) - - flatOptions['//diff-registry.npmjs.com/:_authToken'] = '@bar/' - flatOptions['//registry.npmjs.org/:_authToken'] = '@foo/' - config.scope = '@myscope' - config['@myscope:registry'] = 'https://diff-registry.npmjs.com/' - flatOptions.scope = '@myscope' - flatOptions['@myscope:registry'] = 'https://diff-registry.npmjs.com/' - - npm.config.clearCredentialsByURI = registry => { - t.equal( - registry, - 'https://diff-registry.npmjs.com/', - 'should clear credentials from the expected registry' - ) - } - - npm.config.delete = (ref, type) => { - t.equal(ref, '@myscope:registry', 'should delete scoped registyr from config') - t.equal(type, 'user', 'should delete from user config') - } - - npm.config.save = type => { - t.equal(type, 'user', 'should save to user config') - } - - const logout = mockLogout({ - 'proc-log': { - verbose: (title, msg) => { - t.equal(title, 'logout', 'should have correcct log prefix') - t.equal( - msg, - 'clearing token for https://diff-registry.npmjs.com/', - 'should log message with correct registry' - ) - }, - }, + const { logout, logMsg, result, userRc } = await mockLogout(t, { + config: { scope: '@myscope' }, + userRc: [ + '//diff-registry.npmjs.com/:_authToken=@bar/', + '//registry.npmjs.org/:_authToken=@foo/', + '@myscope:registry=https://diff-registry.npmjs.com/', + ], }) await logout.exec([]) + t.equal( + logMsg(), + 'clearing token for https://diff-registry.npmjs.com/', + 'should log message with correct registry' + ) + t.match( - result, + result(), { url: '/-/user/token/%40bar%2F', opts: { @@ -148,41 +98,32 @@ t.test('token scoped logout', async t => { }, 'should call npm-registry-fetch with expected values' ) + + t.equal(await userRc(), '//registry.npmjs.org/:_authToken=@foo/') }) t.test('user/pass logout', async t => { - t.teardown(() => { - delete flatOptions['//registry.npmjs.org/:username'] - delete flatOptions['//registry.npmjs.org/:_password'] - npm.config.clearCredentialsByURI = null - npm.config.save = null - }) - t.plan(2) - - flatOptions['//registry.npmjs.org/:username'] = 'foo' - flatOptions['//registry.npmjs.org/:_password'] = 'bar' - - npm.config.clearCredentialsByURI = () => null - npm.config.save = () => null - - const logout = mockLogout({ - 'proc-log': { - verbose: (title, msg) => { - t.equal(title, 'logout', 'should have correct log prefix') - t.equal( - msg, - 'clearing user credentials for https://registry.npmjs.org/', - 'should log message with correct registry' - ) - }, - }, + const { logout, logMsg, userRc } = await mockLogout(t, { + userRc: [ + '//registry.npmjs.org/:username=foo', + '//registry.npmjs.org/:_password=bar', + 'other-config=true', + ], }) await logout.exec([]) + + t.equal( + logMsg(), + 'clearing user credentials for https://registry.npmjs.org/', + 'should log message with correct registry' + ) + + t.equal(await userRc(), 'other-config=true') }) t.test('missing credentials', async t => { - const logout = mockLogout() + const { logout } = await mockLogout(t) await t.rejects( logout.exec([]), @@ -195,57 +136,35 @@ t.test('missing credentials', async t => { }) t.test('ignore invalid scoped registry config', async t => { - t.teardown(() => { - delete flatOptions.token - result = null - config.clearCredentialsByURI = null - config.delete = null - config.save = null - }) - t.plan(4) - - flatOptions['//registry.npmjs.org/:_authToken'] = '@foo/' - config.scope = '@myscope' - flatOptions['@myscope:registry'] = '' - - npm.config.clearCredentialsByURI = registry => { - t.equal( - registry, - 'https://registry.npmjs.org/', - 'should clear credentials from the expected registry' - ) - } - - npm.config.delete = () => null - npm.config.save = () => null - - const logout = mockLogout({ - 'proc-log': { - verbose: (title, msg) => { - t.equal(title, 'logout', 'should have correcct log prefix') - t.equal( - msg, - 'clearing token for https://registry.npmjs.org/', - 'should log message with correct registry' - ) - }, - }, + const { logout, logMsg, result, userRc } = await mockLogout(t, { + config: { scope: '@myscope' }, + userRc: [ + '//registry.npmjs.org/:_authToken=@foo/', + 'other-config=true', + ], }) await logout.exec([]) + t.equal( + logMsg(), + 'clearing token for https://registry.npmjs.org/', + 'should log message with correct registry' + ) + t.match( - result, + result(), { url: '/-/user/token/%40foo%2F', opts: { '//registry.npmjs.org/:_authToken': '@foo/', registry: 'https://registry.npmjs.org/', - '@myscope:registry': '', method: 'DELETE', ignoreBody: true, }, }, 'should call npm-registry-fetch with expected values' ) + + t.equal(await userRc(), 'other-config=true') }) diff --git a/deps/npm/test/lib/commands/ls.js b/deps/npm/test/lib/commands/ls.js index b9278dd20688d9..9b773345525b5d 100644 --- a/deps/npm/test/lib/commands/ls.js +++ b/deps/npm/test/lib/commands/ls.js @@ -2,17 +2,18 @@ // Consider using t.matchSnapshot on these instead, especially since many // of them contain the tap testdir folders, which are auto-generated and // may change when node-tap is updated. -const t = require('tap') -const { fake: mockNpm } = require('../../fixtures/mock-npm.js') -const { resolve } = require('path') +const t = require('tap') const { utimesSync } = require('fs') +const mockNpm = require('../../fixtures/mock-npm.js') +const { cleanCwd } = require('../../fixtures/clean-snapshot') + const touchHiddenPackageLock = prefix => { const later = new Date(Date.now() + 10000) utimesSync(`${prefix}/node_modules/.package-lock.json`, later, later) } -t.cleanSnapshot = str => str.split(/\r\n/).join('\n') +t.cleanSnapshot = str => cleanCwd(str) const simpleNmFixture = { node_modules: { @@ -89,775 +90,827 @@ const diffDepTypesNmFixture = { }, } -let result = '' -const LS = t.mock('../../../lib/commands/ls.js', { - path: { - ...require('path'), - sep: '/', - }, -}) -const config = { - all: true, - color: false, - depth: Infinity, - global: false, - json: false, - link: false, - location: 'project', - omit: [], - parseable: false, - 'package-lock-only': false, -} -const flatOptions = { - workspacesEnabled: true, -} -const npm = mockNpm({ - config, - flatOptions, - output: msg => { - result = msg - }, -}) -const ls = new LS(npm) +const mockLs = async (t, { mocks, config, ...opts } = {}) => { + const mock = await mockNpm(t, { + ...opts, + config: { + all: true, + ...config, + }, + command: 'ls', + mocks: { + path: { + ...require('path'), + sep: '/', + }, + ...mocks, + }, + }) -const redactCwd = res => - res && - res.replace(/\\+/g, '/').replace(new RegExp(__dirname.replace(/\\+/g, '/'), 'gi'), '{CWD}') + return { + ...mock, + result: () => mock.joinedOutput(), + } +} const redactCwdObj = obj => { if (Array.isArray(obj)) { return obj.map(o => redactCwdObj(o)) - } else if (typeof obj === 'string') { - return redactCwd(obj) - } else if (!obj) { - return obj - } else if (typeof obj === 'object') { + } + if (obj && typeof obj === 'object') { return Object.keys(obj).reduce((o, k) => { o[k] = redactCwdObj(obj[k]) return o }, {}) - } else { - return obj } + return typeof obj === 'string' ? cleanCwd(obj) : obj } const jsonParse = res => redactCwdObj(JSON.parse(res)) -const cleanUpResult = () => (result = '') - -t.test('ls', t => { - t.beforeEach(cleanUpResult) - config.json = false - config.unicode = false +t.test('ls', async t => { t.test('no args', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - }, - }), - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + // config: {}, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await ls.exec([]) t.matchSnapshot( - redactCwd(result), + cleanCwd(result()), 'should output tree representation of dependencies structure' ) }) t.test('missing package.json', async t => { - npm.prefix = t.testdir({ - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + config: {}, + prefixDir: { + ...simpleNmFixture, + }, }) await ls.exec([]) t.matchSnapshot( - redactCwd(result), + cleanCwd(result()), 'should output tree missing name/version of top-level package' ) }) t.test('workspace and missing optional dep', async t => { - npm.prefix = npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'root', - dependencies: { - foo: '^1.0.0', - }, - optionalDependencies: { - bar: '^1.0.0', - }, - workspaces: ['./baz'], - }), - baz: { + const config = { + 'include-workspace-root': true, + workspace: 'baz', + } + const { result, ls } = await mockLs(t, { + config, + prefixDir: { 'package.json': JSON.stringify({ - name: 'baz', - version: '1.0.0', + name: 'root', + dependencies: { + foo: '^1.0.0', + }, + optionalDependencies: { + bar: '^1.0.0', + }, + workspaces: ['./baz'], }), - }, - node_modules: { - baz: t.fixture('symlink', '../baz'), - foo: { + baz: { 'package.json': JSON.stringify({ - name: 'foo', + name: 'baz', version: '1.0.0', }), }, + node_modules: { + baz: t.fixture('symlink', '../baz'), + foo: { + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.0.0', + }), + }, + }, }, }) - npm.flatOptions.includeWorkspaceRoot = true - t.teardown(() => { - delete npm.flatOptions.includeWorkspaceRoot - }) - - await ls.execWorkspaces([], ['baz']) - t.matchSnapshot(redactCwd(result), 'should omit missing optional dep') + await ls.exec([]) + t.matchSnapshot(cleanCwd(result()), 'should omit missing optional dep') }) t.test('extraneous deps', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - }, - }), - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + config: {}, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should output containing problems info') + t.matchSnapshot(cleanCwd(result()), 'should output containing problems info') }) t.test('overridden dep', async t => { - config.all = true - t.teardown(() => { - config.all = false - }) + const config = { + } - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-overridden', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - }, - overrides: { - bar: '1.0.0', - }, - }), - node_modules: { - foo: { - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.0.0', - dependencies: { - bar: '^2.0.0', - }, - }), - }, - bar: { - 'package.json': JSON.stringify({ - name: 'bar', - version: '1.0.0', - }), + const { result, ls } = await mockLs(t, { + config, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-overridden', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + }, + overrides: { + bar: '1.0.0', + }, + }), + node_modules: { + foo: { + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.0.0', + dependencies: { + bar: '^2.0.0', + }, + }), + }, + bar: { + 'package.json': JSON.stringify({ + name: 'bar', + version: '1.0.0', + }), + }, }, }, }) - await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should contain overridden outout') + await + + ls.exec([]) + t.matchSnapshot(cleanCwd(result()), 'should contain overridden outout') }) t.test('overridden dep w/ color', async t => { - config.all = true - npm.color = true - t.teardown(() => { - config.all = false - npm.color = false - }) + const config = { + color: 'always', + } - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-overridden', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - }, - overrides: { - bar: '1.0.0', - }, - }), - node_modules: { - foo: { - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.0.0', - dependencies: { - bar: '^2.0.0', - }, - }), - }, - bar: { - 'package.json': JSON.stringify({ - name: 'bar', - version: '1.0.0', - }), + const { result, ls } = await mockLs(t, { + config, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-overridden', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + }, + overrides: { + bar: '1.0.0', + }, + }), + node_modules: { + foo: { + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.0.0', + dependencies: { + bar: '^2.0.0', + }, + }), + }, + bar: { + 'package.json': JSON.stringify({ + name: 'bar', + version: '1.0.0', + }), + }, }, }, }) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should contain overridden outout') + t.matchSnapshot(cleanCwd(result()), 'should contain overridden outout') }) t.test('with filter arg', async t => { - npm.color = true - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - }, - }), - ...simpleNmFixture, + const config = { + color: 'always', + } + const { result, ls } = await mockLs(t, { + config, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await ls.exec(['chai']) t.matchSnapshot( - redactCwd(result), + cleanCwd(result()), 'should output tree contaning only occurrences of filtered by package and colored output' ) - npm.color = false }) t.test('with dot filter arg', async t => { - config.all = false - config.depth = 0 - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - ipsum: '^1.0.0', - }, - }), - ...simpleNmFixture, + const config = { + all: false, + depth: 0, + } + const { result, ls } = await mockLs(t, { + config, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + ipsum: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await ls.exec(['.']) t.matchSnapshot( - redactCwd(result), + cleanCwd(result()), 'should output tree contaning only occurrences of filtered by package and colored output' ) - config.all = true - config.depth = Infinity - process.exitCode = 0 }) t.test('with filter arg nested dep', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - }, - }), - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + config: {}, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await ls.exec(['dog']) t.matchSnapshot( - redactCwd(result), + cleanCwd(result()), 'should output tree contaning only occurrences of filtered package and its ancestors' ) }) t.test('with multiple filter args', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - ipsum: '^1.0.0', - }, - }), - node_modules: { - ...simpleNmFixture.node_modules, - ipsum: { - 'package.json': JSON.stringify({ - name: 'ipsum', - version: '1.0.0', - }), + const { result, ls } = await mockLs(t, { + config: {}, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', + ipsum: '^1.0.0', + }, + }), + node_modules: { + ...simpleNmFixture.node_modules, + ipsum: { + 'package.json': JSON.stringify({ + name: 'ipsum', + version: '1.0.0', + }), + }, }, }, }) await ls.exec(['dog@*', 'chai@1.0.0']) t.matchSnapshot( - redactCwd(result), + cleanCwd(result()), /* eslint-disable-next-line max-len */ 'should output tree contaning only occurrences of multiple filtered packages and their ancestors' ) }) t.test('with missing filter arg', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - }, - }), - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + config: {}, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await ls.exec(['notadep']) - t.matchSnapshot(redactCwd(result), 'should output tree containing no dependencies info') + t.matchSnapshot(cleanCwd(result()), 'should output tree containing no dependencies info') t.equal(process.exitCode, 1, 'should exit with error code 1') - process.exitCode = 0 }) t.test('default --depth value should be 0', async t => { - config.all = false - config.depth = undefined - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - }, - }), - ...simpleNmFixture, + const config = { + all: false, + } + const { result, ls } = await mockLs(t, { + config, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should output tree containing only top-level dependencies') - config.all = true - config.depth = Infinity + t.matchSnapshot(cleanCwd(result()), + 'should output tree containing only top-level dependencies') }) t.test('--depth=0', async t => { - config.all = false - config.depth = 0 - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - }, - }), - ...simpleNmFixture, + const config = { + all: false, + depth: 0, + } + const { result, ls } = await mockLs(t, { + config, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should output tree containing only top-level dependencies') - config.all = true - config.depth = Infinity + t.matchSnapshot(cleanCwd(result()), + 'should output tree containing only top-level dependencies') }) t.test('--depth=1', async t => { - config.all = false - config.depth = 1 - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - a: '^1.0.0', - e: '^1.0.0', - }, - }), - node_modules: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - dependencies: { - b: '^1.0.0', - }, - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'b', - version: '1.0.0', - dependencies: { - c: '^1.0.0', - d: '*', - }, - }), - }, - c: { - 'package.json': JSON.stringify({ - name: 'c', - version: '1.0.0', - }), - }, - d: { - 'package.json': JSON.stringify({ - name: 'd', - version: '1.0.0', - }), - }, - e: { - 'package.json': JSON.stringify({ - name: 'e', - version: '1.0.0', - }), + const config = { + all: false, + depth: 1, + } + const { result, ls } = await mockLs(t, { + config, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + a: '^1.0.0', + e: '^1.0.0', + }, + }), + node_modules: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + dependencies: { + b: '^1.0.0', + }, + }), + }, + b: { + 'package.json': JSON.stringify({ + name: 'b', + version: '1.0.0', + dependencies: { + c: '^1.0.0', + d: '*', + }, + }), + }, + c: { + 'package.json': JSON.stringify({ + name: 'c', + version: '1.0.0', + }), + }, + d: { + 'package.json': JSON.stringify({ + name: 'd', + version: '1.0.0', + }), + }, + e: { + 'package.json': JSON.stringify({ + name: 'e', + version: '1.0.0', + }), + }, }, }, }) await ls.exec([]) t.matchSnapshot( - redactCwd(result), + cleanCwd(result()), 'should output tree containing top-level deps and their deps only' ) - config.all = true - config.depth = Infinity }) t.test('missing/invalid/extraneous', async t => { t.plan(3) - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^2.0.0', - ipsum: '^1.0.0', - }, - }), - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + config: {}, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^2.0.0', + ipsum: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await ls.exec([]).catch(err => { t.equal(err.code, 'ELSPROBLEMS', 'should have error code') t.equal( - redactCwd(err.message).replace(/\r\n/g, '\n'), - /* eslint-disable-next-line max-len */ - 'extraneous: chai@1.0.0 {CWD}/tap-testdir-ls-ls-missing-invalid-extraneous/node_modules/chai\n' + - 'invalid: foo@1.0.0 {CWD}/tap-testdir-ls-ls-missing-invalid-extraneous/node_modules/foo\n' + + cleanCwd(err.message), + 'extraneous: chai@1.0.0 {CWD}/prefix/node_modules/chai\n' + + 'invalid: foo@1.0.0 {CWD}/prefix/node_modules/foo\n' + 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0', 'should log missing/invalid/extraneous errors' ) }) t.matchSnapshot( - redactCwd(result), + cleanCwd(result()), 'should output tree containing missing, invalid, extraneous labels' ) }) t.test('colored output', async t => { - npm.color = true - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^2.0.0', - ipsum: '^1.0.0', - }, - }), - ...simpleNmFixture, + const config = { + color: 'always', + } + const { result, ls } = await mockLs(t, { + config, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^2.0.0', + ipsum: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await t.rejects(ls.exec([]), { code: 'ELSPROBLEMS' }, 'should have error code') - t.matchSnapshot(redactCwd(result), 'should output tree containing color info') - npm.color = false + t.matchSnapshot(cleanCwd(result()), 'should output tree containing color info') }) t.test('--dev', async t => { - flatOptions.omit = ['peer', 'prod', 'optional'] - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'prod-dep': '^1.0.0', - chai: '^1.0.0', - }, - devDependencies: { - 'dev-dep': '^1.0.0', - }, - optionalDependencies: { - 'optional-dep': '^1.0.0', - }, - peerDependencies: { - 'peer-dep': '^1.0.0', - }, - }), - ...diffDepTypesNmFixture, + const { result, ls } = await mockLs(t, { + config: { + omit: ['peer', 'prod', 'optional'], + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'prod-dep': '^1.0.0', + chai: '^1.0.0', + }, + devDependencies: { + 'dev-dep': '^1.0.0', + }, + optionalDependencies: { + 'optional-dep': '^1.0.0', + }, + peerDependencies: { + 'peer-dep': '^1.0.0', + }, + }), + ...diffDepTypesNmFixture, + }, }) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should output tree containing dev deps') - flatOptions.omit = [] + t.matchSnapshot(cleanCwd(result()), 'should output tree containing dev deps') }) t.test('--link', async t => { - config.link = true - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'prod-dep': '^1.0.0', - chai: '^1.0.0', - 'linked-dep': '^1.0.0', - }, - devDependencies: { - 'dev-dep': '^1.0.0', - }, - optionalDependencies: { - 'optional-dep': '^1.0.0', - }, - peerDependencies: { - 'peer-dep': '^1.0.0', - }, - }), - 'linked-dep': { + const config = { + link: true, + } + const { result, ls } = await mockLs(t, { + config, + prefixDir: { 'package.json': JSON.stringify({ - name: 'linked-dep', + name: 'test-npm-ls', version: '1.0.0', + dependencies: { + 'prod-dep': '^1.0.0', + chai: '^1.0.0', + 'linked-dep': '^1.0.0', + }, + devDependencies: { + 'dev-dep': '^1.0.0', + }, + optionalDependencies: { + 'optional-dep': '^1.0.0', + }, + peerDependencies: { + 'peer-dep': '^1.0.0', + }, }), - }, - node_modules: { - 'linked-dep': t.fixture('symlink', '../linked-dep'), - ...diffDepTypesNmFixture.node_modules, + 'linked-dep': { + 'package.json': JSON.stringify({ + name: 'linked-dep', + version: '1.0.0', + }), + }, + node_modules: { + 'linked-dep': t.fixture('symlink', '../linked-dep'), + ...diffDepTypesNmFixture.node_modules, + }, }, }) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should output tree containing linked deps') - config.link = false + t.matchSnapshot(cleanCwd(result()), 'should output tree containing linked deps') }) t.test('print deduped symlinks', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'print-deduped-symlinks', - version: '1.0.0', - dependencies: { - a: '^1.0.0', - b: '^1.0.0', - }, - }), - b: { + const { result, ls } = await mockLs(t, { + config: {}, + prefixDir: { 'package.json': JSON.stringify({ - name: 'b', + name: 'print-deduped-symlinks', version: '1.0.0', + dependencies: { + a: '^1.0.0', + b: '^1.0.0', + }, }), - }, - node_modules: { - a: { + b: { 'package.json': JSON.stringify({ - name: 'a', + name: 'b', version: '1.0.0', - dependencies: { - b: '^1.0.0', - }, }), }, - b: t.fixture('symlink', '../b'), + node_modules: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + dependencies: { + b: '^1.0.0', + }, + }), + }, + b: t.fixture('symlink', '../b'), + }, }, }) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should output tree containing linked deps') - config.link = false + t.matchSnapshot(cleanCwd(result()), 'should output tree containing linked deps') }) t.test('--production', async t => { - flatOptions.omit = ['dev', 'peer'] - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'prod-dep': '^1.0.0', - chai: '^1.0.0', - }, - devDependencies: { - 'dev-dep': '^1.0.0', - }, - optionalDependencies: { - 'optional-dep': '^1.0.0', - }, - peerDependencies: { - 'peer-dep': '^1.0.0', - }, - }), - ...diffDepTypesNmFixture, + const { result, ls } = await mockLs(t, { + config: { omit: ['dev', 'peer'] }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'prod-dep': '^1.0.0', + chai: '^1.0.0', + }, + devDependencies: { + 'dev-dep': '^1.0.0', + }, + optionalDependencies: { + 'optional-dep': '^1.0.0', + }, + peerDependencies: { + 'peer-dep': '^1.0.0', + }, + }), + ...diffDepTypesNmFixture, + }, }) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should output tree containing production deps') - flatOptions.omit = [] + t.matchSnapshot(cleanCwd(result()), 'should output tree containing production deps') }) t.test('--long', async t => { - config.long = true - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'prod-dep': '^1.0.0', - chai: '^1.0.0', - }, - devDependencies: { - 'dev-dep': '^1.0.0', - }, - optionalDependencies: { - 'optional-dep': '^1.0.0', - }, - peerDependencies: { - 'peer-dep': '^1.0.0', - }, - }), - ...diffDepTypesNmFixture, + const config = { + long: true, + } + const { result, ls } = await mockLs(t, { + config, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'prod-dep': '^1.0.0', + chai: '^1.0.0', + }, + devDependencies: { + 'dev-dep': '^1.0.0', + }, + optionalDependencies: { + 'optional-dep': '^1.0.0', + }, + peerDependencies: { + 'peer-dep': '^1.0.0', + }, + }), + ...diffDepTypesNmFixture, + }, }) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should output tree info with descriptions') - config.long = true + t.matchSnapshot(cleanCwd(result()), 'should output tree info with descriptions') }) t.test('--long --depth=0', async t => { - config.all = false - config.depth = 0 - config.long = true - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'prod-dep': '^1.0.0', - chai: '^1.0.0', - }, - devDependencies: { - 'dev-dep': '^1.0.0', - }, - optionalDependencies: { - 'optional-dep': '^1.0.0', - }, - peerDependencies: { - 'peer-dep': '^1.0.0', - }, - }), - ...diffDepTypesNmFixture, + const config = { + all: false, + depth: 0, + long: true, + } + const { result, ls } = await mockLs(t, { + config, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'prod-dep': '^1.0.0', + chai: '^1.0.0', + }, + devDependencies: { + 'dev-dep': '^1.0.0', + }, + optionalDependencies: { + 'optional-dep': '^1.0.0', + }, + peerDependencies: { + 'peer-dep': '^1.0.0', + }, + }), + ...diffDepTypesNmFixture, + }, }) await ls.exec([]) t.matchSnapshot( - redactCwd(result), + cleanCwd(result()), 'should output tree containing top-level deps with descriptions' ) - config.all = true - config.depth = Infinity - config.long = false }) t.test('json read problems', async t => { - npm.prefix = t.testdir({ - 'package.json': '{broken json', + const { result, ls } = await mockLs(t, { + config: {}, + prefixDir: { + 'package.json': '{broken json', + }, }) await t.rejects(ls.exec([]), { code: 'EJSONPARSE' }, 'should throw EJSONPARSE error') - t.matchSnapshot(redactCwd(result), 'should print empty result') + t.matchSnapshot(cleanCwd(result()), 'should print empty result') }) t.test('empty location', async t => { - npm.prefix = t.testdir({}) + const { ls, result } = await mockLs(t) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should print empty result') + t.matchSnapshot(cleanCwd(result()), 'should print empty result') }) t.test('invalid peer dep', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'prod-dep': '^1.0.0', - chai: '^1.0.0', - }, - devDependencies: { - 'dev-dep': '^1.0.0', - }, - optionalDependencies: { - 'optional-dep': '^1.0.0', - }, - peerDependencies: { - 'peer-dep': '^2.0.0', // mismatching version # - }, - }), - ...diffDepTypesNmFixture, - }) - await t.rejects(ls.exec([])) - t.matchSnapshot( - redactCwd(result), + const { result, ls } = await mockLs(t, { + config: {}, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'prod-dep': '^1.0.0', + chai: '^1.0.0', + }, + devDependencies: { + 'dev-dep': '^1.0.0', + }, + optionalDependencies: { + 'optional-dep': '^1.0.0', + }, + peerDependencies: { + 'peer-dep': '^2.0.0', // mismatching version # + }, + }), + ...diffDepTypesNmFixture, + }, + }) + await t.rejects(ls.exec([])) + t.matchSnapshot( + cleanCwd(result()), 'should output tree signaling mismatching peer dep in problems' ) }) t.test('invalid deduped dep', async t => { - npm.color = true - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'invalid-deduped-dep', - version: '1.0.0', - dependencies: { - a: '^1.0.0', - b: '^2.0.0', - }, - }), - node_modules: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - dependencies: { - b: '^2.0.0', - }, - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'b', - version: '1.0.0', - }), + const config = { + color: 'always', + } + const { result, ls } = await mockLs(t, { + config, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'invalid-deduped-dep', + version: '1.0.0', + dependencies: { + a: '^1.0.0', + b: '^2.0.0', + }, + }), + node_modules: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + dependencies: { + b: '^2.0.0', + }, + }), + }, + b: { + 'package.json': JSON.stringify({ + name: 'b', + version: '1.0.0', + }), + }, }, }, }) await t.rejects(ls.exec([])) t.matchSnapshot( - redactCwd(result), + cleanCwd(result()), 'should output tree signaling mismatching peer dep in problems' ) - npm.color = false }) t.test('deduped missing dep', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - a: '^1.0.0', - b: '^1.0.0', - }, - }), - node_modules: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - dependencies: { - b: '^1.0.0', - }, - }), + const { result, ls } = await mockLs(t, { + config: {}, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + a: '^1.0.0', + b: '^1.0.0', + }, + }), + node_modules: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + dependencies: { + b: '^1.0.0', + }, + }), + }, }, }, }) @@ -867,51 +920,58 @@ t.test('ls', t => { 'should list missing dep problem' ) t.matchSnapshot( - redactCwd(result), + cleanCwd(result()), 'should output parseable signaling missing peer dep in problems' ) }) t.test('unmet peer dep', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - peerDependencies: { - 'peer-dep': '*', - }, - }), + const { result, ls } = await mockLs(t, { + config: {}, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + peerDependencies: { + 'peer-dep': '*', + }, + }), + }, }) await t.rejects( ls.exec([]), { code: 'ELSPROBLEMS', message: 'missing: peer-dep@*, required by test-npm-ls@1.0.0' }, 'should have missing peer-dep error msg' ) - t.matchSnapshot(redactCwd(result), 'should output tree signaling missing peer dep in problems') + t.matchSnapshot(cleanCwd(result()), + 'should output tree signaling missing peer dep in problems') }) t.test('unmet optional dep', async t => { - npm.color = true - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'prod-dep': '^1.0.0', - chai: '^1.0.0', - }, - devDependencies: { - 'dev-dep': '^1.0.0', - }, - optionalDependencies: { - 'missing-optional-dep': '^1.0.0', - 'optional-dep': '^2.0.0', // mismatching version # - }, - peerDependencies: { - 'peer-dep': '^1.0.0', - }, - }), - ...diffDepTypesNmFixture, + const config = { color: 'always' } + const { result, ls } = await mockLs(t, { + config, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'prod-dep': '^1.0.0', + chai: '^1.0.0', + }, + devDependencies: { + 'dev-dep': '^1.0.0', + }, + optionalDependencies: { + 'missing-optional-dep': '^1.0.0', + 'optional-dep': '^2.0.0', // mismatching version # + }, + peerDependencies: { + 'peer-dep': '^1.0.0', + }, + }), + ...diffDepTypesNmFixture, + }, }) await t.rejects( ls.exec([]), @@ -919,116 +979,38 @@ t.test('ls', t => { 'should have invalid dep error msg' ) t.matchSnapshot( - redactCwd(result), + cleanCwd(result()), 'should output tree with empty entry for missing optional deps' ) - npm.color = false }) t.test('cycle deps', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - a: '^1.0.0', - }, - }), - node_modules: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - dependencies: { - b: '^1.0.0', - }, - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'b', - version: '1.0.0', - dependencies: { - a: '^1.0.0', - }, - }), - }, - }, - }) - await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should print tree output containing deduped ref') - }) - - t.test('cycle deps with filter args', async t => { - npm.color = true - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - a: '^1.0.0', - }, - }), - node_modules: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - dependencies: { - b: '^1.0.0', - }, - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'b', - version: '1.0.0', - dependencies: { - a: '^1.0.0', - }, - }), - }, - }, - }) - await ls.exec(['a']) - t.matchSnapshot(redactCwd(result), 'should print tree output containing deduped ref') - npm.color = false - }) - - t.test('with no args dedupe entries', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'dedupe-entries', - version: '1.0.0', - dependencies: { - '@npmcli/a': '^1.0.0', - '@npmcli/b': '^1.0.0', - '@npmcli/c': '^1.0.0', - }, - }), - node_modules: { - '@npmcli': { + const { result, ls } = await mockLs(t, { + config: {}, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + a: '^1.0.0', + }, + }), + node_modules: { a: { 'package.json': JSON.stringify({ - name: '@npmcli/a', + name: 'a', version: '1.0.0', dependencies: { - '@npmcli/b': '^1.0.0', + b: '^1.0.0', }, }), }, b: { 'package.json': JSON.stringify({ - name: '@npmcli/b', - version: '1.1.2', - }), - }, - c: { - 'package.json': JSON.stringify({ - name: '@npmcli/c', + name: 'b', version: '1.0.0', dependencies: { - '@npmcli/b': '^1.0.0', + a: '^1.0.0', }, }), }, @@ -1036,400 +1018,509 @@ t.test('ls', t => { }, }) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should print tree output containing deduped ref') + t.matchSnapshot(cleanCwd(result()), 'should print tree output containing deduped ref') }) - t.test('with no args dedupe entries and not displaying all', async t => { - config.all = false - config.depth = 0 - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'dedupe-entries', - version: '1.0.0', - dependencies: { - '@npmcli/a': '^1.0.0', - '@npmcli/b': '^1.0.0', - '@npmcli/c': '^1.0.0', - }, - }), - node_modules: { - '@npmcli': { + t.test('cycle deps with filter args', async t => { + const config = { color: 'always' } + const { result, ls } = await mockLs(t, { + config, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + a: '^1.0.0', + }, + }), + node_modules: { a: { 'package.json': JSON.stringify({ - name: '@npmcli/a', + name: 'a', version: '1.0.0', dependencies: { - '@npmcli/b': '^1.0.0', + b: '^1.0.0', }, }), }, b: { 'package.json': JSON.stringify({ - name: '@npmcli/b', - version: '1.1.2', - }), - }, - c: { - 'package.json': JSON.stringify({ - name: '@npmcli/c', + name: 'b', version: '1.0.0', dependencies: { - '@npmcli/b': '^1.0.0', + a: '^1.0.0', }, }), }, }, }, }) - await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should print tree output containing deduped ref') - config.all = true - config.depth = Infinity + await ls.exec(['a']) + t.matchSnapshot(cleanCwd(result()), 'should print tree output containing deduped ref') }) - t.test('with args and dedupe entries', async t => { - npm.color = true - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'dedupe-entries', - version: '1.0.0', - dependencies: { - '@npmcli/a': '^1.0.0', - '@npmcli/b': '^1.0.0', - '@npmcli/c': '^1.0.0', - }, - }), - node_modules: { - '@npmcli': { - a: { - 'package.json': JSON.stringify({ - name: '@npmcli/a', - version: '1.0.0', - dependencies: { - '@npmcli/b': '^1.0.0', - }, - }), - }, - b: { - 'package.json': JSON.stringify({ - name: '@npmcli/b', - version: '1.1.2', - }), + t.test('with no args dedupe entries', async t => { + const { result, ls } = await mockLs(t, { + config: {}, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'dedupe-entries', + version: '1.0.0', + dependencies: { + '@npmcli/a': '^1.0.0', + '@npmcli/b': '^1.0.0', + '@npmcli/c': '^1.0.0', }, - c: { - 'package.json': JSON.stringify({ - name: '@npmcli/c', - version: '1.0.0', - dependencies: { - '@npmcli/b': '^1.0.0', - }, - }), + }), + node_modules: { + '@npmcli': { + a: { + 'package.json': JSON.stringify({ + name: '@npmcli/a', + version: '1.0.0', + dependencies: { + '@npmcli/b': '^1.0.0', + }, + }), + }, + b: { + 'package.json': JSON.stringify({ + name: '@npmcli/b', + version: '1.1.2', + }), + }, + c: { + 'package.json': JSON.stringify({ + name: '@npmcli/c', + version: '1.0.0', + dependencies: { + '@npmcli/b': '^1.0.0', + }, + }), + }, }, }, }, }) - await ls.exec(['@npmcli/b']) - t.matchSnapshot(redactCwd(result), 'should print tree output containing deduped ref') - npm.color = false + await ls.exec([]) + t.matchSnapshot(cleanCwd(result()), 'should print tree output containing deduped ref') }) - t.test('with args and different order of items', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'dedupe-entries', - version: '1.0.0', - dependencies: { - '@npmcli/a': '^1.0.0', - '@npmcli/b': '^1.0.0', - '@npmcli/c': '^1.0.0', - }, - }), - node_modules: { - '@npmcli': { - a: { - 'package.json': JSON.stringify({ - name: '@npmcli/a', - version: '1.0.0', - dependencies: { - '@npmcli/c': '^1.0.0', - }, - }), + t.test('with no args dedupe entries and not displaying all', async t => { + const config = { + all: false, + depth: 0, + } + const { result, ls } = await mockLs(t, { + config, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'dedupe-entries', + version: '1.0.0', + dependencies: { + '@npmcli/a': '^1.0.0', + '@npmcli/b': '^1.0.0', + '@npmcli/c': '^1.0.0', }, - b: { - 'package.json': JSON.stringify({ - name: '@npmcli/b', - version: '1.1.2', - dependencies: { - '@npmcli/c': '^1.0.0', - }, - }), + }), + node_modules: { + '@npmcli': { + a: { + 'package.json': JSON.stringify({ + name: '@npmcli/a', + version: '1.0.0', + dependencies: { + '@npmcli/b': '^1.0.0', + }, + }), + }, + b: { + 'package.json': JSON.stringify({ + name: '@npmcli/b', + version: '1.1.2', + }), + }, + c: { + 'package.json': JSON.stringify({ + name: '@npmcli/c', + version: '1.0.0', + dependencies: { + '@npmcli/b': '^1.0.0', + }, + }), + }, }, - c: { - 'package.json': JSON.stringify({ - name: '@npmcli/c', - version: '1.0.0', - }), + }, + }, + }) + await ls.exec([]) + t.matchSnapshot(cleanCwd(result()), 'should print tree output containing deduped ref') + }) + + t.test('with args and dedupe entries', async t => { + const config = { color: 'always' } + const { result, ls } = await mockLs(t, { + config, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'dedupe-entries', + version: '1.0.0', + dependencies: { + '@npmcli/a': '^1.0.0', + '@npmcli/b': '^1.0.0', + '@npmcli/c': '^1.0.0', + }, + }), + node_modules: { + '@npmcli': { + a: { + 'package.json': JSON.stringify({ + name: '@npmcli/a', + version: '1.0.0', + dependencies: { + '@npmcli/b': '^1.0.0', + }, + }), + }, + b: { + 'package.json': JSON.stringify({ + name: '@npmcli/b', + version: '1.1.2', + }), + }, + c: { + 'package.json': JSON.stringify({ + name: '@npmcli/c', + version: '1.0.0', + dependencies: { + '@npmcli/b': '^1.0.0', + }, + }), + }, + }, + }, + }, + }) + await ls.exec(['@npmcli/b']) + t.matchSnapshot(cleanCwd(result()), 'should print tree output containing deduped ref') + }) + + t.test('with args and different order of items', async t => { + const { result, ls } = await mockLs(t, { + config: {}, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'dedupe-entries', + version: '1.0.0', + dependencies: { + '@npmcli/a': '^1.0.0', + '@npmcli/b': '^1.0.0', + '@npmcli/c': '^1.0.0', + }, + }), + node_modules: { + '@npmcli': { + a: { + 'package.json': JSON.stringify({ + name: '@npmcli/a', + version: '1.0.0', + dependencies: { + '@npmcli/c': '^1.0.0', + }, + }), + }, + b: { + 'package.json': JSON.stringify({ + name: '@npmcli/b', + version: '1.1.2', + dependencies: { + '@npmcli/c': '^1.0.0', + }, + }), + }, + c: { + 'package.json': JSON.stringify({ + name: '@npmcli/c', + version: '1.0.0', + }), + }, }, }, }, }) await ls.exec(['@npmcli/c']) - t.matchSnapshot(redactCwd(result), 'should print tree output containing deduped ref') + t.matchSnapshot(cleanCwd(result()), 'should print tree output containing deduped ref') }) t.test('using aliases', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - a: 'npm:b@1.0.0', - }, - }), - node_modules: { - '.package-lock.json': JSON.stringify({ - packages: { - 'node_modules/a': { + const { npm, result, ls } = await mockLs(t, { + config: {}, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + a: 'npm:b@1.0.0', + }, + }), + node_modules: { + '.package-lock.json': JSON.stringify({ + packages: { + 'node_modules/a': { + name: 'b', + version: '1.0.0', + from: 'a@npm:b', + resolved: 'https://localhost:8080/abbrev/-/abbrev-1.1.1.tgz', + requested: { + type: 'alias', + }, + }, + }, + }), + 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: { + _from: 'a@npm:b', + _resolved: 'https://localhost:8080/abbrev/-/abbrev-1.1.1.tgz', + _requested: { type: 'alias', }, - }, + }), }, - }), - 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', - }, - }), }, }, }) touchHiddenPackageLock(npm.prefix) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should output tree containing aliases') + t.matchSnapshot(cleanCwd(result()), 'should output tree containing aliases') }) t.test('resolved points to git ref', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - abbrev: 'git+https://github.com/isaacs/abbrev-js.git', - }, - }), - node_modules: { - '.package-lock.json': JSON.stringify({ - packages: { - 'node_modules/abbrev': { - name: 'abbrev', - version: '1.1.1', - from: 'git+https://github.com/isaacs/abbrev-js.git', - /* eslint-disable-next-line max-len */ - resolved: 'git+https://github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', - }, + const { npm, result, ls } = await mockLs(t, { + config: {}, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + abbrev: 'git+https://github.com/isaacs/abbrev-js.git', }, }), - abbrev: { - 'package.json': JSON.stringify({ - name: 'abbrev', - version: '1.1.1', - _id: 'abbrev@1.1.1', - _from: 'git+https://github.com/isaacs/abbrev-js.git', - /* eslint-disable-next-line max-len */ - _resolved: 'git+https://github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', - _requested: { - type: 'git', - raw: 'git+https:github.com/isaacs/abbrev-js.git', - 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, + node_modules: { + '.package-lock.json': JSON.stringify({ + packages: { + 'node_modules/abbrev': { + name: 'abbrev', + version: '1.1.1', + from: 'git+https://github.com/isaacs/abbrev-js.git', + /* eslint-disable-next-line max-len */ + resolved: 'git+https://github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', + }, }, }), + abbrev: { + 'package.json': JSON.stringify({ + name: 'abbrev', + version: '1.1.1', + _id: 'abbrev@1.1.1', + _from: 'git+https://github.com/isaacs/abbrev-js.git', + /* eslint-disable-next-line max-len */ + _resolved: 'git+https://github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', + _requested: { + type: 'git', + raw: 'git+https:github.com/isaacs/abbrev-js.git', + 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, + }, + }), + }, }, }, }) touchHiddenPackageLock(npm.prefix) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should output tree containing git refs') + t.matchSnapshot(cleanCwd(result()), 'should output tree containing git refs') }) t.test('broken resolved field', async t => { - npm.prefix = t.testdir({ - node_modules: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - 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: 'a', - version: '1.0.1', - }, - }, - dependencies: { + const { result, ls } = await mockLs(t, { + config: {}, + prefixDir: { + node_modules: { a: { - version: '1.0.1', - resolved: 'foo@dog://b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', - /* eslint-disable-next-line max-len */ - integrity: 'sha512-8AN9lNCcBt5Xeje7fMEEpp5K3rgcAzIpTtAjYb/YMUYu8SbIVF6wz0WqACDVKvpQOUcSfNHZQNLNmue0QSwXOQ==', + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.1', + }), }, }, - }), - 'package.json': JSON.stringify({ - name: 'npm-broken-resolved-field-test', - version: '1.0.0', - dependencies: { - a: '^1.0.1', - }, - }), + 'package-lock.json': JSON.stringify({ + name: 'npm-broken-resolved-field-test', + version: '1.0.0', + lockfileVersion: 2, + requires: true, + packages: { + '': { + name: 'a', + version: '1.0.1', + }, + }, + dependencies: { + a: { + version: '1.0.1', + resolved: 'foo@dog://b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', + /* eslint-disable-next-line max-len */ + integrity: 'sha512-8AN9lNCcBt5Xeje7fMEEpp5K3rgcAzIpTtAjYb/YMUYu8SbIVF6wz0WqACDVKvpQOUcSfNHZQNLNmue0QSwXOQ==', + }, + }, + }), + 'package.json': JSON.stringify({ + name: 'npm-broken-resolved-field-test', + version: '1.0.0', + dependencies: { + a: '^1.0.1', + }, + }), + }, }) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should NOT print git refs in output tree') + t.matchSnapshot(cleanCwd(result()), 'should NOT print git refs in output tree') }) t.test('from and resolved properties', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'simple-output': '^2.0.0', - }, - }), - node_modules: { - '.package-lock.json': JSON.stringify({ - packages: { - 'node_modules/simple-output': { - name: 'simple-output', - version: '2.1.1', - resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz', - shasum: '3c07708ec9ef3e3c985cf0ddd67df09ab8ec2abc', - }, + const { npm, result, ls } = await mockLs(t, { + config: {}, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'simple-output': '^2.0.0', }, }), - 'simple-output': { - 'package.json': JSON.stringify({ - name: 'simple-output', - version: '2.1.1', - _from: 'simple-output', - _id: 'simple-output@2.1.1', - _resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz', - _requested: { - type: 'tag', - registry: true, - raw: 'simple-output', - name: 'simple-output', - escapedName: 'simple-output', - rawSpec: '', - saveSpec: null, - fetchSpec: 'latest', + node_modules: { + '.package-lock.json': JSON.stringify({ + packages: { + 'node_modules/simple-output': { + name: 'simple-output', + version: '2.1.1', + resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz', + shasum: '3c07708ec9ef3e3c985cf0ddd67df09ab8ec2abc', + }, }, - _requiredBy: ['#USER', '/'], - _shasum: '3c07708ec9ef3e3c985cf0ddd67df09ab8ec2abc', - _spec: 'simple-output', }), + 'simple-output': { + 'package.json': JSON.stringify({ + name: 'simple-output', + version: '2.1.1', + _from: 'simple-output', + _id: 'simple-output@2.1.1', + _resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz', + _requested: { + type: 'tag', + registry: true, + raw: 'simple-output', + name: 'simple-output', + escapedName: 'simple-output', + rawSpec: '', + saveSpec: null, + fetchSpec: 'latest', + }, + _requiredBy: ['#USER', '/'], + _shasum: '3c07708ec9ef3e3c985cf0ddd67df09ab8ec2abc', + _spec: 'simple-output', + }), + }, }, }, }) touchHiddenPackageLock(npm.prefix) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should not be printed in tree output') + t.matchSnapshot(cleanCwd(result()), 'should not be printed in tree output') }) t.test('global', async t => { - config.global = true - const fixtures = t.testdir({ - node_modules: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'b', - version: '1.0.0', - }), - node_modules: { - c: { - 'package.json': JSON.stringify({ - name: 'c', - version: '1.0.0', - }), + const config = { + global: true, + } + const { result, ls } = await mockLs(t, { + config, + globalPrefixDir: { + node_modules: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + }), + }, + b: { + 'package.json': JSON.stringify({ + name: 'b', + version: '1.0.0', + }), + node_modules: { + c: { + 'package.json': JSON.stringify({ + name: 'c', + version: '1.0.0', + }), + }, }, }, }, }, }) - // mimics lib/npm.js globalDir getter but pointing to fixtures - npm.globalDir = resolve(fixtures, 'node_modules') - await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should print tree and not mark top-level items extraneous') - npm.globalDir = 'MISSING_GLOBAL_DIR' - config.global = false + t.matchSnapshot(cleanCwd(result()), + 'should print tree and not mark top-level items extraneous') }) t.test('filtering by child of missing dep', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'filter-by-child-of-missing-dep', - version: '1.0.0', - dependencies: { - a: '^1.0.0', - }, - }), - node_modules: { - b: { - 'package.json': JSON.stringify({ - name: 'b', - version: '1.0.0', - dependencies: { - c: '^1.0.0', - }, - }), - }, - c: { - 'package.json': JSON.stringify({ - name: 'c', - version: '1.0.0', - }), - }, - d: { - 'package.json': JSON.stringify({ - name: 'd', - version: '1.0.0', - dependencies: { - c: '^2.0.0', - }, - }), - node_modules: { - c: { - 'package.json': JSON.stringify({ - name: 'c', - version: '2.0.0', - }), + const { result, ls } = await mockLs(t, { + config: {}, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'filter-by-child-of-missing-dep', + version: '1.0.0', + dependencies: { + a: '^1.0.0', + }, + }), + node_modules: { + b: { + 'package.json': JSON.stringify({ + name: 'b', + version: '1.0.0', + dependencies: { + c: '^1.0.0', + }, + }), + }, + c: { + 'package.json': JSON.stringify({ + name: 'c', + version: '1.0.0', + }), + }, + d: { + 'package.json': JSON.stringify({ + name: 'd', + version: '1.0.0', + dependencies: { + c: '^2.0.0', + }, + }), + node_modules: { + c: { + 'package.json': JSON.stringify({ + name: 'c', + version: '2.0.0', + }), + }, }, }, }, @@ -1438,772 +1529,830 @@ t.test('ls', t => { await ls.exec(['c']) t.matchSnapshot( - redactCwd(result), + cleanCwd(result()), 'should print tree and not duplicate child of missing items' ) }) t.test('loading a tree containing workspaces', async t => { - npm.localPrefix = npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'workspaces-tree', - version: '1.0.0', - workspaces: ['./a', './b', './d', './group/*'], - dependencies: { pacote: '1.0.0' }, - }), - node_modules: { - a: t.fixture('symlink', '../a'), - b: t.fixture('symlink', '../b'), - c: { + const mockWorkspaces = async (t, exec = [], config = {}) => { + const { result, ls } = await mockLs(t, { + config, + prefixDir: { 'package.json': JSON.stringify({ - name: 'c', + name: 'workspaces-tree', version: '1.0.0', + workspaces: ['./a', './b', './d', './group/*'], + dependencies: { pacote: '1.0.0' }, }), - }, - d: t.fixture('symlink', '../d'), - e: t.fixture('symlink', '../group/e'), - f: t.fixture('symlink', '../group/f'), - foo: { - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.1.1', - dependencies: { - bar: '^1.0.0', + node_modules: { + a: t.fixture('symlink', '../a'), + b: t.fixture('symlink', '../b'), + c: { + 'package.json': JSON.stringify({ + name: 'c', + version: '1.0.0', + }), + }, + d: t.fixture('symlink', '../d'), + e: t.fixture('symlink', '../group/e'), + f: t.fixture('symlink', '../group/f'), + foo: { + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.1.1', + dependencies: { + bar: '^1.0.0', + }, + }), + }, + bar: { + 'package.json': JSON.stringify({ name: 'bar', version: '1.0.0' }), + }, + baz: { + 'package.json': JSON.stringify({ name: 'baz', version: '1.0.0' }), + }, + pacote: { + 'package.json': JSON.stringify({ name: 'pacote', version: '1.0.0' }), }, - }), - }, - bar: { - 'package.json': JSON.stringify({ name: 'bar', version: '1.0.0' }), - }, - baz: { - 'package.json': JSON.stringify({ name: 'baz', version: '1.0.0' }), - }, - pacote: { - 'package.json': JSON.stringify({ name: 'pacote', version: '1.0.0' }), - }, - }, - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - dependencies: { - c: '^1.0.0', - d: '^1.0.0', }, - devDependencies: { - baz: '^1.0.0', + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + dependencies: { + c: '^1.0.0', + d: '^1.0.0', + }, + devDependencies: { + baz: '^1.0.0', + }, + }), }, - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'b', - version: '1.0.0', - }), - }, - d: { - 'package.json': JSON.stringify({ - name: 'd', - version: '1.0.0', - dependencies: { - foo: '^1.1.1', + b: { + 'package.json': JSON.stringify({ + name: 'b', + version: '1.0.0', + }), + }, + d: { + 'package.json': JSON.stringify({ + name: 'd', + version: '1.0.0', + dependencies: { + foo: '^1.1.1', + }, + }), + }, + group: { + e: { + 'package.json': JSON.stringify({ + name: 'e', + version: '1.0.0', + }), + }, + f: { + 'package.json': JSON.stringify({ + name: 'f', + version: '1.0.0', + }), + }, }, - }), - }, - group: { - e: { - 'package.json': JSON.stringify({ - name: 'e', - version: '1.0.0', - }), - }, - f: { - 'package.json': JSON.stringify({ - name: 'f', - version: '1.0.0', - }), }, - }, - }) + }) - config.all = false - config.depth = 0 - npm.color = true - await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should list workspaces properly with default configs') + await ls.exec(exec) - config.all = false - config.depth = 0 - npm.color = true - npm.flatOptions.workspacesEnabled = false - await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should not list workspaces with --no-workspaces') + t.matchSnapshot(cleanCwd(result(), t), 'output') + } - config.all = true - config.depth = Infinity - npm.color = false - npm.flatOptions.workspacesEnabled = true + t.test('should list workspaces properly with default configs', t => mockWorkspaces(t, [], { + depth: 0, + color: 'always', + })) + + t.test('should not list workspaces with --no-workspaces', t => mockWorkspaces(t, [], { + depth: 0, + color: 'always', + workspaces: false, + })) // --all - await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should list --all workspaces properly') + t.test('should list --all workspaces properly', t => mockWorkspaces(t)) // --production - flatOptions.omit = ['dev', 'peer', 'optional'] - await ls.exec([]) - - t.matchSnapshot(redactCwd(result), 'should list only prod deps of workspaces') - - flatOptions.omit = [] + t.test('should list only prod deps of workspaces', t => mockWorkspaces(t, [], { + omit: ['dev', 'peer', 'optional'], + })) // filter out a single workspace using args - await ls.exec(['d']) - t.matchSnapshot(redactCwd(result), 'should filter single workspace') + t.test('should filter single workspace', t => mockWorkspaces(t, ['d'])) // filter out a single workspace and its deps using workspaces filters - await ls.execWorkspaces([], ['a']) - - t.matchSnapshot(redactCwd(result), 'should filter using workspace config') + t.test('should filter using workspace config', t => mockWorkspaces(t, [], { + workspace: 'a', + })) // filter out a single workspace and include root - npm.flatOptions.includeWorkspaceRoot = true - await ls.execWorkspaces([], ['d']) - t.matchSnapshot(redactCwd(result), 'should inlude root and specified workspace') - npm.flatOptions.includeWorkspaceRoot = false + t.test('should inlude root and specified workspace', t => mockWorkspaces(t, [], { + 'include-workspace-root': true, + workspace: 'd', + })) // filter out a workspace by parent path - await ls.execWorkspaces([], ['./group']) - - t.matchSnapshot(redactCwd(result), 'should filter by parent folder workspace config') + t.test('should filter by parent folder workspace config', t => mockWorkspaces(t, [], { + workspace: './group', + })) // filter by a dep within a workspaces sub tree - await ls.execWorkspaces(['bar'], ['d']) - - t.matchSnapshot( - redactCwd(result), - 'should print all tree and filter by dep within only the ws subtree' - ) + t.test('should print all tree and filter by dep within only the ws subtree', t => + mockWorkspaces(t, ['bar'], { + workspace: 'd', + })) }) t.test('filter pkg arg using depth option', async t => { - config.depth = 0 - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-pkg-arg-filter-with-depth-opt', - version: '1.0.0', - dependencies: { - a: '^1.0.0', - b: '^1.0.0', - }, - }), - node_modules: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - }), - }, - b: { + const mock = async (t, exec, depth = 0) => { + const { result, ls } = await mockLs(t, { + config: typeof depth === 'number' ? { depth } : {}, + prefixDir: { 'package.json': JSON.stringify({ - name: 'b', + name: 'test-pkg-arg-filter-with-depth-opt', version: '1.0.0', dependencies: { - c: '^1.0.0', + a: '^1.0.0', + b: '^1.0.0', }, }), - }, - c: { - 'package.json': JSON.stringify({ - name: 'c', - version: '1.0.0', - dependencies: { - d: '^1.0.0', + node_modules: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + }), }, - }), - }, - d: { - 'package.json': JSON.stringify({ - name: 'd', - version: '1.0.0', - dependencies: { - a: '^1.0.0', + b: { + 'package.json': JSON.stringify({ + name: 'b', + version: '1.0.0', + dependencies: { + c: '^1.0.0', + }, + }), }, - }), + c: { + 'package.json': JSON.stringify({ + name: 'c', + version: '1.0.0', + dependencies: { + d: '^1.0.0', + }, + }), + }, + d: { + 'package.json': JSON.stringify({ + name: 'd', + version: '1.0.0', + dependencies: { + a: '^1.0.0', + }, + }), + }, + }, }, - }, - }) + }) - t.plan(3) - await ls.exec(['a']) - t.matchSnapshot(redactCwd(result), 'should list a in top-level only') + await ls.exec(exec) - await ls.exec(['d']) - t.matchSnapshot(redactCwd(result), 'should print empty results msg') + t.matchSnapshot(cleanCwd(result(), t), 'output') + } - // if no --depth config is defined, should print path to dep - config.depth = null // default config value - await ls.exec(['d']) - t.matchSnapshot(redactCwd(result), 'should print expected result') - process.exitCode = 0 - }) + t.test('should list a in top-level only', t => mock(t, ['a'])) - t.teardown(() => { - config.depth = Infinity - }) + t.test('should print empty results msg', t => mock(t, ['d'])) - t.end() + // if no --depth config is defined, should print path to dep + t.test('should print expected result', t => mock(t, ['d'], null)) + }) }) -t.test('ls --parseable', t => { - t.beforeEach(cleanUpResult) - config.json = false - config.unicode = false - config.parseable = true +t.test('ls --parseable', async t => { + const parseable = { parseable: true } t.test('no args', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - }, - }), - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + config: parseable, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await ls.exec([]) t.matchSnapshot( - redactCwd(result), + cleanCwd(result()), 'should output parseable representation of dependencies structure' ) }) t.test('missing package.json', async t => { - npm.prefix = t.testdir({ - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + config: parseable, + prefixDir: { + ...simpleNmFixture, + }, }) await ls.exec([]) t.matchSnapshot( - redactCwd(result), + cleanCwd(result()), 'should output parseable missing name/version of top-level package' ) }) t.test('extraneous deps', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - }, - }), - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + config: parseable, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should output containing problems info') + t.matchSnapshot(cleanCwd(result()), 'should output containing problems info') }) t.test('overridden dep', async t => { - config.all = true - config.long = true - t.teardown(() => { - config.all = false - config.long = false - }) - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-overridden', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - }, - overrides: { - bar: '1.0.0', - }, - }), - node_modules: { - foo: { - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.0.0', - dependencies: { - bar: '^2.0.0', - }, - }), - }, - bar: { - 'package.json': JSON.stringify({ - name: 'bar', - version: '1.0.0', - }), + const { result, ls } = await mockLs(t, { + config: { ...parseable, long: true }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-overridden', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + }, + overrides: { + bar: '1.0.0', + }, + }), + node_modules: { + foo: { + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.0.0', + dependencies: { + bar: '^2.0.0', + }, + }), + }, + bar: { + 'package.json': JSON.stringify({ + name: 'bar', + version: '1.0.0', + }), + }, }, }, }) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should contain overridden outout') + t.matchSnapshot(cleanCwd(result()), 'should contain overridden outout') }) t.test('with filter arg', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - }, - }), - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + config: parseable, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await ls.exec(['chai']) t.matchSnapshot( - redactCwd(result), + cleanCwd(result()), 'should output parseable contaning only occurrences of filtered by package' ) }) t.test('with filter arg nested dep', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - }, - }), - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + config: parseable, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await ls.exec(['dog']) t.matchSnapshot( - redactCwd(result), + cleanCwd(result()), 'should output parseable contaning only occurrences of filtered package' ) }) t.test('with multiple filter args', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - ipsum: '^1.0.0', - }, - }), - node_modules: { - ...simpleNmFixture.node_modules, - ipsum: { - 'package.json': JSON.stringify({ - name: 'ipsum', - version: '1.0.0', - }), + const { result, ls } = await mockLs(t, { + config: parseable, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', + ipsum: '^1.0.0', + }, + }), + node_modules: { + ...simpleNmFixture.node_modules, + ipsum: { + 'package.json': JSON.stringify({ + name: 'ipsum', + version: '1.0.0', + }), + }, }, }, }) await ls.exec(['dog@*', 'chai@1.0.0']) t.matchSnapshot( - redactCwd(result), + cleanCwd(result()), /* eslint-disable-next-line max-len */ 'should output parseable contaning only occurrences of multiple filtered packages and their ancestors' ) }) t.test('with missing filter arg', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - }, - }), - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + config: parseable, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await ls.exec(['notadep']) t.matchSnapshot( - redactCwd(result), + cleanCwd(result()), 'should output parseable output containing no dependencies info' ) }) t.test('default --depth value should be 0', async t => { - config.all = false - config.depth = undefined - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - }, - }), - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + config: { ...parseable, all: false }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await ls.exec([]) t.matchSnapshot( - redactCwd(result), + cleanCwd(result()), 'should output parseable output containing only top-level dependencies' ) - config.all = true - config.depth = Infinity }) t.test('--depth=0', async t => { - config.all = false - config.depth = 0 - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - }, - }), - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + config: { ...parseable, all: false, depth: 0 }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should output tree containing only top-level dependencies') - config.all = true - config.depth = Infinity + t.matchSnapshot(cleanCwd(result()), + 'should output tree containing only top-level dependencies') }) t.test('--depth=1', async t => { - config.all = false - config.depth = 1 - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - }, - }), - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + config: { ...parseable, all: false, depth: 1 }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await ls.exec([]) t.matchSnapshot( - redactCwd(result), + cleanCwd(result()), 'should output parseable containing top-level deps and their deps only' ) - config.all = true - config.depth = Infinity }) t.test('missing/invalid/extraneous', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^2.0.0', - ipsum: '^1.0.0', - }, - }), - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + config: parseable, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^2.0.0', + ipsum: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await t.rejects(ls.exec([]), { code: 'ELSPROBLEMS' }, 'should list dep problems') t.matchSnapshot( - redactCwd(result), + cleanCwd(result()), 'should output parseable containing top-level deps and their deps only' ) }) t.test('--dev', async t => { - flatOptions.omit = ['peer', 'prod', 'optional'] - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'prod-dep': '^1.0.0', - chai: '^1.0.0', - }, - devDependencies: { - 'dev-dep': '^1.0.0', - }, - optionalDependencies: { - 'optional-dep': '^1.0.0', - }, - peerDependencies: { - 'peer-dep': '^1.0.0', - }, - }), - ...diffDepTypesNmFixture, + const { result, ls } = await mockLs(t, { + config: { + ...parseable, + omit: ['peer', 'prod', 'optional'], + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'prod-dep': '^1.0.0', + chai: '^1.0.0', + }, + devDependencies: { + 'dev-dep': '^1.0.0', + }, + optionalDependencies: { + 'optional-dep': '^1.0.0', + }, + peerDependencies: { + 'peer-dep': '^1.0.0', + }, + }), + ...diffDepTypesNmFixture, + }, }) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should output tree containing dev deps') - flatOptions.omit = [] + t.matchSnapshot(cleanCwd(result()), 'should output tree containing dev deps') }) t.test('--link', async t => { - config.link = true - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'prod-dep': '^1.0.0', - chai: '^1.0.0', - 'linked-dep': '^1.0.0', - }, - devDependencies: { - 'dev-dep': '^1.0.0', - }, - optionalDependencies: { - 'optional-dep': '^1.0.0', - }, - peerDependencies: { - 'peer-dep': '^1.0.0', - }, - }), - 'linked-dep': { + const { result, ls } = await mockLs(t, { + config: { + ...parseable, + link: true, + }, + prefixDir: { 'package.json': JSON.stringify({ - name: 'linked-dep', + name: 'test-npm-ls', version: '1.0.0', + dependencies: { + 'prod-dep': '^1.0.0', + chai: '^1.0.0', + 'linked-dep': '^1.0.0', + }, + devDependencies: { + 'dev-dep': '^1.0.0', + }, + optionalDependencies: { + 'optional-dep': '^1.0.0', + }, + peerDependencies: { + 'peer-dep': '^1.0.0', + }, }), - }, - node_modules: { - 'linked-dep': t.fixture('symlink', '../linked-dep'), - ...diffDepTypesNmFixture.node_modules, + 'linked-dep': { + 'package.json': JSON.stringify({ + name: 'linked-dep', + version: '1.0.0', + }), + }, + node_modules: { + 'linked-dep': t.fixture('symlink', '../linked-dep'), + ...diffDepTypesNmFixture.node_modules, + }, }, }) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should output tree containing linked deps') - config.link = false + t.matchSnapshot(cleanCwd(result()), 'should output tree containing linked deps') }) t.test('--production', async t => { - flatOptions.omit = ['dev', 'peer'] - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'prod-dep': '^1.0.0', - chai: '^1.0.0', - }, - devDependencies: { - 'dev-dep': '^1.0.0', - }, - optionalDependencies: { - 'optional-dep': '^1.0.0', - }, - peerDependencies: { - 'peer-dep': '^1.0.0', - }, - }), - ...diffDepTypesNmFixture, + const { result, ls } = await mockLs(t, { + config: { + ...parseable, + omit: ['dev', 'peer'], + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'prod-dep': '^1.0.0', + chai: '^1.0.0', + }, + devDependencies: { + 'dev-dep': '^1.0.0', + }, + optionalDependencies: { + 'optional-dep': '^1.0.0', + }, + peerDependencies: { + 'peer-dep': '^1.0.0', + }, + }), + ...diffDepTypesNmFixture, + }, }) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should output tree containing production deps') - flatOptions.omit = [] + t.matchSnapshot(cleanCwd(result()), 'should output tree containing production deps') }) t.test('--long', async t => { - config.long = true - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'prod-dep': '^1.0.0', - chai: '^1.0.0', - }, - devDependencies: { - 'dev-dep': '^1.0.0', - }, - optionalDependencies: { - 'optional-dep': '^1.0.0', - }, - peerDependencies: { - 'peer-dep': '^1.0.0', - }, - }), - ...diffDepTypesNmFixture, + const { result, ls } = await mockLs(t, { + config: { + ...parseable, + long: true, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'prod-dep': '^1.0.0', + chai: '^1.0.0', + }, + devDependencies: { + 'dev-dep': '^1.0.0', + }, + optionalDependencies: { + 'optional-dep': '^1.0.0', + }, + peerDependencies: { + 'peer-dep': '^1.0.0', + }, + }), + ...diffDepTypesNmFixture, + }, }) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should output tree info with descriptions') - config.long = true + t.matchSnapshot(cleanCwd(result()), 'should output tree info with descriptions') }) t.test('--long with extraneous deps', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - }, - }), - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + config: { + ...parseable, + long: true, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should output long parseable output with extraneous info') + t.matchSnapshot(cleanCwd(result()), 'should output long parseable output with extraneous info') }) t.test('--long missing/invalid/extraneous', async t => { - config.long = true - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^2.0.0', - ipsum: '^1.0.0', - }, - }), - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + config: { + ...parseable, + long: true, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^2.0.0', + ipsum: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await t.rejects(ls.exec([]), { code: 'ELSPROBLEMS' }, 'should list dep problems') t.matchSnapshot( - redactCwd(result), + cleanCwd(result()), 'should output parseable result containing EXTRANEOUS/INVALID labels' ) - config.long = false }) t.test('--long print symlink target location', async t => { - config.long = true - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'prod-dep': '^1.0.0', - chai: '^1.0.0', - 'linked-dep': '^1.0.0', - }, - devDependencies: { - 'dev-dep': '^1.0.0', - }, - optionalDependencies: { - 'optional-dep': '^1.0.0', - }, - peerDependencies: { - 'peer-dep': '^1.0.0', - }, - }), - 'linked-dep': { + const { result, ls } = await mockLs(t, { + config: { + ...parseable, + long: true, + }, + prefixDir: { 'package.json': JSON.stringify({ - name: 'linked-dep', + name: 'test-npm-ls', version: '1.0.0', + dependencies: { + 'prod-dep': '^1.0.0', + chai: '^1.0.0', + 'linked-dep': '^1.0.0', + }, + devDependencies: { + 'dev-dep': '^1.0.0', + }, + optionalDependencies: { + 'optional-dep': '^1.0.0', + }, + peerDependencies: { + 'peer-dep': '^1.0.0', + }, }), - }, - node_modules: { - 'linked-dep': t.fixture('symlink', '../linked-dep'), - ...diffDepTypesNmFixture.node_modules, + 'linked-dep': { + 'package.json': JSON.stringify({ + name: 'linked-dep', + version: '1.0.0', + }), + }, + node_modules: { + 'linked-dep': t.fixture('symlink', '../linked-dep'), + ...diffDepTypesNmFixture.node_modules, + }, }, }) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should output parseable results with symlink targets') - config.long = false + t.matchSnapshot(cleanCwd(result()), 'should output parseable results with symlink targets') }) t.test('--long --depth=0', async t => { - config.all = false - config.depth = 0 - config.long = true - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'prod-dep': '^1.0.0', - chai: '^1.0.0', - }, - devDependencies: { - 'dev-dep': '^1.0.0', - }, - optionalDependencies: { - 'optional-dep': '^1.0.0', - }, - peerDependencies: { - 'peer-dep': '^1.0.0', - }, - }), - ...diffDepTypesNmFixture, + const { result, ls } = await mockLs(t, { + config: { + ...parseable, + all: false, + depth: 0, + long: true, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'prod-dep': '^1.0.0', + chai: '^1.0.0', + }, + devDependencies: { + 'dev-dep': '^1.0.0', + }, + optionalDependencies: { + 'optional-dep': '^1.0.0', + }, + peerDependencies: { + 'peer-dep': '^1.0.0', + }, + }), + ...diffDepTypesNmFixture, + }, }) await ls.exec([]) t.matchSnapshot( - redactCwd(result), + cleanCwd(result()), 'should output tree containing top-level deps with descriptions' ) - config.all = true - config.depth = Infinity - config.long = false }) t.test('json read problems', async t => { - npm.prefix = t.testdir({ - 'package.json': '{broken json', + const { result, ls } = await mockLs(t, { + config: { + ...parseable, + }, + prefixDir: { + 'package.json': '{broken json', + }, }) await t.rejects(ls.exec([]), { code: 'EJSONPARSE' }, 'should throw EJSONPARSE error') - t.matchSnapshot(redactCwd(result), 'should print empty result') + t.matchSnapshot(cleanCwd(result()), 'should print empty result') }) t.test('empty location', async t => { - npm.prefix = t.testdir({}) + const { ls, result } = await mockLs(t, { + config: { + ...parseable, + }, + }) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should print empty result') + t.matchSnapshot(cleanCwd(result()), 'should print empty result') }) t.test('unmet peer dep', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'prod-dep': '^1.0.0', - chai: '^1.0.0', - }, - devDependencies: { - 'dev-dep': '^1.0.0', - }, - optionalDependencies: { - 'optional-dep': '^1.0.0', - }, - peerDependencies: { - 'peer-dep': '^2.0.0', // mismatching version # - }, - }), - ...diffDepTypesNmFixture, + const { result, ls } = await mockLs(t, { + config: { + ...parseable, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'prod-dep': '^1.0.0', + chai: '^1.0.0', + }, + devDependencies: { + 'dev-dep': '^1.0.0', + }, + optionalDependencies: { + 'optional-dep': '^1.0.0', + }, + peerDependencies: { + 'peer-dep': '^2.0.0', // mismatching version # + }, + }), + ...diffDepTypesNmFixture, + }, }) await t.rejects(ls.exec([])) t.matchSnapshot( - redactCwd(result), + cleanCwd(result()), 'should output parseable signaling missing peer dep in problems' ) }) t.test('unmet optional dep', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'prod-dep': '^1.0.0', - chai: '^1.0.0', - }, - devDependencies: { - 'dev-dep': '^1.0.0', - }, - optionalDependencies: { - 'missing-optional-dep': '^1.0.0', - 'optional-dep': '^2.0.0', // mismatching version # - }, - peerDependencies: { - 'peer-dep': '^1.0.0', - }, - }), - ...diffDepTypesNmFixture, + const { result, ls } = await mockLs(t, { + config: { + ...parseable, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'prod-dep': '^1.0.0', + chai: '^1.0.0', + }, + devDependencies: { + 'dev-dep': '^1.0.0', + }, + optionalDependencies: { + 'missing-optional-dep': '^1.0.0', + 'optional-dep': '^2.0.0', // mismatching version # + }, + peerDependencies: { + 'peer-dep': '^1.0.0', + }, + }), + ...diffDepTypesNmFixture, + }, }) await t.rejects( ls.exec([]), @@ -2211,326 +2360,340 @@ t.test('ls --parseable', t => { 'should have invalid dep error msg' ) t.matchSnapshot( - redactCwd(result), + cleanCwd(result()), 'should output parseable with empty entry for missing optional deps' ) }) t.test('cycle deps', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - a: '^1.0.0', - }, - }), - node_modules: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - dependencies: { - b: '^1.0.0', - }, - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'b', - version: '1.0.0', - dependencies: { - a: '^1.0.0', - }, - }), + const { result, ls } = await mockLs(t, { + config: { + ...parseable, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + a: '^1.0.0', + }, + }), + node_modules: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + dependencies: { + b: '^1.0.0', + }, + }), + }, + b: { + 'package.json': JSON.stringify({ + name: 'b', + version: '1.0.0', + dependencies: { + a: '^1.0.0', + }, + }), + }, }, }, }) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should print tree output omitting deduped ref') + t.matchSnapshot(cleanCwd(result()), 'should print tree output omitting deduped ref') }) t.test('using aliases', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - a: 'npm:b@1.0.0', - }, - }), - node_modules: { - '.package-lock.json': JSON.stringify({ - packages: { - 'node_modules/a': { - name: 'b', - version: '1.0.0', - resolved: 'https://localhost:8080/abbrev/-/abbrev-1.1.1.tgz', - }, + const { npm, result, ls } = await mockLs(t, { + config: { + ...parseable, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + a: 'npm:b@1.0.0', }, }), - 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', + node_modules: { + '.package-lock.json': JSON.stringify({ + packages: { + 'node_modules/a': { + name: 'b', + version: '1.0.0', + resolved: 'https://localhost:8080/abbrev/-/abbrev-1.1.1.tgz', + }, }, }), + 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', + }, + }), + }, }, }, }) touchHiddenPackageLock(npm.prefix) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should output tree containing aliases') + t.matchSnapshot(cleanCwd(result()), 'should output tree containing aliases') }) t.test('resolved points to git ref', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - abbrev: 'git+https://github.com/isaacs/abbrev-js.git', - }, - }), - node_modules: { - '.package-lock.json': JSON.stringify({ - packages: { - 'node_modules/abbrev': { - name: 'abbrev', - version: '1.1.1', - /* eslint-disable-next-line max-len */ - resolved: 'git+https://github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', - }, + const { npm, result, ls } = await mockLs(t, { + config: { + ...parseable, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + abbrev: 'git+https://github.com/isaacs/abbrev-js.git', }, }), - abbrev: { - 'package.json': JSON.stringify({ - name: 'abbrev', - version: '1.1.1', - _id: 'abbrev@1.1.1', - _from: 'git+https://github.com/isaacs/abbrev-js.git', - /* eslint-disable-next-line max-len */ - _resolved: 'git+https://github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', - _requested: { - type: 'git', - raw: 'git+https:github.com/isaacs/abbrev-js.git', - 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, + node_modules: { + '.package-lock.json': JSON.stringify({ + packages: { + 'node_modules/abbrev': { + name: 'abbrev', + version: '1.1.1', + /* eslint-disable-next-line max-len */ + resolved: 'git+https://github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', + }, }, }), + abbrev: { + 'package.json': JSON.stringify({ + name: 'abbrev', + version: '1.1.1', + _id: 'abbrev@1.1.1', + _from: 'git+https://github.com/isaacs/abbrev-js.git', + /* eslint-disable-next-line max-len */ + _resolved: 'git+https://github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', + _requested: { + type: 'git', + raw: 'git+https:github.com/isaacs/abbrev-js.git', + 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, + }, + }), + }, }, }, }) touchHiddenPackageLock(npm.prefix) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should output tree containing git refs') + t.matchSnapshot(cleanCwd(result()), 'should output tree containing git refs') }) t.test('from and resolved properties', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'simple-output': '^2.0.0', - }, - }), - node_modules: { - '.package-lock.json': JSON.stringify({ - packages: { - 'node_modules/simple-output': { - name: 'simple-output', - version: '2.1.1', - resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz', - shasum: '3c07708ec9ef3e3c985cf0ddd67df09ab8ec2abc', - }, + const { npm, result, ls } = await mockLs(t, { + config: { + ...parseable, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'simple-output': '^2.0.0', }, }), - 'simple-output': { - 'package.json': JSON.stringify({ - name: 'simple-output', - version: '2.1.1', - _from: 'simple-output', - _id: 'simple-output@2.1.1', - _resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz', - _requested: { - type: 'tag', - registry: true, - raw: 'simple-output', - name: 'simple-output', - escapedName: 'simple-output', - rawSpec: '', - saveSpec: null, - fetchSpec: 'latest', + node_modules: { + '.package-lock.json': JSON.stringify({ + packages: { + 'node_modules/simple-output': { + name: 'simple-output', + version: '2.1.1', + resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz', + shasum: '3c07708ec9ef3e3c985cf0ddd67df09ab8ec2abc', + }, }, - _requiredBy: ['#USER', '/'], - _shasum: '3c07708ec9ef3e3c985cf0ddd67df09ab8ec2abc', - _spec: 'simple-output', }), + 'simple-output': { + 'package.json': JSON.stringify({ + name: 'simple-output', + version: '2.1.1', + _from: 'simple-output', + _id: 'simple-output@2.1.1', + _resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz', + _requested: { + type: 'tag', + registry: true, + raw: 'simple-output', + name: 'simple-output', + escapedName: 'simple-output', + rawSpec: '', + saveSpec: null, + fetchSpec: 'latest', + }, + _requiredBy: ['#USER', '/'], + _shasum: '3c07708ec9ef3e3c985cf0ddd67df09ab8ec2abc', + _spec: 'simple-output', + }), + }, }, }, }) touchHiddenPackageLock(npm.prefix) await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should not be printed in tree output') + t.matchSnapshot(cleanCwd(result()), 'should not be printed in tree output') }) t.test('global', async t => { - config.global = true - const fixtures = t.testdir({ - node_modules: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'b', - version: '1.0.0', - }), - node_modules: { - c: { - 'package.json': JSON.stringify({ - name: 'c', - version: '1.0.0', - }), + const { result, ls } = await mockLs(t, { + config: { ...parseable, global: true }, + globalPrefixDir: { + node_modules: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + }), + }, + b: { + 'package.json': JSON.stringify({ + name: 'b', + version: '1.0.0', + }), + node_modules: { + c: { + 'package.json': JSON.stringify({ + name: 'c', + version: '1.0.0', + }), + }, }, }, }, }, }) - // mimics lib/npm.js globalDir getter but pointing to fixtures - npm.globalDir = resolve(fixtures, 'node_modules') - await ls.exec([]) - t.matchSnapshot(redactCwd(result), 'should print parseable output for global deps') - npm.globalDir = 'MISSING_GLOBAL_DIR' - config.global = false + t.matchSnapshot(cleanCwd(result()), 'should print parseable output for global deps') }) - - t.end() }) t.test('ignore missing optional deps', async t => { - t.beforeEach(cleanUpResult) - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls-ignore-missing-optional', - version: '1.2.3', - peerDependencies: { - 'peer-ok': '1', - 'peer-missing': '1', - 'peer-wrong': '1', - 'peer-optional-ok': '1', - 'peer-optional-missing': '1', - 'peer-optional-wrong': '1', - }, - peerDependenciesMeta: { - 'peer-optional-ok': { - optional: true, - }, - 'peer-optional-missing': { - optional: true, - }, - 'peer-optional-wrong': { - optional: true, + const mock = async (t, config = {}) => { + const { result, ls } = await mockLs(t, { + config: config, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls-ignore-missing-optional', + version: '1.2.3', + peerDependencies: { + 'peer-ok': '1', + 'peer-missing': '1', + 'peer-wrong': '1', + 'peer-optional-ok': '1', + 'peer-optional-missing': '1', + 'peer-optional-wrong': '1', + }, + peerDependenciesMeta: { + 'peer-optional-ok': { + optional: true, + }, + 'peer-optional-missing': { + optional: true, + }, + 'peer-optional-wrong': { + optional: true, + }, + }, + optionalDependencies: { + 'optional-ok': '1', + 'optional-missing': '1', + 'optional-wrong': '1', + }, + dependencies: { + 'prod-ok': '1', + 'prod-missing': '1', + 'prod-wrong': '1', + }, + }), + node_modules: { + 'prod-ok': { + 'package.json': JSON.stringify({ name: 'prod-ok', version: '1.2.3' }), + }, + 'prod-wrong': { + 'package.json': JSON.stringify({ name: 'prod-wrong', version: '3.2.1' }), + }, + 'optional-ok': { + 'package.json': JSON.stringify({ name: 'optional-ok', version: '1.2.3' }), + }, + 'optional-wrong': { + 'package.json': JSON.stringify({ name: 'optional-wrong', version: '3.2.1' }), + }, + 'peer-optional-ok': { + 'package.json': JSON.stringify({ name: 'peer-optional-ok', version: '1.2.3' }), + }, + 'peer-optional-wrong': { + 'package.json': JSON.stringify({ name: 'peer-optional-wrong', version: '3.2.1' }), + }, + 'peer-ok': { + 'package.json': JSON.stringify({ name: 'peer-ok', version: '1.2.3' }), + }, + 'peer-wrong': { + 'package.json': JSON.stringify({ name: 'peer-wrong', version: '3.2.1' }), + }, }, }, - optionalDependencies: { - 'optional-ok': '1', - 'optional-missing': '1', - 'optional-wrong': '1', - }, - dependencies: { - 'prod-ok': '1', - 'prod-missing': '1', - 'prod-wrong': '1', - }, - }), - node_modules: { - 'prod-ok': { - 'package.json': JSON.stringify({ name: 'prod-ok', version: '1.2.3' }), - }, - 'prod-wrong': { - 'package.json': JSON.stringify({ name: 'prod-wrong', version: '3.2.1' }), - }, - 'optional-ok': { - 'package.json': JSON.stringify({ name: 'optional-ok', version: '1.2.3' }), - }, - 'optional-wrong': { - 'package.json': JSON.stringify({ name: 'optional-wrong', version: '3.2.1' }), - }, - 'peer-optional-ok': { - 'package.json': JSON.stringify({ name: 'peer-optional-ok', version: '1.2.3' }), - }, - 'peer-optional-wrong': { - 'package.json': JSON.stringify({ name: 'peer-optional-wrong', version: '3.2.1' }), - }, - 'peer-ok': { - 'package.json': JSON.stringify({ name: 'peer-ok', version: '1.2.3' }), - }, - 'peer-wrong': { - 'package.json': JSON.stringify({ name: 'peer-wrong', version: '3.2.1' }), - }, - }, - }) + }) + + await t.rejects(ls.exec([]), { code: 'ELSPROBLEMS' }) - config.all = true - const prefix = npm.prefix.toLowerCase().replace(/\\/g, '/') - const cleanupPaths = str => str.toLowerCase().replace(/\\/g, '/').split(prefix).join('{project}') + return config.json ? jsonParse(result()).problems : cleanCwd(result()) + } t.test('--json', async t => { - config.json = true - config.parseable = false - await t.rejects(ls.exec([]), { code: 'ELSPROBLEMS' }) - result = JSON.parse(result) - const problems = result.problems.map(cleanupPaths) - t.matchSnapshot(problems, 'ls --json problems') + const result = await mock(t, { json: true }) + t.matchSnapshot(result, 'ls --json problems') }) t.test('--parseable', async t => { - config.json = false - config.parseable = true - await t.rejects(ls.exec([]), { code: 'ELSPROBLEMS' }) - t.matchSnapshot(cleanupPaths(result), 'ls --parseable result') + const result = await mock(t, { parseable: true }) + t.matchSnapshot(result, 'ls --parseable result') }) t.test('human output', async t => { - config.json = false - config.parseable = false - await t.rejects(ls.exec([]), { code: 'ELSPROBLEMS' }) - t.matchSnapshot(cleanupPaths(result), 'ls result') + const result = await mock(t) + t.matchSnapshot(result, 'ls result') }) }) -t.test('ls --json', t => { - t.beforeEach(cleanUpResult) - config.json = true - config.parseable = false +t.test('ls --json', async t => { + const json = { json: true } t.test('no args', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - }, - }), - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + config: { + ...json, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await ls.exec([]) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', @@ -2556,20 +2719,22 @@ t.test('ls --json', t => { }) t.test('missing package.json', async t => { - npm.prefix = t.testdir({ - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + config: { + ...json, + }, + prefixDir: { + ...simpleNmFixture, + }, }) await ls.exec([]) t.same( - jsonParse(result), + jsonParse(result()), { problems: [ - /* eslint-disable-next-line max-len */ - 'extraneous: chai@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-package.json/node_modules/chai', - /* eslint-disable-next-line max-len */ - 'extraneous: dog@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-package.json/node_modules/dog', - /* eslint-disable-next-line max-len */ - 'extraneous: foo@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-package.json/node_modules/foo', + 'extraneous: chai@1.0.0 {CWD}/prefix/node_modules/chai', + 'extraneous: dog@1.0.0 {CWD}/prefix/node_modules/dog', + 'extraneous: foo@1.0.0 {CWD}/prefix/node_modules/foo', ], dependencies: { dog: { @@ -2577,8 +2742,7 @@ t.test('ls --json', t => { extraneous: true, overridden: false, problems: [ - /* eslint-disable-next-line max-len */ - 'extraneous: dog@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-package.json/node_modules/dog', + 'extraneous: dog@1.0.0 {CWD}/prefix/node_modules/dog', ], }, foo: { @@ -2586,8 +2750,7 @@ t.test('ls --json', t => { extraneous: true, overridden: false, problems: [ - /* eslint-disable-next-line max-len */ - 'extraneous: foo@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-package.json/node_modules/foo', + 'extraneous: foo@1.0.0 {CWD}/prefix/node_modules/foo', ], dependencies: { dog: { @@ -2600,8 +2763,7 @@ t.test('ls --json', t => { extraneous: true, overridden: false, problems: [ - /* eslint-disable-next-line max-len */ - 'extraneous: chai@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-package.json/node_modules/chai', + 'extraneous: chai@1.0.0 {CWD}/prefix/node_modules/chai', ], }, }, @@ -2611,24 +2773,29 @@ t.test('ls --json', t => { }) t.test('extraneous deps', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - }, - }), - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + config: { + ...json, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await ls.exec([]) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', problems: [ - 'extraneous: chai@1.0.0 {CWD}/tap-testdir-ls-ls---json-extraneous-deps/node_modules/chai', + 'extraneous: chai@1.0.0 {CWD}/prefix/node_modules/chai', ], dependencies: { foo: { @@ -2646,8 +2813,7 @@ t.test('ls --json', t => { extraneous: true, overridden: false, problems: [ - /* eslint-disable-next-line max-len */ - 'extraneous: chai@1.0.0 {CWD}/tap-testdir-ls-ls---json-extraneous-deps/node_modules/chai', + 'extraneous: chai@1.0.0 {CWD}/prefix/node_modules/chai', ], }, }, @@ -2657,40 +2823,43 @@ t.test('ls --json', t => { }) t.test('overridden dep', async t => { - config.all = true - t.teardown(() => config.all = false) - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-overridden', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - }, - overrides: { - bar: '1.0.0', - }, - }), - node_modules: { - foo: { - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.0.0', - dependencies: { - bar: '^2.0.0', - }, - }), - }, - bar: { - 'package.json': JSON.stringify({ - name: 'bar', - version: '1.0.0', - }), + const { result, ls } = await mockLs(t, { + config: { + ...json, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-overridden', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + }, + overrides: { + bar: '1.0.0', + }, + }), + node_modules: { + foo: { + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.0.0', + dependencies: { + bar: '^2.0.0', + }, + }), + }, + bar: { + 'package.json': JSON.stringify({ + name: 'bar', + version: '1.0.0', + }), + }, }, }, }) await ls.exec([]) - t.same(JSON.parse(result), { + t.same(JSON.parse(result()), { name: 'test-overridden', version: '1.0.0', dependencies: { @@ -2710,31 +2879,36 @@ t.test('ls --json', t => { t.test('missing deps --long', async t => { t.plan(3) - config.long = true - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - dog: '^1.0.0', - chai: '^1.0.0', - ipsum: '^1.0.0', - }, - }), - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + config: { + ...json, + long: true, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + dog: '^1.0.0', + chai: '^1.0.0', + ipsum: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await ls.exec([]).catch(err => { t.equal( - redactCwd(err.message), + cleanCwd(err.message), 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0', 'should log missing dep as error' ) t.equal(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code') }) t.match( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', @@ -2742,24 +2916,28 @@ t.test('ls --json', t => { }, 'should output json containing problems info' ) - config.long = false }) t.test('with filter arg', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - }, - }), - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + config: { + ...json, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await ls.exec(['chai']) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', @@ -2770,26 +2948,31 @@ t.test('ls --json', t => { }, }, }, - 'should output json contaning only occurrences of filtered by package' - ) - t.not(process.exitCode, 1, 'should not exit with error code 1') - }) - - t.test('with filter arg nested dep', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - }, - }), - ...simpleNmFixture, + 'should output json contaning only occurrences of filtered by package' + ) + t.not(process.exitCode, 1, 'should not exit with error code 1') + }) + + t.test('with filter arg nested dep', async t => { + const { result, ls } = await mockLs(t, { + config: { + ...json, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await ls.exec(['dog']) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', @@ -2808,33 +2991,38 @@ t.test('ls --json', t => { }, 'should output json contaning only occurrences of filtered by package' ) - t.notOk(jsonParse(result).dependencies.chai) + t.notOk(jsonParse(result()).dependencies.chai) }) t.test('with multiple filter args', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - ipsum: '^1.0.0', - }, - }), - node_modules: { - ...simpleNmFixture.node_modules, - ipsum: { - 'package.json': JSON.stringify({ - name: 'ipsum', - version: '1.0.0', - }), + const { result, ls } = await mockLs(t, { + config: { + ...json, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', + ipsum: '^1.0.0', + }, + }), + node_modules: { + ...simpleNmFixture.node_modules, + ipsum: { + 'package.json': JSON.stringify({ + name: 'ipsum', + version: '1.0.0', + }), + }, }, }, }) await ls.exec(['dog@*', 'chai@1.0.0']) t.same( - jsonParse(result), + jsonParse(result()), { version: '1.0.0', name: 'test-npm-ls', @@ -2861,20 +3049,25 @@ t.test('ls --json', t => { }) t.test('with missing filter arg', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - }, - }), - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + config: { + ...json, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await ls.exec(['notadep']) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', @@ -2882,26 +3075,29 @@ t.test('ls --json', t => { 'should output json containing no dependencies info' ) t.equal(process.exitCode, 1, 'should exit with error code 1') - process.exitCode = 0 }) t.test('default --depth value should now be 0', async t => { - config.all = false - config.depth = undefined - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - }, - }), - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + config: { + ...json, + all: false, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await ls.exec([]) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', @@ -2918,27 +3114,30 @@ t.test('ls --json', t => { }, 'should output json containing only top-level dependencies' ) - config.all = true - config.depth = Infinity }) t.test('--depth=0', async t => { - config.all = false - config.depth = 0 - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - }, - }), - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + config: { + ...json, + all: false, + depth: 0, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await ls.exec([]) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', @@ -2955,27 +3154,30 @@ t.test('ls --json', t => { }, 'should output json containing only top-level dependencies' ) - config.all = true - config.depth = Infinity }) t.test('--depth=1', async t => { - config.all = false - config.depth = 1 - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - }, - }), - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + config: { + ...json, + all: false, + depth: 1, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await ls.exec([]) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', @@ -2998,33 +3200,34 @@ t.test('ls --json', t => { }, 'should output json containing top-level deps and their deps only' ) - config.all = true - config.depth = Infinity }) t.test('missing/invalid/extraneous', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^2.0.0', - ipsum: '^1.0.0', - }, - }), - ...simpleNmFixture, + const { result, ls } = await mockLs(t, { + config: { + ...json, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^2.0.0', + ipsum: '^1.0.0', + }, + }), + ...simpleNmFixture, + }, }) await t.rejects(ls.exec([]), { code: 'ELSPROBLEMS' }, 'should list dep problems') t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', problems: [ - /* eslint-disable-next-line max-len */ - 'extraneous: chai@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-invalid-extraneous/node_modules/chai', - /* eslint-disable-next-line max-len */ - 'invalid: foo@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-invalid-extraneous/node_modules/foo', + 'extraneous: chai@1.0.0 {CWD}/prefix/node_modules/chai', + 'invalid: foo@1.0.0 {CWD}/prefix/node_modules/foo', 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0', ], dependencies: { @@ -3033,8 +3236,7 @@ t.test('ls --json', t => { invalid: '"^2.0.0" from the root project', overridden: false, problems: [ - /* eslint-disable-next-line max-len */ - 'invalid: foo@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-invalid-extraneous/node_modules/foo', + 'invalid: foo@1.0.0 {CWD}/prefix/node_modules/foo', ], dependencies: { dog: { @@ -3048,8 +3250,7 @@ t.test('ls --json', t => { extraneous: true, overridden: false, problems: [ - /* eslint-disable-next-line max-len */ - 'extraneous: chai@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-invalid-extraneous/node_modules/chai', + 'extraneous: chai@1.0.0 {CWD}/prefix/node_modules/chai', ], }, ipsum: { @@ -3058,36 +3259,50 @@ t.test('ls --json', t => { problems: ['missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0'], }, }, + error: { + code: 'ELSPROBLEMS', + summary: [ + 'extraneous: chai@1.0.0 {CWD}/prefix/node_modules/chai', + 'invalid: foo@1.0.0 {CWD}/prefix/node_modules/foo', + 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0', + ].join('\n'), + detail: '', + }, }, 'should output json containing top-level deps and their deps only' ) }) t.test('--dev', async t => { - flatOptions.omit = ['prod', 'optional', 'peer'] - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'prod-dep': '^1.0.0', - chai: '^1.0.0', - }, - devDependencies: { - 'dev-dep': '^1.0.0', - }, - optionalDependencies: { - 'optional-dep': '^1.0.0', - }, - peerDependencies: { - 'peer-dep': '^1.0.0', - }, - }), - ...diffDepTypesNmFixture, + const { result, ls } = await mockLs(t, { + config: { + ...json, + omit: ['prod', 'optional', 'peer'], + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'prod-dep': '^1.0.0', + chai: '^1.0.0', + }, + devDependencies: { + 'dev-dep': '^1.0.0', + }, + optionalDependencies: { + 'optional-dep': '^1.0.0', + }, + peerDependencies: { + 'peer-dep': '^1.0.0', + }, + }), + ...diffDepTypesNmFixture, + }, }) await ls.exec([]) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', @@ -3112,44 +3327,48 @@ t.test('ls --json', t => { }, 'should output json containing dev deps' ) - flatOptions.omit = [] }) t.test('--link', async t => { - config.link = true - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'prod-dep': '^1.0.0', - chai: '^1.0.0', - 'linked-dep': '^1.0.0', - }, - devDependencies: { - 'dev-dep': '^1.0.0', - }, - optionalDependencies: { - 'optional-dep': '^1.0.0', - }, - peerDependencies: { - 'peer-dep': '^1.0.0', - }, - }), - 'linked-dep': { + const { result, ls } = await mockLs(t, { + config: { + ...json, + link: true, + }, + prefixDir: { 'package.json': JSON.stringify({ - name: 'linked-dep', + name: 'test-npm-ls', version: '1.0.0', + dependencies: { + 'prod-dep': '^1.0.0', + chai: '^1.0.0', + 'linked-dep': '^1.0.0', + }, + devDependencies: { + 'dev-dep': '^1.0.0', + }, + optionalDependencies: { + 'optional-dep': '^1.0.0', + }, + peerDependencies: { + 'peer-dep': '^1.0.0', + }, }), - }, - node_modules: { - 'linked-dep': t.fixture('symlink', '../linked-dep'), - ...diffDepTypesNmFixture.node_modules, + 'linked-dep': { + 'package.json': JSON.stringify({ + name: 'linked-dep', + version: '1.0.0', + }), + }, + node_modules: { + 'linked-dep': t.fixture('symlink', '../linked-dep'), + ...diffDepTypesNmFixture.node_modules, + }, }, }) await ls.exec([]) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', @@ -3163,34 +3382,38 @@ t.test('ls --json', t => { }, 'should output json containing linked deps' ) - config.link = false }) t.test('--production', async t => { - flatOptions.omit = ['dev', 'peer'] - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'prod-dep': '^1.0.0', - chai: '^1.0.0', - }, - devDependencies: { - 'dev-dep': '^1.0.0', - }, - optionalDependencies: { - 'optional-dep': '^1.0.0', - }, - peerDependencies: { - 'peer-dep': '^1.0.0', - }, - }), - ...diffDepTypesNmFixture, + const { result, ls } = await mockLs(t, { + config: { + ...json, + omit: ['dev', 'peer'], + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'prod-dep': '^1.0.0', + chai: '^1.0.0', + }, + devDependencies: { + 'dev-dep': '^1.0.0', + }, + optionalDependencies: { + 'optional-dep': '^1.0.0', + }, + peerDependencies: { + 'peer-dep': '^1.0.0', + }, + }), + ...diffDepTypesNmFixture, + }, }) await ls.exec([]) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', @@ -3217,118 +3440,122 @@ t.test('ls --json', t => { }, 'should output json containing production deps' ) - flatOptions.omit = [] }) t.test('from lockfile', async t => { - npm.prefix = t.testdir({ - node_modules: { - '@isaacs': { - 'dedupe-tests-a': { - 'package.json': JSON.stringify({ + const { result, ls } = await mockLs(t, { + config: { + ...json, + }, + prefixDir: { + node_modules: { + '@isaacs': { + 'dedupe-tests-a': { + 'package.json': JSON.stringify({ + name: '@isaacs/dedupe-tests-a', + version: '1.0.1', + }), + node_modules: { + '@isaacs': { + 'dedupe-tests-b': { + name: '@isaacs/dedupe-tests-b', + version: '1.0.0', + }, + }, + }, + }, + 'dedupe-tests-b': { + 'package.json': JSON.stringify({ + name: '@isaacs/dedupe-tests-b', + 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', + dependencies: { + '@isaacs/dedupe-tests-a': '1.0.1', + '@isaacs/dedupe-tests-b': '1||2', + }, + }, + 'node_modules/@isaacs/dedupe-tests-a': { name: '@isaacs/dedupe-tests-a', version: '1.0.1', - }), - node_modules: { - '@isaacs': { - 'dedupe-tests-b': { - name: '@isaacs/dedupe-tests-b', + /* eslint-disable-next-line max-len */ + resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz', + /* eslint-disable-next-line max-len */ + 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', + /* eslint-disable-next-line max-len */ + resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz', + /* eslint-disable-next-line max-len */ + integrity: 'sha512-3nmvzIb8QL8OXODzipwoV3U8h9OQD9g9RwOPuSBQqjqSg9JZR1CCFOWNsDUtOfmwY8HFUJV9EAZ124uhqVxq+w==', + }, + 'node_modules/@isaacs/dedupe-tests-b': { + name: '@isaacs/dedupe-tests-b', + version: '2.0.0', + /* eslint-disable-next-line max-len */ + resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz', + /* eslint-disable-next-line max-len */ + integrity: 'sha512-KTYkpRv9EzlmCg4Gsm/jpclWmRYFCXow8GZKJXjK08sIZBlElTZEa5Bw/UQxIvEfcKmWXczSqItD49Kr8Ax4UA==', + }, + }, + dependencies: { + '@isaacs/dedupe-tests-a': { + version: '1.0.1', + /* eslint-disable-next-line max-len */ + resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz', + /* eslint-disable-next-line max-len */ + integrity: 'sha512-8AN9lNCcBt5Xeje7fMEEpp5K3rgcAzIpTtAjYb/YMUYu8SbIVF6wz0WqACDVKvpQOUcSfNHZQNLNmue0QSwXOQ==', + requires: { + '@isaacs/dedupe-tests-b': '1', + }, + dependencies: { + '@isaacs/dedupe-tests-b': { version: '1.0.0', + /* eslint-disable-next-line max-len */ + resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz', + /* eslint-disable-next-line max-len */ + integrity: 'sha512-3nmvzIb8QL8OXODzipwoV3U8h9OQD9g9RwOPuSBQqjqSg9JZR1CCFOWNsDUtOfmwY8HFUJV9EAZ124uhqVxq+w==', }, }, }, - }, - 'dedupe-tests-b': { - 'package.json': JSON.stringify({ - name: '@isaacs/dedupe-tests-b', + '@isaacs/dedupe-tests-b': { 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', - dependencies: { - '@isaacs/dedupe-tests-a': '1.0.1', - '@isaacs/dedupe-tests-b': '1||2', - }, - }, - 'node_modules/@isaacs/dedupe-tests-a': { - name: '@isaacs/dedupe-tests-a', - version: '1.0.1', - /* eslint-disable-next-line max-len */ - resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz', - /* eslint-disable-next-line max-len */ - 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', - /* eslint-disable-next-line max-len */ - resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz', - /* eslint-disable-next-line max-len */ - integrity: 'sha512-3nmvzIb8QL8OXODzipwoV3U8h9OQD9g9RwOPuSBQqjqSg9JZR1CCFOWNsDUtOfmwY8HFUJV9EAZ124uhqVxq+w==', - }, - 'node_modules/@isaacs/dedupe-tests-b': { - name: '@isaacs/dedupe-tests-b', - version: '2.0.0', - /* eslint-disable-next-line max-len */ - resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz', - /* eslint-disable-next-line max-len */ - integrity: 'sha512-KTYkpRv9EzlmCg4Gsm/jpclWmRYFCXow8GZKJXjK08sIZBlElTZEa5Bw/UQxIvEfcKmWXczSqItD49Kr8Ax4UA==', - }, - }, - dependencies: { - '@isaacs/dedupe-tests-a': { - version: '1.0.1', - /* eslint-disable-next-line max-len */ - resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz', - /* eslint-disable-next-line max-len */ - integrity: 'sha512-8AN9lNCcBt5Xeje7fMEEpp5K3rgcAzIpTtAjYb/YMUYu8SbIVF6wz0WqACDVKvpQOUcSfNHZQNLNmue0QSwXOQ==', - requires: { - '@isaacs/dedupe-tests-b': '1', - }, - dependencies: { - '@isaacs/dedupe-tests-b': { - version: '1.0.0', - /* eslint-disable-next-line max-len */ - resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz', - /* eslint-disable-next-line max-len */ - integrity: 'sha512-3nmvzIb8QL8OXODzipwoV3U8h9OQD9g9RwOPuSBQqjqSg9JZR1CCFOWNsDUtOfmwY8HFUJV9EAZ124uhqVxq+w==', - }, + /* eslint-disable-next-line max-len */ + resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz', + /* eslint-disable-next-line max-len */ + integrity: 'sha512-KTYkpRv9EzlmCg4Gsm/jpclWmRYFCXow8GZKJXjK08sIZBlElTZEa5Bw/UQxIvEfcKmWXczSqItD49Kr8Ax4UA==', }, }, - '@isaacs/dedupe-tests-b': { - version: '2.0.0', - /* eslint-disable-next-line max-len */ - resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz', - /* eslint-disable-next-line max-len */ - integrity: 'sha512-KTYkpRv9EzlmCg4Gsm/jpclWmRYFCXow8GZKJXjK08sIZBlElTZEa5Bw/UQxIvEfcKmWXczSqItD49Kr8Ax4UA==', + }), + 'package.json': JSON.stringify({ + name: 'dedupe-lockfile', + version: '1.0.0', + dependencies: { + '@isaacs/dedupe-tests-a': '1.0.1', + '@isaacs/dedupe-tests-b': '1||2', }, - }, - }), - 'package.json': JSON.stringify({ - name: 'dedupe-lockfile', - version: '1.0.0', - dependencies: { - '@isaacs/dedupe-tests-a': '1.0.1', - '@isaacs/dedupe-tests-b': '1||2', - }, - }), + }), + }, }) await ls.exec([]) t.same( - jsonParse(result), + jsonParse(result()), { version: '1.0.0', name: 'dedupe-lockfile', @@ -3346,7 +3573,7 @@ t.test('ls --json', t => { overridden: false, problems: [ /* eslint-disable-next-line max-len */ - 'extraneous: @isaacs/dedupe-tests-b@ {CWD}/tap-testdir-ls-ls---json-from-lockfile/node_modules/@isaacs/dedupe-tests-a/node_modules/@isaacs/dedupe-tests-b', + 'extraneous: @isaacs/dedupe-tests-b@ {CWD}/prefix/node_modules/@isaacs/dedupe-tests-a/node_modules/@isaacs/dedupe-tests-b', ], }, }, @@ -3360,7 +3587,7 @@ t.test('ls --json', t => { }, problems: [ /* eslint-disable-next-line max-len */ - 'extraneous: @isaacs/dedupe-tests-b@ {CWD}/tap-testdir-ls-ls---json-from-lockfile/node_modules/@isaacs/dedupe-tests-a/node_modules/@isaacs/dedupe-tests-b', + 'extraneous: @isaacs/dedupe-tests-b@ {CWD}/prefix/node_modules/@isaacs/dedupe-tests-a/node_modules/@isaacs/dedupe-tests-b', ], }, 'should output json containing only prod deps' @@ -3368,30 +3595,35 @@ t.test('ls --json', t => { }) t.test('--long', async t => { - config.long = true - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'prod-dep': '^1.0.0', - chai: '^1.0.0', - }, - devDependencies: { - 'dev-dep': '^1.0.0', - }, - optionalDependencies: { - 'optional-dep': '^1.0.0', - }, - peerDependencies: { - 'peer-dep': '^1.0.0', - }, - }), - ...diffDepTypesNmFixture, + const { result, ls } = await mockLs(t, { + config: { + ...json, + long: true, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'prod-dep': '^1.0.0', + chai: '^1.0.0', + }, + devDependencies: { + 'dev-dep': '^1.0.0', + }, + optionalDependencies: { + 'optional-dep': '^1.0.0', + }, + peerDependencies: { + 'peer-dep': '^1.0.0', + }, + }), + ...diffDepTypesNmFixture, + }, }) await ls.exec([]) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', @@ -3405,7 +3637,7 @@ t.test('ls --json', t => { devDependencies: {}, peerDependencies: {}, _dependencies: {}, - path: '{CWD}/tap-testdir-ls-ls---json---long/node_modules/peer-dep', + path: '{CWD}/prefix/node_modules/peer-dep', extraneous: false, }, 'dev-dep': { @@ -3427,7 +3659,7 @@ t.test('ls --json', t => { devDependencies: {}, peerDependencies: {}, _dependencies: {}, - path: '{CWD}/tap-testdir-ls-ls---json---long/node_modules/dog', + path: '{CWD}/prefix/node_modules/dog', extraneous: false, }, }, @@ -3435,7 +3667,7 @@ t.test('ls --json', t => { devDependencies: {}, peerDependencies: {}, _dependencies: { dog: '^1.0.0' }, - path: '{CWD}/tap-testdir-ls-ls---json---long/node_modules/foo', + path: '{CWD}/prefix/node_modules/foo', extraneous: false, }, }, @@ -3443,7 +3675,7 @@ t.test('ls --json', t => { devDependencies: {}, peerDependencies: {}, _dependencies: { foo: '^1.0.0' }, - path: '{CWD}/tap-testdir-ls-ls---json---long/node_modules/dev-dep', + path: '{CWD}/prefix/node_modules/dev-dep', extraneous: false, }, chai: { @@ -3454,7 +3686,7 @@ t.test('ls --json', t => { devDependencies: {}, peerDependencies: {}, _dependencies: {}, - path: '{CWD}/tap-testdir-ls-ls---json---long/node_modules/chai', + path: '{CWD}/prefix/node_modules/chai', extraneous: false, }, 'optional-dep': { @@ -3466,7 +3698,7 @@ t.test('ls --json', t => { devDependencies: {}, peerDependencies: {}, _dependencies: {}, - path: '{CWD}/tap-testdir-ls-ls---json---long/node_modules/optional-dep', + path: '{CWD}/prefix/node_modules/optional-dep', extraneous: false, }, 'prod-dep': { @@ -3484,8 +3716,7 @@ t.test('ls --json', t => { devDependencies: {}, peerDependencies: {}, _dependencies: {}, - /* eslint-disable-next-line max-len */ - path: '{CWD}/tap-testdir-ls-ls---json---long/node_modules/prod-dep/node_modules/dog', + path: '{CWD}/prefix/node_modules/prod-dep/node_modules/dog', extraneous: false, }, }, @@ -3493,7 +3724,7 @@ t.test('ls --json', t => { devDependencies: {}, peerDependencies: {}, _dependencies: { dog: '^2.0.0' }, - path: '{CWD}/tap-testdir-ls-ls---json---long/node_modules/prod-dep', + path: '{CWD}/prefix/node_modules/prod-dep', extraneous: false, }, }, @@ -3502,41 +3733,45 @@ t.test('ls --json', t => { peerDependencies: { 'peer-dep': '^1.0.0' }, _id: 'test-npm-ls@1.0.0', _dependencies: { 'prod-dep': '^1.0.0', chai: '^1.0.0', 'optional-dep': '^1.0.0' }, - path: '{CWD}/tap-testdir-ls-ls---json---long', + path: '{CWD}/prefix', extraneous: false, }, 'should output long json info' ) - config.long = true }) t.test('--long --depth=0', async t => { - config.all = false - config.depth = 0 - config.long = true - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'prod-dep': '^1.0.0', - chai: '^1.0.0', - }, - devDependencies: { - 'dev-dep': '^1.0.0', - }, - optionalDependencies: { - 'optional-dep': '^1.0.0', - }, - peerDependencies: { - 'peer-dep': '^1.0.0', - }, - }), - ...diffDepTypesNmFixture, + const { result, ls } = await mockLs(t, { + config: { + ...json, + all: false, + depth: 0, + long: true, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'prod-dep': '^1.0.0', + chai: '^1.0.0', + }, + devDependencies: { + 'dev-dep': '^1.0.0', + }, + optionalDependencies: { + 'optional-dep': '^1.0.0', + }, + peerDependencies: { + 'peer-dep': '^1.0.0', + }, + }), + ...diffDepTypesNmFixture, + }, }) await ls.exec([]) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', @@ -3550,7 +3785,7 @@ t.test('ls --json', t => { devDependencies: {}, peerDependencies: {}, _dependencies: {}, - path: '{CWD}/tap-testdir-ls-ls---json---long---depth-0/node_modules/peer-dep', + path: '{CWD}/prefix/node_modules/peer-dep', extraneous: false, }, 'dev-dep': { @@ -3562,7 +3797,7 @@ t.test('ls --json', t => { devDependencies: {}, peerDependencies: {}, _dependencies: { foo: '^1.0.0' }, - path: '{CWD}/tap-testdir-ls-ls---json---long---depth-0/node_modules/dev-dep', + path: '{CWD}/prefix/node_modules/dev-dep', extraneous: false, }, chai: { @@ -3573,7 +3808,7 @@ t.test('ls --json', t => { devDependencies: {}, peerDependencies: {}, _dependencies: {}, - path: '{CWD}/tap-testdir-ls-ls---json---long---depth-0/node_modules/chai', + path: '{CWD}/prefix/node_modules/chai', extraneous: false, }, 'optional-dep': { @@ -3585,7 +3820,7 @@ t.test('ls --json', t => { devDependencies: {}, peerDependencies: {}, _dependencies: {}, - path: '{CWD}/tap-testdir-ls-ls---json---long---depth-0/node_modules/optional-dep', + path: '{CWD}/prefix/node_modules/optional-dep', extraneous: false, }, 'prod-dep': { @@ -3597,7 +3832,7 @@ t.test('ls --json', t => { devDependencies: {}, peerDependencies: {}, _dependencies: { dog: '^2.0.0' }, - path: '{CWD}/tap-testdir-ls-ls---json---long---depth-0/node_modules/prod-dep', + path: '{CWD}/prefix/node_modules/prod-dep', extraneous: false, }, }, @@ -3606,19 +3841,21 @@ t.test('ls --json', t => { peerDependencies: { 'peer-dep': '^1.0.0' }, _id: 'test-npm-ls@1.0.0', _dependencies: { 'prod-dep': '^1.0.0', chai: '^1.0.0', 'optional-dep': '^1.0.0' }, - path: '{CWD}/tap-testdir-ls-ls---json---long---depth-0', + path: '{CWD}/prefix', extraneous: false, }, 'should output json containing top-level deps in long format' ) - config.all = true - config.depth = Infinity - config.long = false }) t.test('json read problems', async t => { - npm.prefix = t.testdir({ - 'package.json': '{broken json', + const { result, ls } = await mockLs(t, { + config: { + ...json, + }, + prefixDir: { + 'package.json': '{broken json', + }, }) await t.rejects( ls.exec([]), @@ -3626,54 +3863,65 @@ t.test('ls --json', t => { 'should have missin root package.json msg' ) t.same( - jsonParse(result), + jsonParse(result()), { invalid: true, problems: [ - /* eslint-disable-next-line max-len */ - 'error in {CWD}/tap-testdir-ls-ls---json-json-read-problems: Failed to parse root package.json', + 'error in {CWD}/prefix: Failed to parse root package.json', ], + error: { + code: 'EJSONPARSE', + summary: 'Failed to parse root package.json', + detail: [ + 'Failed to parse JSON data.', + 'Note: package.json must be actual JSON, not just JavaScript.', + ].join('\n'), + }, }, 'should print empty json result' ) }) t.test('empty location', async t => { - npm.prefix = t.testdir({}) + const { ls, result } = await mockLs(t, { config: json }) await ls.exec([]) - t.same(jsonParse(result), {}, 'should print empty json result') + t.same(jsonParse(result()), {}, 'should print empty json result') }) t.test('unmet peer dep', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'prod-dep': '^1.0.0', - chai: '^1.0.0', - }, - devDependencies: { - 'dev-dep': '^1.0.0', - }, - optionalDependencies: { - 'optional-dep': '^1.0.0', - }, - peerDependencies: { - 'peer-dep': '^2.0.0', // mismatching version # - }, - }), - ...diffDepTypesNmFixture, + const { result, ls } = await mockLs(t, { + config: { + ...json, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'prod-dep': '^1.0.0', + chai: '^1.0.0', + }, + devDependencies: { + 'dev-dep': '^1.0.0', + }, + optionalDependencies: { + 'optional-dep': '^1.0.0', + }, + peerDependencies: { + 'peer-dep': '^2.0.0', // mismatching version # + }, + }), + ...diffDepTypesNmFixture, + }, }) await t.rejects(ls.exec([]), { code: 'ELSPROBLEMS' }, 'Should have ELSPROBLEMS error code') t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', problems: [ - /* eslint-disable-next-line max-len */ - 'invalid: peer-dep@1.0.0 {CWD}/tap-testdir-ls-ls---json-unmet-peer-dep/node_modules/peer-dep', + 'invalid: peer-dep@1.0.0 {CWD}/prefix/node_modules/peer-dep', ], dependencies: { 'peer-dep': { @@ -3681,8 +3929,7 @@ t.test('ls --json', t => { invalid: '"^2.0.0" from the root project', overridden: false, problems: [ - /* eslint-disable-next-line max-len */ - 'invalid: peer-dep@1.0.0 {CWD}/tap-testdir-ls-ls---json-unmet-peer-dep/node_modules/peer-dep', + 'invalid: peer-dep@1.0.0 {CWD}/prefix/node_modules/peer-dep', ], }, 'dev-dep': { @@ -3720,32 +3967,42 @@ t.test('ls --json', t => { }, }, }, + error: { + code: 'ELSPROBLEMS', + summary: 'invalid: peer-dep@1.0.0 {CWD}/prefix/node_modules/peer-dep', + detail: '', + }, }, 'should output json signaling missing peer dep in problems' ) }) t.test('unmet optional dep', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'prod-dep': '^1.0.0', - chai: '^1.0.0', - }, - devDependencies: { - 'dev-dep': '^1.0.0', - }, - optionalDependencies: { - 'missing-optional-dep': '^1.0.0', - 'optional-dep': '^2.0.0', // mismatching version # - }, - peerDependencies: { - 'peer-dep': '^1.0.0', - }, - }), - ...diffDepTypesNmFixture, + const { result, ls } = await mockLs(t, { + config: { + ...json, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'prod-dep': '^1.0.0', + chai: '^1.0.0', + }, + devDependencies: { + 'dev-dep': '^1.0.0', + }, + optionalDependencies: { + 'missing-optional-dep': '^1.0.0', + 'optional-dep': '^2.0.0', // mismatching version # + }, + peerDependencies: { + 'peer-dep': '^1.0.0', + }, + }), + ...diffDepTypesNmFixture, + }, }) await t.rejects( ls.exec([]), @@ -3753,13 +4010,13 @@ t.test('ls --json', t => { 'should have invalid dep error msg' ) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', problems: [ - /* eslint-disable-next-line max-len */ - 'invalid: optional-dep@1.0.0 {CWD}/tap-testdir-ls-ls---json-unmet-optional-dep/node_modules/optional-dep', // mismatching optional deps get flagged in problems + // mismatching optional deps get flagged in problems + 'invalid: optional-dep@1.0.0 {CWD}/prefix/node_modules/optional-dep', ], dependencies: { 'optional-dep': { @@ -3767,8 +4024,7 @@ t.test('ls --json', t => { invalid: '"^2.0.0" from the root project', overridden: false, problems: [ - /* eslint-disable-next-line max-len */ - 'invalid: optional-dep@1.0.0 {CWD}/tap-testdir-ls-ls---json-unmet-optional-dep/node_modules/optional-dep', + 'invalid: optional-dep@1.0.0 {CWD}/prefix/node_modules/optional-dep', ], }, 'peer-dep': { @@ -3807,44 +4063,54 @@ t.test('ls --json', t => { }, 'missing-optional-dep': {}, // missing optional dep has an empty entry in json output }, + error: { + code: 'ELSPROBLEMS', + summary: 'invalid: optional-dep@1.0.0 {CWD}/prefix/node_modules/optional-dep', + detail: '', + }, }, 'should output json with empty entry for missing optional deps' ) }) t.test('cycle deps', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - a: '^1.0.0', - }, - }), - node_modules: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - dependencies: { - b: '^1.0.0', - }, - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'b', - version: '1.0.0', - dependencies: { - a: '^1.0.0', - }, - }), + const { result, ls } = await mockLs(t, { + config: { + ...json, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + a: '^1.0.0', + }, + }), + node_modules: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + dependencies: { + b: '^1.0.0', + }, + }), + }, + b: { + 'package.json': JSON.stringify({ + name: 'b', + version: '1.0.0', + dependencies: { + a: '^1.0.0', + }, + }), + }, }, }, }) await ls.exec([]) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', @@ -3871,40 +4137,45 @@ t.test('ls --json', t => { }) t.test('using aliases', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - a: 'npm:b@1.0.0', - }, - }), - node_modules: { - '.package-lock.json': JSON.stringify({ - packages: { - 'node_modules/a': { - name: 'b', - version: '1.0.0', - from: 'a@npm:b', - resolved: 'https://localhost:8080/abbrev/-/abbrev-1.1.1.tgz', - requested: { - type: 'alias', - }, - }, + const { npm, result, ls } = await mockLs(t, { + config: { + ...json, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + a: 'npm:b@1.0.0', }, }), - a: { - 'package.json': JSON.stringify({ - name: 'b', - version: '1.0.0', + node_modules: { + '.package-lock.json': JSON.stringify({ + packages: { + 'node_modules/a': { + name: 'b', + version: '1.0.0', + from: 'a@npm:b', + resolved: 'https://localhost:8080/abbrev/-/abbrev-1.1.1.tgz', + requested: { + type: 'alias', + }, + }, + }, }), + a: { + 'package.json': JSON.stringify({ + name: 'b', + version: '1.0.0', + }), + }, }, }, }) touchHiddenPackageLock(npm.prefix) await ls.exec([]) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', @@ -3921,51 +4192,56 @@ t.test('ls --json', t => { }) t.test('resolved points to git ref', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - abbrev: 'git+https://github.com/isaacs/abbrev-js.git', - }, - }), - node_modules: { - '.package-lock.json': JSON.stringify({ - packages: { - 'node_modules/abbrev': { - name: 'abbrev', - version: '1.1.1', - id: 'abbrev@1.1.1', - from: 'git+https://github.com/isaacs/abbrev-js.git', - /* eslint-disable-next-line max-len */ - resolved: 'git+https://github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', - }, + const { npm, result, ls } = await mockLs(t, { + config: { + ...json, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + abbrev: 'git+https://github.com/isaacs/abbrev-js.git', }, }), - abbrev: { - 'package.json': JSON.stringify({ - name: 'abbrev', - version: '1.1.1', - _id: 'abbrev@1.1.1', - _from: 'git+https://github.com/isaacs/abbrev-js.git', - /* eslint-disable-next-line max-len */ - _resolved: 'git+https://github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', - _requested: { - type: 'git', - raw: 'git+https:github.com/isaacs/abbrev-js.git', - 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, + node_modules: { + '.package-lock.json': JSON.stringify({ + packages: { + 'node_modules/abbrev': { + name: 'abbrev', + version: '1.1.1', + id: 'abbrev@1.1.1', + from: 'git+https://github.com/isaacs/abbrev-js.git', + /* eslint-disable-next-line max-len */ + resolved: 'git+https://github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', + }, }, }), + abbrev: { + 'package.json': JSON.stringify({ + name: 'abbrev', + version: '1.1.1', + _id: 'abbrev@1.1.1', + _from: 'git+https://github.com/isaacs/abbrev-js.git', + /* eslint-disable-next-line max-len */ + _resolved: 'git+https://github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', + _requested: { + type: 'git', + raw: 'git+https:github.com/isaacs/abbrev-js.git', + 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, + }, + }), + }, }, }, }) touchHiddenPackageLock(npm.prefix) await ls.exec([]) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', @@ -3983,18 +4259,45 @@ t.test('ls --json', t => { }) t.test('from and resolved properties', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'simple-output': '^2.0.0', - }, - }), - node_modules: { - '.package-lock.json': JSON.stringify({ - packages: { - 'node_modules/simple-output': { + const { npm, result, ls } = await mockLs(t, { + config: { + ...json, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'simple-output': '^2.0.0', + }, + }), + node_modules: { + '.package-lock.json': JSON.stringify({ + packages: { + 'node_modules/simple-output': { + name: 'simple-output', + version: '2.1.1', + _from: 'simple-output', + _id: 'simple-output@2.1.1', + _resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz', + _requested: { + type: 'tag', + registry: true, + raw: 'simple-output', + name: 'simple-output', + escapedName: 'simple-output', + rawSpec: '', + saveSpec: null, + fetchSpec: 'latest', + }, + _requiredBy: ['#USER', '/'], + _shasum: '3c07708ec9ef3e3c985cf0ddd67df09ab8ec2abc', + _spec: 'simple-output', + }, + }, + }), + 'simple-output': { + 'package.json': JSON.stringify({ name: 'simple-output', version: '2.1.1', _from: 'simple-output', @@ -4013,37 +4316,15 @@ t.test('ls --json', t => { _requiredBy: ['#USER', '/'], _shasum: '3c07708ec9ef3e3c985cf0ddd67df09ab8ec2abc', _spec: 'simple-output', - }, + }), }, - }), - 'simple-output': { - 'package.json': JSON.stringify({ - name: 'simple-output', - version: '2.1.1', - _from: 'simple-output', - _id: 'simple-output@2.1.1', - _resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz', - _requested: { - type: 'tag', - registry: true, - raw: 'simple-output', - name: 'simple-output', - escapedName: 'simple-output', - rawSpec: '', - saveSpec: null, - fetchSpec: 'latest', - }, - _requiredBy: ['#USER', '/'], - _shasum: '3c07708ec9ef3e3c985cf0ddd67df09ab8ec2abc', - _spec: 'simple-output', - }), }, }, }) touchHiddenPackageLock(npm.prefix) await ls.exec([]) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', @@ -4060,57 +4341,64 @@ t.test('ls --json', t => { }) t.test('node.name fallback if missing root package name', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - version: '1.0.0', - }), + const { result, ls } = await mockLs(t, { + config: { + ...json, + }, + prefixDir: { + 'package.json': JSON.stringify({ + version: '1.0.0', + }), + }, }) await ls.exec([]) t.same( - jsonParse(result), + jsonParse(result()), { version: '1.0.0', - name: 'tap-testdir-ls-ls---json-node.name-fallback-if-missing-root-package-name', + name: 'prefix', }, 'should use node.name as key in json result obj' ) }) t.test('global', async t => { - config.global = true - const fixtures = t.testdir({ - node_modules: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'b', - version: '1.0.0', - }), - node_modules: { - c: { - 'package.json': JSON.stringify({ - name: 'c', - version: '1.0.0', - }), + const { result, ls } = await mockLs(t, { + config: { + ...json, + global: true, + }, + globalPrefixDir: { + node_modules: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + }), + }, + b: { + 'package.json': JSON.stringify({ + name: 'b', + version: '1.0.0', + }), + node_modules: { + c: { + 'package.json': JSON.stringify({ + name: 'c', + version: '1.0.0', + }), + }, }, }, }, }, }) - // mimics lib/npm.js globalDir getter but pointing to fixtures - npm.globalDir = resolve(fixtures, 'node_modules') - await ls.exec([]) t.same( - jsonParse(result), + jsonParse(result()), { - name: 'tap-testdir-ls-ls---json-global', + name: process.platform === 'win32' ? 'global' : 'lib', dependencies: { a: { version: '1.0.0', @@ -4130,98 +4418,99 @@ t.test('ls --json', t => { }, 'should print json output for global deps' ) - npm.globalDir = 'MISSING_GLOBAL_DIR' - config.global = false }) - - t.end() }) t.test('show multiple invalid reasons', async t => { - config.json = false - config.all = true - config.depth = Infinity - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - cat: '^2.0.0', - dog: '^1.2.3', - }, - }), - node_modules: { - cat: { - 'package.json': JSON.stringify({ - name: 'cat', - version: '1.0.0', - dependencies: { - dog: '^2.0.0', - }, - }), - }, - dog: { - 'package.json': JSON.stringify({ - name: 'dog', - version: '1.0.0', - dependencies: { - cat: '', - }, - }), - }, - chai: { - 'package.json': JSON.stringify({ - name: 'chai', - version: '1.0.0', - dependencies: { - dog: '2.x', - }, - }), + const { result, ls } = await mockLs(t, { + config: {}, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + cat: '^2.0.0', + dog: '^1.2.3', + }, + }), + node_modules: { + cat: { + 'package.json': JSON.stringify({ + name: 'cat', + version: '1.0.0', + dependencies: { + dog: '^2.0.0', + }, + }), + }, + dog: { + 'package.json': JSON.stringify({ + name: 'dog', + version: '1.0.0', + dependencies: { + cat: '', + }, + }), + }, + chai: { + 'package.json': JSON.stringify({ + name: 'chai', + version: '1.0.0', + dependencies: { + dog: '2.x', + }, + }), + }, }, }, }) - const cleanupPaths = str => redactCwd(str).toLowerCase().replace(/\\/g, '/') await t.rejects(ls.exec([]), { code: 'ELSPROBLEMS' }, 'should list dep problems') - t.matchSnapshot(cleanupPaths(result), 'ls result') + t.matchSnapshot(cleanCwd(result()), 'ls result') }) -t.test('ls --package-lock-only', t => { - config['package-lock-only'] = true - t.test('ls --package-lock-only --json', t => { - t.beforeEach(cleanUpResult) - config.json = true - config.parseable = false +t.test('ls --package-lock-only', async t => { + const lock = { 'package-lock-only': true } + + t.test('ls --package-lock-only --json', async t => { + const json = { json: true } + t.test('no args', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - }, - }), - 'package-lock.json': JSON.stringify({ - dependencies: { - foo: { - version: '1.0.0', - requires: { - dog: '^1.0.0', - }, - }, - dog: { - version: '1.0.0', + const { result, ls } = await mockLs(t, { + config: { + ...lock, + ...json, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', }, - chai: { - version: '1.0.0', + }), + 'package-lock.json': JSON.stringify({ + dependencies: { + foo: { + version: '1.0.0', + requires: { + dog: '^1.0.0', + }, + }, + dog: { + version: '1.0.0', + }, + chai: { + version: '1.0.0', + }, }, - }, - }), + }), + }, }) await ls.exec([]) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', @@ -4247,34 +4536,40 @@ t.test('ls --package-lock-only', t => { }) t.test('extraneous deps', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - }, - }), - 'package-lock.json': JSON.stringify({ - dependencies: { - foo: { - version: '1.0.0', - requires: { - dog: '^1.0.0', - }, - }, - dog: { - version: '1.0.0', + const { result, ls } = await mockLs(t, { + config: { + ...lock, + ...json, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', }, - chai: { - version: '1.0.0', + }), + 'package-lock.json': JSON.stringify({ + dependencies: { + foo: { + version: '1.0.0', + requires: { + dog: '^1.0.0', + }, + }, + dog: { + version: '1.0.0', + }, + chai: { + version: '1.0.0', + }, }, - }, - }), + }), + }, }) await ls.exec([]) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', @@ -4289,90 +4584,101 @@ t.test('ls --package-lock-only', t => { }, }, }, - }, - }, - 'should output json containing no problem info' - ) - }) - - t.test('missing deps --long', async t => { - config.long = true - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - dog: '^1.0.0', - chai: '^1.0.0', - ipsum: '^1.0.0', - }, - }), - 'package-lock.json': JSON.stringify({ - dependencies: { - foo: { - version: '1.0.0', - requires: { - dog: '^1.0.0', - }, - }, - dog: { - version: '1.0.0', - }, - chai: { - version: '1.0.0', + }, + }, + 'should output json containing no problem info' + ) + }) + + t.test('missing deps --long', async t => { + const { result, ls } = await mockLs(t, { + config: { + ...lock, + ...json, + long: true, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + dog: '^1.0.0', + chai: '^1.0.0', + ipsum: '^1.0.0', }, - ipsum: { - version: '1.0.0', + }), + 'package-lock.json': JSON.stringify({ + dependencies: { + foo: { + version: '1.0.0', + requires: { + dog: '^1.0.0', + }, + }, + dog: { + version: '1.0.0', + }, + chai: { + version: '1.0.0', + }, + ipsum: { + version: '1.0.0', + }, }, - }, - }), + }), + }, }) await ls.exec([]) t.match( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', }, 'should output json containing no problems info' ) - config.long = false }) t.test('with filter arg', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - }, - }), - 'package-lock.json': JSON.stringify({ - dependencies: { - foo: { - version: '1.0.0', - requires: { - dog: '^1.0.0', - }, - }, - dog: { - version: '1.0.0', - }, - chai: { - version: '1.0.0', + const { result, ls } = await mockLs(t, { + config: { + ...lock, + ...json, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', }, - ipsum: { - version: '1.0.0', + }), + 'package-lock.json': JSON.stringify({ + dependencies: { + foo: { + version: '1.0.0', + requires: { + dog: '^1.0.0', + }, + }, + dog: { + version: '1.0.0', + }, + chai: { + version: '1.0.0', + }, + ipsum: { + version: '1.0.0', + }, }, - }, - }), + }), + }, }) await ls.exec(['chai']) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', @@ -4385,42 +4691,48 @@ t.test('ls --package-lock-only', t => { }, 'should output json contaning only occurrences of filtered by package' ) - t.equal(process.exitCode, 0, 'should exit with error code 0') + t.notOk(process.exitCode, 'should not set exit code') }) t.test('with filter arg nested dep', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - }, - }), - 'package-lock.json': JSON.stringify({ - dependencies: { - foo: { - version: '1.0.0', - requires: { - dog: '^1.0.0', - }, - }, - dog: { - version: '1.0.0', - }, - chai: { - version: '1.0.0', + const { result, ls } = await mockLs(t, { + config: { + ...lock, + ...json, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', }, - ipsum: { - version: '1.0.0', + }), + 'package-lock.json': JSON.stringify({ + dependencies: { + foo: { + version: '1.0.0', + requires: { + dog: '^1.0.0', + }, + }, + dog: { + version: '1.0.0', + }, + chai: { + version: '1.0.0', + }, + ipsum: { + version: '1.0.0', + }, }, - }, - }), + }), + }, }) await ls.exec(['dog']) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', @@ -4442,39 +4754,45 @@ t.test('ls --package-lock-only', t => { }) t.test('with multiple filter args', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - ipsum: '^1.0.0', - }, - }), - 'package-lock.json': JSON.stringify({ - dependencies: { - foo: { - version: '1.0.0', - requires: { - dog: '^1.0.0', - }, - }, - dog: { - version: '1.0.0', - }, - chai: { - version: '1.0.0', + const { result, ls } = await mockLs(t, { + config: { + ...lock, + ...json, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', + ipsum: '^1.0.0', }, - ipsum: { - version: '1.0.0', + }), + 'package-lock.json': JSON.stringify({ + dependencies: { + foo: { + version: '1.0.0', + requires: { + dog: '^1.0.0', + }, + }, + dog: { + version: '1.0.0', + }, + chai: { + version: '1.0.0', + }, + ipsum: { + version: '1.0.0', + }, }, - }, - }), + }), + }, }) await ls.exec(['dog@*', 'chai@1.0.0']) t.same( - jsonParse(result), + jsonParse(result()), { version: '1.0.0', name: 'test-npm-ls', @@ -4501,35 +4819,41 @@ t.test('ls --package-lock-only', t => { }) t.test('with missing filter arg', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - }, - }), - 'package-lock.json': JSON.stringify({ - dependencies: { - foo: { - version: '1.0.0', - requires: { - dog: '^1.0.0', - }, - }, - dog: { - version: '1.0.0', + const { result, ls } = await mockLs(t, { + config: { + ...lock, + ...json, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', }, - chai: { - version: '1.0.0', + }), + 'package-lock.json': JSON.stringify({ + dependencies: { + foo: { + version: '1.0.0', + requires: { + dog: '^1.0.0', + }, + }, + dog: { + version: '1.0.0', + }, + chai: { + version: '1.0.0', + }, }, - }, - }), + }), + }, }) await ls.exec(['notadep']) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', @@ -4537,41 +4861,45 @@ t.test('ls --package-lock-only', t => { 'should output json containing no dependencies info' ) t.equal(process.exitCode, 1, 'should exit with error code 1') - process.exitCode = 0 }) t.test('default --depth value should now be 0', async t => { - config.all = false - config.depth = undefined - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - }, - }), - 'package-lock.json': JSON.stringify({ - dependencies: { - foo: { - version: '1.0.0', - requires: { - dog: '^1.0.0', - }, - }, - dog: { - version: '1.0.0', + const { result, ls } = await mockLs(t, { + config: { + ...lock, + ...json, + all: false, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', }, - chai: { - version: '1.0.0', + }), + 'package-lock.json': JSON.stringify({ + dependencies: { + foo: { + version: '1.0.0', + requires: { + dog: '^1.0.0', + }, + }, + dog: { + version: '1.0.0', + }, + chai: { + version: '1.0.0', + }, }, - }, - }), + }), + }, }) await ls.exec([]) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', @@ -4588,42 +4916,46 @@ t.test('ls --package-lock-only', t => { }, 'should output json containing only top-level dependencies' ) - config.all = true - config.depth = Infinity }) t.test('--depth=0', async t => { - config.all = false - config.depth = 0 - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - }, - }), - 'package-lock.json': JSON.stringify({ - dependencies: { - foo: { - version: '1.0.0', - requires: { - dog: '^1.0.0', + const { result, ls } = await mockLs(t, { + config: { + ...lock, + ...json, + depth: 0, + all: false, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', + }, + }), + 'package-lock.json': JSON.stringify({ + dependencies: { + foo: { + version: '1.0.0', + requires: { + dog: '^1.0.0', + }, + }, + dog: { + version: '1.0.0', + }, + chai: { + version: '1.0.0', }, }, - dog: { - version: '1.0.0', - }, - chai: { - version: '1.0.0', - }, - }, - }), + }), + }, }) await ls.exec([]) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', @@ -4640,42 +4972,46 @@ t.test('ls --package-lock-only', t => { }, 'should output json containing only top-level dependencies' ) - config.all = true - config.depth = Infinity }) t.test('--depth=1', async t => { - config.all = false - config.depth = 1 - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^1.0.0', - chai: '^1.0.0', - }, - }), - 'package-lock.json': JSON.stringify({ - dependencies: { - foo: { - version: '1.0.0', - requires: { - dog: '^1.0.0', - }, - }, - dog: { - version: '1.0.0', + const { result, ls } = await mockLs(t, { + config: { + ...lock, + ...json, + all: false, + depth: 1, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + chai: '^1.0.0', }, - chai: { - version: '1.0.0', + }), + 'package-lock.json': JSON.stringify({ + dependencies: { + foo: { + version: '1.0.0', + requires: { + dog: '^1.0.0', + }, + }, + dog: { + version: '1.0.0', + }, + chai: { + version: '1.0.0', + }, }, - }, - }), + }), + }, }) await ls.exec([]) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', @@ -4698,46 +5034,49 @@ t.test('ls --package-lock-only', t => { }, 'should output json containing top-level deps and their deps only' ) - config.all = true - config.depth = Infinity }) t.test('missing/invalid/extraneous', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: '^2.0.0', - ipsum: '^1.0.0', - }, - }), - 'package-lock.json': JSON.stringify({ - dependencies: { - foo: { - version: '1.0.0', - requires: { - dog: '^1.0.0', - }, - }, - dog: { - version: '1.0.0', + const { result, ls } = await mockLs(t, { + config: { + ...lock, + ...json, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^2.0.0', + ipsum: '^1.0.0', }, - chai: { - version: '1.0.0', + }), + 'package-lock.json': JSON.stringify({ + dependencies: { + foo: { + version: '1.0.0', + requires: { + dog: '^1.0.0', + }, + }, + dog: { + version: '1.0.0', + }, + chai: { + version: '1.0.0', + }, }, - }, - }), + }), + }, }) await t.rejects(ls.exec([]), { code: 'ELSPROBLEMS' }, 'should list dep problems') t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', problems: [ - /* eslint-disable-next-line max-len */ - 'invalid: foo@1.0.0 {CWD}/tap-testdir-ls-ls---package-lock-only-ls---package-lock-only---json-missing-invalid-extraneous/node_modules/foo', + 'invalid: foo@1.0.0 {CWD}/prefix/node_modules/foo', 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0', ], dependencies: { @@ -4746,8 +5085,7 @@ t.test('ls --package-lock-only', t => { overridden: false, invalid: '"^2.0.0" from the root project', problems: [ - /* eslint-disable-next-line max-len */ - 'invalid: foo@1.0.0 {CWD}/tap-testdir-ls-ls---package-lock-only-ls---package-lock-only---json-missing-invalid-extraneous/node_modules/foo', + 'invalid: foo@1.0.0 {CWD}/prefix/node_modules/foo', ], dependencies: { dog: { @@ -4762,96 +5100,110 @@ t.test('ls --package-lock-only', t => { problems: ['missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0'], }, }, + error: { + code: 'ELSPROBLEMS', + summary: [ + 'invalid: foo@1.0.0 {CWD}/prefix/node_modules/foo', + 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0', + ].join('\n'), + detail: '', + }, }, 'should output json containing top-level deps and their deps only' ) }) t.test('from lockfile', async t => { - npm.prefix = t.testdir({ - 'package-lock.json': JSON.stringify({ - name: 'dedupe-lockfile', - version: '1.0.0', - lockfileVersion: 2, - requires: true, - packages: { - '': { - name: 'dedupe-lockfile', - version: '1.0.0', - dependencies: { - '@isaacs/dedupe-tests-a': '1.0.1', - '@isaacs/dedupe-tests-b': '1||2', + const { result, ls } = await mockLs(t, { + config: { + ...lock, + ...json, + }, + prefixDir: { + 'package-lock.json': JSON.stringify({ + name: 'dedupe-lockfile', + version: '1.0.0', + lockfileVersion: 2, + requires: true, + packages: { + '': { + name: 'dedupe-lockfile', + version: '1.0.0', + dependencies: { + '@isaacs/dedupe-tests-a': '1.0.1', + '@isaacs/dedupe-tests-b': '1||2', + }, }, - }, - 'node_modules/@isaacs/dedupe-tests-a': { - name: '@isaacs/dedupe-tests-a', - version: '1.0.1', - /* eslint-disable-next-line max-len */ - resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz', - /* eslint-disable-next-line max-len */ - integrity: 'sha512-8AN9lNCcBt5Xeje7fMEEpp5K3rgcAzIpTtAjYb/YMUYu8SbIVF6wz0WqACDVKvpQOUcSfNHZQNLNmue0QSwXOQ==', - dependencies: { - '@isaacs/dedupe-tests-b': '1', + 'node_modules/@isaacs/dedupe-tests-a': { + name: '@isaacs/dedupe-tests-a', + version: '1.0.1', + /* eslint-disable-next-line max-len */ + resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz', + /* eslint-disable-next-line max-len */ + 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', - /* eslint-disable-next-line max-len */ - resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz', - /* eslint-disable-next-line max-len */ - integrity: 'sha512-3nmvzIb8QL8OXODzipwoV3U8h9OQD9g9RwOPuSBQqjqSg9JZR1CCFOWNsDUtOfmwY8HFUJV9EAZ124uhqVxq+w==', - }, - 'node_modules/@isaacs/dedupe-tests-b': { - name: '@isaacs/dedupe-tests-b', - version: '2.0.0', - /* eslint-disable-next-line max-len */ - resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz', - /* eslint-disable-next-line max-len */ - integrity: 'sha512-KTYkpRv9EzlmCg4Gsm/jpclWmRYFCXow8GZKJXjK08sIZBlElTZEa5Bw/UQxIvEfcKmWXczSqItD49Kr8Ax4UA==', - }, - }, - dependencies: { - '@isaacs/dedupe-tests-a': { - version: '1.0.1', - /* eslint-disable-next-line max-len */ - resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz', - /* eslint-disable-next-line max-len */ - integrity: 'sha512-8AN9lNCcBt5Xeje7fMEEpp5K3rgcAzIpTtAjYb/YMUYu8SbIVF6wz0WqACDVKvpQOUcSfNHZQNLNmue0QSwXOQ==', - requires: { - '@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', + /* eslint-disable-next-line max-len */ + resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz', + /* eslint-disable-next-line max-len */ + integrity: 'sha512-3nmvzIb8QL8OXODzipwoV3U8h9OQD9g9RwOPuSBQqjqSg9JZR1CCFOWNsDUtOfmwY8HFUJV9EAZ124uhqVxq+w==', }, - dependencies: { - '@isaacs/dedupe-tests-b': { - version: '1.0.0', - /* eslint-disable-next-line max-len */ - resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz', - /* eslint-disable-next-line max-len */ - integrity: 'sha512-3nmvzIb8QL8OXODzipwoV3U8h9OQD9g9RwOPuSBQqjqSg9JZR1CCFOWNsDUtOfmwY8HFUJV9EAZ124uhqVxq+w==', + 'node_modules/@isaacs/dedupe-tests-b': { + name: '@isaacs/dedupe-tests-b', + version: '2.0.0', + /* eslint-disable-next-line max-len */ + resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz', + /* eslint-disable-next-line max-len */ + integrity: 'sha512-KTYkpRv9EzlmCg4Gsm/jpclWmRYFCXow8GZKJXjK08sIZBlElTZEa5Bw/UQxIvEfcKmWXczSqItD49Kr8Ax4UA==', + }, + }, + dependencies: { + '@isaacs/dedupe-tests-a': { + version: '1.0.1', + /* eslint-disable-next-line max-len */ + resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz', + /* eslint-disable-next-line max-len */ + integrity: 'sha512-8AN9lNCcBt5Xeje7fMEEpp5K3rgcAzIpTtAjYb/YMUYu8SbIVF6wz0WqACDVKvpQOUcSfNHZQNLNmue0QSwXOQ==', + requires: { + '@isaacs/dedupe-tests-b': '1', + }, + dependencies: { + '@isaacs/dedupe-tests-b': { + version: '1.0.0', + /* eslint-disable-next-line max-len */ + resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz', + /* eslint-disable-next-line max-len */ + integrity: 'sha512-3nmvzIb8QL8OXODzipwoV3U8h9OQD9g9RwOPuSBQqjqSg9JZR1CCFOWNsDUtOfmwY8HFUJV9EAZ124uhqVxq+w==', + }, }, }, + '@isaacs/dedupe-tests-b': { + version: '2.0.0', + /* eslint-disable-next-line max-len */ + resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz', + /* eslint-disable-next-line max-len */ + integrity: 'sha512-KTYkpRv9EzlmCg4Gsm/jpclWmRYFCXow8GZKJXjK08sIZBlElTZEa5Bw/UQxIvEfcKmWXczSqItD49Kr8Ax4UA==', + }, }, - '@isaacs/dedupe-tests-b': { - version: '2.0.0', - /* eslint-disable-next-line max-len */ - resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz', - /* eslint-disable-next-line max-len */ - integrity: 'sha512-KTYkpRv9EzlmCg4Gsm/jpclWmRYFCXow8GZKJXjK08sIZBlElTZEa5Bw/UQxIvEfcKmWXczSqItD49Kr8Ax4UA==', + }), + 'package.json': JSON.stringify({ + name: 'dedupe-lockfile', + version: '1.0.0', + dependencies: { + '@isaacs/dedupe-tests-a': '1.0.1', + '@isaacs/dedupe-tests-b': '1||2', }, - }, - }), - 'package.json': JSON.stringify({ - name: 'dedupe-lockfile', - version: '1.0.0', - dependencies: { - '@isaacs/dedupe-tests-a': '1.0.1', - '@isaacs/dedupe-tests-b': '1||2', - }, - }), + }), + }, }) await ls.exec([]) t.same( - jsonParse(result), + jsonParse(result()), { version: '1.0.0', name: 'dedupe-lockfile', @@ -4883,26 +5235,32 @@ t.test('ls --package-lock-only', t => { }) t.test('using aliases', async t => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - a: 'npm:b@1.0.0', - }, - }), - 'package-lock.json': JSON.stringify({ - dependencies: { - a: { - version: 'npm:b@1.0.0', - resolved: 'https://localhost:8080/abbrev/-/abbrev-1.0.0.tgz', + const { result, ls } = await mockLs(t, { + config: { + ...lock, + ...json, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + a: 'npm:b@1.0.0', }, - }, - }), + }), + 'package-lock.json': JSON.stringify({ + dependencies: { + a: { + version: 'npm:b@1.0.0', + resolved: 'https://localhost:8080/abbrev/-/abbrev-1.0.0.tgz', + }, + }, + }), + }, }) await ls.exec([]) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', @@ -4919,32 +5277,38 @@ t.test('ls --package-lock-only', t => { }) t.test('resolved points to git ref', async t => { - config.long = false - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - abbrev: 'git+https://github.com/isaacs/abbrev-js.git', - }, - }), - 'package-lock.json': JSON.stringify({ - name: 'test-npm-ls', - version: '1.0.0', - lockfileVersion: 2, - requires: true, - dependencies: { - abbrev: { + const { result, ls } = await mockLs(t, { + config: { + ...lock, + ...json, + long: false, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + abbrev: 'git+https://github.com/isaacs/abbrev-js.git', + }, + }), + 'package-lock.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + lockfileVersion: 2, + requires: true, + dependencies: { + abbrev: { /* eslint-disable-next-line max-len */ - version: 'git+ssh://git@github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', - from: 'abbrev@git+https://github.com/isaacs/abbrev-js.git', + version: 'git+ssh://git@github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', + from: 'abbrev@git+https://github.com/isaacs/abbrev-js.git', + }, }, - }, - }), + }), + }, }) await ls.exec([]) t.same( - jsonParse(result), + jsonParse(result()), { name: 'test-npm-ls', version: '1.0.0', @@ -4959,9 +5323,5 @@ t.test('ls --package-lock-only', t => { 'should output json containing git refs' ) }) - - t.end() }) - - t.end() }) diff --git a/deps/npm/test/lib/commands/org.js b/deps/npm/test/lib/commands/org.js index cd25fc23aa3344..d3700304328eea 100644 --- a/deps/npm/test/lib/commands/org.js +++ b/deps/npm/test/lib/commands/org.js @@ -1,53 +1,56 @@ const t = require('tap') const ansiTrim = require('../../../lib/utils/ansi-trim.js') -const { fake: mockNpm } = require('../../fixtures/mock-npm') - -const output = [] -const npm = mockNpm({ - flatOptions: { - json: false, - parseable: false, - }, - config: { - loglevel: 'info', - }, - output: msg => { - output.push(msg) - }, -}) +const mockNpm = require('../../fixtures/mock-npm') + +const mockOrg = async (t, { orgSize = 1, orgList = {}, ...npmOpts } = {}) => { + let setArgs = null + let rmArgs = null + let lsArgs = null + + const libnpmorg = { + set: async (org, user, role, opts) => { + setArgs = { org, user, role, opts } + return { + org: { + name: org, + size: orgSize, + }, + user, + role, + } + }, + rm: async (org, user, opts) => { + rmArgs = { org, user, opts } + }, + ls: async (org, opts) => { + lsArgs = { org, opts } + return orgList + }, + } -let orgSize = 1 -let orgSetArgs = null -let orgRmArgs = null -let orgLsArgs = null -let orgList = {} -const libnpmorg = { - set: async (org, user, role, opts) => { - orgSetArgs = { org, user, role, opts } - return { - org: { - name: org, - size: orgSize, - }, - user, - role, - } - }, - rm: async (org, user, opts) => { - orgRmArgs = { org, user, opts } - }, - ls: async (org, opts) => { - orgLsArgs = { org, opts } - return orgList - }, -} + const mock = await mockNpm(t, { + ...npmOpts, + mocks: { + libnpmorg, + ...npmOpts.mocks, + }, + }) -const Org = t.mock('../../../lib/commands/org.js', { - libnpmorg, -}) -const org = new Org(npm) + return { + ...mock, + org: { + exec: (args) => mock.npm.exec('org', args), + completion: (arg) => mock.npm.cmd('org').then(c => c.completion(arg)), + usage: () => mock.npm.cmd('org').then(c => c.usage), + }, + setArgs: () => setArgs, + rmArgs: () => rmArgs, + lsArgs: () => lsArgs, + } +} t.test('completion', async t => { + const { org } = await mockOrg(t) const completion = argv => org.completion({ conf: { argv: { remain: argv } } }) const assertions = [ @@ -73,19 +76,17 @@ t.test('completion', async t => { }) t.test('npm org - invalid subcommand', async t => { - await t.rejects(org.exec(['foo']), org.usage) + const { org } = await mockOrg(t) + await t.rejects(org.exec(['foo']), org.usage()) }) t.test('npm org add', async t => { - t.teardown(() => { - orgSetArgs = null - output.length = 0 - }) + const { npm, org, setArgs, outputs } = await mockOrg(t) await org.exec(['add', 'orgname', 'username']) t.match( - orgSetArgs, + setArgs(), { org: 'orgname', user: 'username', @@ -95,17 +96,14 @@ t.test('npm org add', async t => { 'received the correct arguments' ) t.equal( - output[0], + outputs[0][0], 'Added username as developer to orgname. You now have 1 member in this org.', 'printed the correct output' ) }) t.test('npm org add - no org', async t => { - t.teardown(() => { - orgSetArgs = null - output.length = 0 - }) + const { org } = await mockOrg(t) await t.rejects( org.exec(['add', '', 'username']), @@ -115,11 +113,7 @@ t.test('npm org add - no org', async t => { }) t.test('npm org add - no user', async t => { - t.teardown(() => { - orgSetArgs = null - output.length = 0 - }) - + const { org } = await mockOrg(t) await t.rejects( org.exec(['add', 'orgname', '']), /`username` is required/, @@ -128,11 +122,7 @@ t.test('npm org add - no user', async t => { }) t.test('npm org add - invalid role', async t => { - t.teardown(() => { - orgSetArgs = null - output.length = 0 - }) - + const { org } = await mockOrg(t) await t.rejects( org.exec(['add', 'orgname', 'username', 'person']), /`role` must be one of/, @@ -141,16 +131,12 @@ t.test('npm org add - invalid role', async t => { }) t.test('npm org add - more users', async t => { - orgSize = 5 - t.teardown(() => { - orgSize = 1 - orgSetArgs = null - output.length = 0 - }) + const orgSize = 5 + const { npm, org, outputs, setArgs } = await mockOrg(t, { orgSize }) await org.exec(['add', 'orgname', 'username']) t.match( - orgSetArgs, + setArgs(), { org: 'orgname', user: 'username', @@ -160,24 +146,21 @@ t.test('npm org add - more users', async t => { 'received the correct arguments' ) t.equal( - output[0], + outputs[0][0], 'Added username as developer to orgname. You now have 5 members in this org.', 'printed the correct output' ) }) t.test('npm org add - json output', async t => { - npm.flatOptions.json = true - t.teardown(() => { - npm.flatOptions.json = false - orgSetArgs = null - output.length = 0 + const { npm, org, outputs, setArgs } = await mockOrg(t, { + config: { json: true }, }) await org.exec(['add', 'orgname', 'username']) t.match( - orgSetArgs, + setArgs(), { org: 'orgname', user: 'username', @@ -187,7 +170,7 @@ t.test('npm org add - json output', async t => { 'received the correct arguments' ) t.strictSame( - JSON.parse(output[0]), + JSON.parse(outputs[0]), { org: { name: 'orgname', @@ -201,17 +184,15 @@ t.test('npm org add - json output', async t => { }) t.test('npm org add - parseable output', async t => { - npm.flatOptions.parseable = true - t.teardown(() => { - npm.flatOptions.parseable = false - orgSetArgs = null - output.length = 0 + const config = { parseable: true } + const { npm, org, outputs, setArgs } = await mockOrg(t, { + config, }) await org.exec(['add', 'orgname', 'username']) t.match( - orgSetArgs, + setArgs(), { org: 'orgname', user: 'username', @@ -221,7 +202,7 @@ t.test('npm org add - parseable output', async t => { 'received the correct arguments' ) t.strictSame( - output.map(line => line.split(/\t/)), + outputs.map(line => line[0].split(/\t/)), [ ['org', 'orgsize', 'user', 'role'], ['orgname', '1', 'username', 'developer'], @@ -231,17 +212,15 @@ t.test('npm org add - parseable output', async t => { }) t.test('npm org add - silent output', async t => { - npm.config.set('loglevel', 'silent') - t.teardown(() => { - npm.config.set('loglevel', 'info') - orgSetArgs = null - output.length = 0 + const config = { loglevel: 'silent' } + const { npm, org, outputs, setArgs } = await mockOrg(t, { + config, }) await org.exec(['add', 'orgname', 'username']) t.match( - orgSetArgs, + setArgs(), { org: 'orgname', user: 'username', @@ -250,20 +229,16 @@ t.test('npm org add - silent output', async t => { }, 'received the correct arguments' ) - t.strictSame(output, [], 'prints no output') + t.strictSame(outputs, [], 'prints no output') }) t.test('npm org rm', async t => { - t.teardown(() => { - orgRmArgs = null - orgLsArgs = null - output.length = 0 - }) + const { npm, org, outputs, lsArgs, rmArgs } = await mockOrg(t) await org.exec(['rm', 'orgname', 'username']) t.match( - orgRmArgs, + rmArgs(), { org: 'orgname', user: 'username', @@ -272,7 +247,7 @@ t.test('npm org rm', async t => { 'libnpmorg.rm received the correct args' ) t.match( - orgLsArgs, + lsArgs(), { org: 'orgname', opts: npm.flatOptions, @@ -280,18 +255,14 @@ t.test('npm org rm', async t => { 'libnpmorg.ls received the correct args' ) t.equal( - output[0], + outputs[0][0], 'Successfully removed username from orgname. You now have 0 members in this org.', 'printed the correct output' ) }) t.test('npm org rm - no org', async t => { - t.teardown(() => { - orgRmArgs = null - orgLsArgs = null - output.length = 0 - }) + const { org } = await mockOrg(t) await t.rejects( org.exec(['rm', '', 'username']), @@ -301,31 +272,23 @@ t.test('npm org rm - no org', async t => { }) t.test('npm org rm - no user', async t => { - t.teardown(() => { - orgRmArgs = null - orgLsArgs = null - output.length = 0 - }) + const { org } = await mockOrg(t) await t.rejects(org.exec(['rm', 'orgname']), /`username` is required/, 'threw the correct error') }) t.test('npm org rm - one user left', async t => { - orgList = { + const orgList = { one: 'developer', } - - t.teardown(() => { - orgList = {} - orgRmArgs = null - orgLsArgs = null - output.length = 0 + const { npm, org, outputs, lsArgs, rmArgs } = await mockOrg(t, { + orgList, }) await org.exec(['rm', 'orgname', 'username']) t.match( - orgRmArgs, + rmArgs(), { org: 'orgname', user: 'username', @@ -334,7 +297,7 @@ t.test('npm org rm - one user left', async t => { 'libnpmorg.rm received the correct args' ) t.match( - orgLsArgs, + lsArgs(), { org: 'orgname', opts: npm.flatOptions, @@ -342,25 +305,22 @@ t.test('npm org rm - one user left', async t => { 'libnpmorg.ls received the correct args' ) t.equal( - output[0], + outputs[0][0], 'Successfully removed username from orgname. You now have 1 member in this org.', 'printed the correct output' ) }) t.test('npm org rm - json output', async t => { - npm.flatOptions.json = true - t.teardown(() => { - npm.flatOptions.json = false - orgRmArgs = null - orgLsArgs = null - output.length = 0 + const config = { json: true } + const { npm, org, outputs, lsArgs, rmArgs } = await mockOrg(t, { + config, }) await org.exec(['rm', 'orgname', 'username']) t.match( - orgRmArgs, + rmArgs(), { org: 'orgname', user: 'username', @@ -369,7 +329,7 @@ t.test('npm org rm - json output', async t => { 'libnpmorg.rm received the correct args' ) t.match( - orgLsArgs, + lsArgs(), { org: 'orgname', opts: npm.flatOptions, @@ -377,7 +337,7 @@ t.test('npm org rm - json output', async t => { 'libnpmorg.ls received the correct args' ) t.strictSame( - JSON.parse(output[0]), + JSON.parse(outputs[0]), { user: 'username', org: 'orgname', @@ -389,18 +349,15 @@ t.test('npm org rm - json output', async t => { }) t.test('npm org rm - parseable output', async t => { - npm.flatOptions.parseable = true - t.teardown(() => { - npm.flatOptions.parseable = false - orgRmArgs = null - orgLsArgs = null - output.length = 0 + const config = { parseable: true } + const { npm, org, outputs, lsArgs, rmArgs } = await mockOrg(t, { + config, }) await org.exec(['rm', 'orgname', 'username']) t.match( - orgRmArgs, + rmArgs(), { org: 'orgname', user: 'username', @@ -409,7 +366,7 @@ t.test('npm org rm - parseable output', async t => { 'libnpmorg.rm received the correct args' ) t.match( - orgLsArgs, + lsArgs(), { org: 'orgname', opts: npm.flatOptions, @@ -417,7 +374,7 @@ t.test('npm org rm - parseable output', async t => { 'libnpmorg.ls received the correct args' ) t.strictSame( - output.map(line => line.split(/\t/)), + outputs.map(line => line[0].split(/\t/)), [ ['user', 'org', 'userCount', 'deleted'], ['username', 'orgname', '0', 'true'], @@ -427,18 +384,15 @@ t.test('npm org rm - parseable output', async t => { }) t.test('npm org rm - silent output', async t => { - npm.config.set('loglevel', 'silent') - t.teardown(() => { - npm.config.set('loglevel', 'info') - orgRmArgs = null - orgLsArgs = null - output.length = 0 + const config = { loglevel: 'silent' } + const { npm, org, outputs, lsArgs, rmArgs } = await mockOrg(t, { + config, }) await org.exec(['rm', 'orgname', 'username']) t.match( - orgRmArgs, + rmArgs(), { org: 'orgname', user: 'username', @@ -447,149 +401,135 @@ t.test('npm org rm - silent output', async t => { 'libnpmorg.rm received the correct args' ) t.match( - orgLsArgs, + lsArgs(), { org: 'orgname', opts: npm.flatOptions, }, 'libnpmorg.ls received the correct args' ) - t.strictSame(output, [], 'printed no output') + t.strictSame(outputs, [], 'printed no output') }) t.test('npm org ls', async t => { - orgList = { + const orgList = { one: 'developer', two: 'admin', three: 'owner', } - t.teardown(() => { - orgList = {} - orgLsArgs = null - output.length = 0 + const { npm, org, outputs, lsArgs } = await mockOrg(t, { + orgList, }) await org.exec(['ls', 'orgname']) t.match( - orgLsArgs, + lsArgs(), { org: 'orgname', opts: npm.flatOptions, }, 'receieved the correct args' ) - const out = ansiTrim(output[0]) + const out = ansiTrim(outputs[0][0]) t.match(out, /one.*developer/, 'contains the developer member') t.match(out, /two.*admin/, 'contains the admin member') t.match(out, /three.*owner/, 'contains the owner member') }) t.test('npm org ls - user filter', async t => { - orgList = { + const orgList = { username: 'admin', missing: 'admin', } - t.teardown(() => { - orgList = {} - orgLsArgs = null - output.length = 0 + const { npm, org, outputs, lsArgs } = await mockOrg(t, { + orgList, }) await org.exec(['ls', 'orgname', 'username']) t.match( - orgLsArgs, + lsArgs(), { org: 'orgname', opts: npm.flatOptions, }, 'receieved the correct args' ) - const out = ansiTrim(output[0]) + const out = ansiTrim(outputs[0][0]) t.match(out, /username.*admin/, 'contains the filtered member') t.notMatch(out, /missing.*admin/, 'does not contain other members') }) t.test('npm org ls - user filter, missing user', async t => { - orgList = { + const orgList = { missing: 'admin', } - t.teardown(() => { - orgList = {} - orgLsArgs = null - output.length = 0 + const { npm, org, outputs, lsArgs } = await mockOrg(t, { + orgList, }) await org.exec(['ls', 'orgname', 'username']) t.match( - orgLsArgs, + lsArgs(), { org: 'orgname', opts: npm.flatOptions, }, 'receieved the correct args' ) - const out = ansiTrim(output[0]) + const out = ansiTrim(outputs[0][0]) t.notMatch(out, /username/, 'does not contain the requested member') t.notMatch(out, /missing.*admin/, 'does not contain other members') }) t.test('npm org ls - no org', async t => { - t.teardown(() => { - orgLsArgs = null - output.length = 0 - }) - + const { org } = await mockOrg(t) await t.rejects(org.exec(['ls']), /`orgname` is required/, 'throws the correct error') }) t.test('npm org ls - json output', async t => { - npm.flatOptions.json = true - orgList = { + const config = { json: true } + const orgList = { one: 'developer', two: 'admin', three: 'owner', } - t.teardown(() => { - npm.flatOptions.json = false - orgList = {} - orgLsArgs = null - output.length = 0 + const { npm, org, outputs, lsArgs } = await mockOrg(t, { + orgList, + config, }) await org.exec(['ls', 'orgname']) t.match( - orgLsArgs, + lsArgs(), { org: 'orgname', opts: npm.flatOptions, }, 'receieved the correct args' ) - t.strictSame(JSON.parse(output[0]), orgList, 'prints the correct output') + t.strictSame(JSON.parse(outputs[0]), orgList, 'prints the correct output') }) t.test('npm org ls - parseable output', async t => { - npm.flatOptions.parseable = true - orgList = { + const config = { parseable: true } + const orgList = { one: 'developer', two: 'admin', three: 'owner', } - t.teardown(() => { - npm.flatOptions.parseable = false - orgList = {} - orgLsArgs = null - output.length = 0 + const { npm, org, outputs, lsArgs } = await mockOrg(t, { + orgList, + config, }) await org.exec(['ls', 'orgname']) t.match( - orgLsArgs, + lsArgs(), { org: 'orgname', opts: npm.flatOptions, @@ -597,7 +537,7 @@ t.test('npm org ls - parseable output', async t => { 'receieved the correct args' ) t.strictSame( - output.map(line => line.split(/\t/)), + outputs.map(line => line[0].split(/\t/)), [ ['user', 'role'], ['one', 'developer'], @@ -609,28 +549,26 @@ t.test('npm org ls - parseable output', async t => { }) t.test('npm org ls - silent output', async t => { - npm.config.set('loglevel', 'silent') - orgList = { + const config = { loglevel: 'silent' } + const orgList = { one: 'developer', two: 'admin', three: 'owner', } - t.teardown(() => { - npm.config.set('loglevel', 'info') - orgList = {} - orgLsArgs = null - output.length = 0 + const { npm, org, outputs, lsArgs } = await mockOrg(t, { + orgList, + config, }) await org.exec(['ls', 'orgname']) t.match( - orgLsArgs, + lsArgs(), { org: 'orgname', opts: npm.flatOptions, }, 'receieved the correct args' ) - t.strictSame(output, [], 'printed no output') + t.strictSame(outputs, [], 'printed no output') }) diff --git a/deps/npm/test/lib/commands/outdated.js b/deps/npm/test/lib/commands/outdated.js index 4803c7e17188ca..02f2067c5480eb 100644 --- a/deps/npm/test/lib/commands/outdated.js +++ b/deps/npm/test/lib/commands/outdated.js @@ -1,5 +1,9 @@ const t = require('tap') -const { fake: mockNpm } = require('../../fixtures/mock-npm') +const MockRegistry = require('@npmcli/mock-registry') +const _mockNpm = require('../../fixtures/mock-npm') +const { cleanCwd } = require('../../fixtures/clean-snapshot') + +t.cleanSnapshot = (str) => cleanCwd(str) const packument = spec => { const mocks = { @@ -68,69 +72,18 @@ const packument = spec => { return mocks[spec.name] } -let logs -const output = (msg) => { - logs = `${logs}\n${msg}` -} - -const globalDir = t.testdir({ - node_modules: { - cat: { - 'package.json': JSON.stringify({ - name: 'cat', - version: '1.0.0', - }, null, 2), +const fixtures = { + global: { + node_modules: { + cat: { + 'package.json': JSON.stringify({ + name: 'cat', + version: '1.0.0', + }, null, 2), + }, }, }, -}) - -const outdated = (dir, opts) => { - logs = '' - const Outdated = t.mock('../../../lib/commands/outdated.js', { - pacote: { - packument, - }, - }) - if (opts.config && opts.config.omit) { - opts.flatOptions = { - omit: opts.config.omit, - ...opts.flatOptions, - } - delete opts.config.omit - } - const npm = mockNpm({ - ...opts, - localPrefix: dir, - prefix: dir, - flatOptions: { - workspacesEnabled: true, - omit: [], - ...opts.flatOptions, - }, - globalDir: `${globalDir}/node_modules`, - output, - }) - return new Outdated(npm) -} - -t.beforeEach(() => logs = '') - -const { exitCode } = process - -t.afterEach(() => process.exitCode = exitCode) - -const redactCwd = (path) => { - const normalizePath = p => p - .replace(/\\+/g, '/') - .replace(/\r\n/g, '\n') - return normalizePath(path) - .replace(new RegExp(normalizePath(process.cwd()), 'g'), '{CWD}') -} - -t.cleanSnapshot = (str) => redactCwd(str) - -t.test('should display outdated deps', t => { - const testDir = t.testdir({ + local: { 'package.json': JSON.stringify({ name: 'delta', version: '1.0.0', @@ -186,145 +139,274 @@ t.test('should display outdated deps', t => { }, null, 2), }, }, + }, + workspaces: { + 'package.json': JSON.stringify({ + name: 'workspaces-project', + version: '1.0.0', + workspaces: ['packages/*'], + dependencies: { + dog: '^1.0.0', + }, + }), + node_modules: { + a: t.fixture('symlink', '../packages/a'), + b: t.fixture('symlink', '../packages/b'), + c: t.fixture('symlink', '../packages/c'), + cat: { + 'package.json': JSON.stringify({ + name: 'cat', + version: '1.0.0', + dependencies: { + dog: '2.0.0', + }, + }), + node_modules: { + dog: { + 'package.json': JSON.stringify({ + name: 'dog', + version: '2.0.0', + }), + }, + }, + }, + chai: { + 'package.json': JSON.stringify({ + name: 'chai', + version: '1.0.0', + }), + }, + dog: { + 'package.json': JSON.stringify({ + name: 'dog', + version: '1.0.1', + }), + }, + foo: { + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.0.0', + dependencies: { + chai: '^1.0.0', + }, + }), + }, + zeta: { + 'package.json': JSON.stringify({ + name: 'zeta', + version: '1.0.0', + }), + }, + }, + packages: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + dependencies: { + b: '^1.0.0', + cat: '^1.0.0', + foo: '^1.0.0', + }, + }), + }, + b: { + 'package.json': JSON.stringify({ + name: 'b', + version: '1.0.0', + dependencies: { + zeta: '^1.0.0', + }, + }), + }, + c: { + 'package.json': JSON.stringify({ + name: 'c', + version: '1.0.0', + dependencies: { + theta: '^1.0.0', + }, + }), + }, + }, + }, +} + +const mockNpm = async (t, { prefixDir, ...opts } = {}) => { + const res = await _mockNpm(t, { + mocks: { + pacote: { + packument, + }, + }, + ...opts, + prefixDir, + }) + + // this is not currently used, but ensures that no requests are + // hitting the registry. + // XXX: the pacote mock should be replaced with mock registry calls + const registry = new MockRegistry({ + tap: t, + registry: res.npm.config.get('registry'), + strict: true, }) - t.test('outdated global', async t => { - await outdated(null, { + return { + ...res, + registry, + exec: (args) => res.npm.exec('outdated', args), + } +} + +t.test('should display outdated deps', async t => { + await t.test('outdated global', async t => { + const { exec, joinedOutput } = await mockNpm(t, { + globalPrefixDir: fixtures.global, config: { global: true }, - }).exec([]) + }) + await exec([]) t.equal(process.exitCode, 1) - t.matchSnapshot(logs) + t.matchSnapshot(joinedOutput()) }) - t.test('outdated', async t => { - await outdated(testDir, { + await t.test('outdated', async t => { + const { exec, joinedOutput } = await mockNpm(t, { + prefixDir: fixtures.local, config: { - global: false, + color: 'always', }, - color: true, - }).exec([]) + }) + await exec([]) t.equal(process.exitCode, 1) - t.matchSnapshot(logs) + t.matchSnapshot(joinedOutput()) }) - t.test('outdated --omit=dev', async t => { - await outdated(testDir, { + await t.test('outdated --omit=dev', async t => { + const { exec, joinedOutput } = await mockNpm(t, { + prefixDir: fixtures.local, config: { - global: false, omit: ['dev'], + color: 'always', }, - color: true, - }).exec([]) + }) + await exec([]) t.equal(process.exitCode, 1) - t.matchSnapshot(logs) + t.matchSnapshot(joinedOutput()) }) - t.test('outdated --omit=dev --omit=peer', async t => { - await outdated(testDir, { + await t.test('outdated --omit=dev --omit=peer', async t => { + const { exec, joinedOutput } = await mockNpm(t, { + prefixDir: fixtures.local, config: { - global: false, omit: ['dev', 'peer'], + color: 'always', }, - color: true, - }).exec([]) + }) + await exec([]) t.equal(process.exitCode, 1) - t.matchSnapshot(logs) + t.matchSnapshot(joinedOutput()) }) - t.test('outdated --omit=prod', async t => { - await outdated(testDir, { + await t.test('outdated --omit=prod', async t => { + const { exec, joinedOutput } = await mockNpm(t, { + prefixDir: fixtures.local, config: { - global: false, omit: ['prod'], + color: 'always', }, - color: true, - }).exec([]) + }) + await exec([]) t.equal(process.exitCode, 1) - t.matchSnapshot(logs) + t.matchSnapshot(joinedOutput()) }) - t.test('outdated --long', async t => { - await outdated(testDir, { + await t.test('outdated --long', async t => { + const { exec, joinedOutput } = await mockNpm(t, { + prefixDir: fixtures.local, config: { - global: false, long: true, }, - }).exec([]) + }) + await exec([]) t.equal(process.exitCode, 1) - t.matchSnapshot(logs) + t.matchSnapshot(joinedOutput()) }) - t.test('outdated --json', async t => { - await outdated(testDir, { + await t.test('outdated --json', async t => { + const { exec, joinedOutput } = await mockNpm(t, { + prefixDir: fixtures.local, config: { - global: false, json: true, }, - }).exec([]) + }) + await exec([]) t.equal(process.exitCode, 1) - t.matchSnapshot(logs) + t.matchSnapshot(joinedOutput()) }) - t.test('outdated --json --long', async t => { - await outdated(testDir, { + await t.test('outdated --json --long', async t => { + const { exec, joinedOutput } = await mockNpm(t, { + prefixDir: fixtures.local, config: { - global: false, json: true, long: true, }, - }).exec([]) + }) + await exec([]) t.equal(process.exitCode, 1) - t.matchSnapshot(logs) + t.matchSnapshot(joinedOutput()) }) - t.test('outdated --parseable', async t => { - await outdated(testDir, { + await t.test('outdated --parseable', async t => { + const { exec, joinedOutput } = await mockNpm(t, { + prefixDir: fixtures.local, config: { - global: false, parseable: true, }, - }).exec([]) + }) + await exec([]) t.equal(process.exitCode, 1) - t.matchSnapshot(logs) + t.matchSnapshot(joinedOutput()) }) - t.test('outdated --parseable --long', async t => { - await outdated(testDir, { + await t.test('outdated --parseable --long', async t => { + const { exec, joinedOutput } = await mockNpm(t, { + prefixDir: fixtures.local, config: { - global: false, parseable: true, long: true, }, - }).exec([]) + }) + await exec([]) t.equal(process.exitCode, 1) - t.matchSnapshot(logs) + t.matchSnapshot(joinedOutput()) }) - t.test('outdated --all', async t => { - await outdated(testDir, { + await t.test('outdated --all', async t => { + const { exec, joinedOutput } = await mockNpm(t, { + prefixDir: fixtures.local, config: { all: true, }, - }).exec([]) + }) + await exec([]) t.equal(process.exitCode, 1) - t.matchSnapshot(logs) + t.matchSnapshot(joinedOutput()) }) - t.test('outdated specific dep', async t => { - await outdated(testDir, { - config: { - global: false, - }, - }).exec(['cat']) + await t.test('outdated specific dep', async t => { + const { exec, joinedOutput } = await mockNpm(t, { + prefixDir: fixtures.local, + }) + await exec(['cat']) t.equal(process.exitCode, 1) - t.matchSnapshot(logs) + t.matchSnapshot(joinedOutput()) }) - - t.end() }) t.test('should return if no outdated deps', async t => { - const testDir = t.testdir({ + const testDir = { 'package.json': JSON.stringify({ name: 'delta', version: '1.0.0', @@ -340,18 +422,18 @@ t.test('should return if no outdated deps', async t => { }, null, 2), }, }, - }) + } - await outdated(testDir, { - config: { - global: false, - }, - }).exec([]) - t.equal(logs.length, 0, 'no logs') + const { exec, joinedOutput } = await mockNpm(t, { + prefixDir: testDir, + + }) + await exec([]) + t.equal(joinedOutput(), '', 'no logs') }) t.test('throws if error with a dep', async t => { - const testDir = t.testdir({ + const testDir = { 'package.json': JSON.stringify({ name: 'delta', version: '1.0.0', @@ -367,20 +449,17 @@ t.test('throws if error with a dep', async t => { }, null, 2), }, }, + } + + const { exec } = await mockNpm(t, { + prefixDir: testDir, }) - await t.rejects( - outdated(testDir, { - config: { - global: false, - }, - }).exec([]), - 'There is an error with this package.' - ) + await t.rejects(exec([]), 'There is an error with this package.') }) t.test('should skip missing non-prod deps', async t => { - const testDir = t.testdir({ + const testDir = { 'package.json': JSON.stringify({ name: 'delta', version: '1.0.0', @@ -389,18 +468,19 @@ t.test('should skip missing non-prod deps', async t => { }, }, null, 2), node_modules: {}, + } + + const { exec, joinedOutput } = await mockNpm(t, { + prefixDir: testDir, }) - await outdated(testDir, { - config: { - global: false, - }, - }).exec([]) - t.equal(logs.length, 0, 'no logs') + await exec([]) + + t.equal(joinedOutput(), '', 'no logs') }) t.test('should skip invalid pkg ranges', async t => { - const testDir = t.testdir({ + const testDir = { 'package.json': JSON.stringify({ name: 'delta', version: '1.0.0', @@ -416,14 +496,17 @@ t.test('should skip invalid pkg ranges', async t => { }, null, 2), }, }, - }) + } - await outdated(testDir, {}).exec([]) - t.equal(logs.length, 0, 'no logs') + const { exec, joinedOutput } = await mockNpm(t, { + prefixDir: testDir, + }) + await exec([]) + t.equal(joinedOutput(), '', 'no logs') }) t.test('should skip git specs', async t => { - const testDir = t.testdir({ + const testDir = { 'package.json': JSON.stringify({ name: 'delta', version: '1.0.0', @@ -439,194 +522,70 @@ t.test('should skip git specs', async t => { }, null, 2), }, }, - }) + } - await outdated(testDir, {}).exec([]) - t.equal(logs.length, 0, 'no logs') + const { exec, joinedOutput } = await mockNpm(t, { + prefixDir: testDir, + }) + await exec([]) + t.equal(joinedOutput(), '', 'no logs') }) t.test('workspaces', async t => { - const testDir = t.testdir({ - 'package.json': JSON.stringify({ - name: 'workspaces-project', - version: '1.0.0', - workspaces: ['packages/*'], - dependencies: { - dog: '^1.0.0', - }, - }), - node_modules: { - a: t.fixture('symlink', '../packages/a'), - b: t.fixture('symlink', '../packages/b'), - c: t.fixture('symlink', '../packages/c'), - cat: { - 'package.json': JSON.stringify({ - name: 'cat', - version: '1.0.0', - dependencies: { - dog: '2.0.0', - }, - }), - node_modules: { - dog: { - 'package.json': JSON.stringify({ - name: 'dog', - version: '2.0.0', - }), - }, - }, - }, - chai: { - 'package.json': JSON.stringify({ - name: 'chai', - version: '1.0.0', - }), - }, - dog: { - 'package.json': JSON.stringify({ - name: 'dog', - version: '1.0.1', - }), - }, - foo: { - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.0.0', - dependencies: { - chai: '^1.0.0', - }, - }), - }, - zeta: { - 'package.json': JSON.stringify({ - name: 'zeta', - version: '1.0.0', - }), - }, - }, - packages: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - dependencies: { - b: '^1.0.0', - cat: '^1.0.0', - foo: '^1.0.0', - }, - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'b', - version: '1.0.0', - dependencies: { - zeta: '^1.0.0', - }, - }), - }, - c: { - 'package.json': JSON.stringify({ - name: 'c', - version: '1.0.0', - dependencies: { - theta: '^1.0.0', - }, - }), - }, - }, - }) + const mockWorkspaces = async (t, { exitCode = 1, ...config } = {}) => { + const { exec, joinedOutput } = await mockNpm(t, { + prefixDir: fixtures.workspaces, + config, + }) - await outdated(testDir, {}).exec([]) + await exec([]) - t.matchSnapshot(logs, 'should display ws outdated deps human output') - t.equal(process.exitCode, 1) + t.matchSnapshot(joinedOutput(), 'output') + t.equal(process.exitCode, exitCode ?? undefined) + } - await outdated(testDir, { - flatOptions: { - workspacesEnabled: false, - }, - }).exec([]) + await t.test('should display ws outdated deps human output', t => + mockWorkspaces(t)) // TODO: This should display dog, but doesn't because arborist filters // workspace deps even if they're also root deps // This will be fixed in a future arborist version - t.matchSnapshot(logs, 'should display only root outdated when ws disabled') - - await outdated(testDir, { - config: { - json: true, - }, - }).exec([]) - t.matchSnapshot(logs, 'should display ws outdated deps json output') - t.equal(process.exitCode, 1) - - await outdated(testDir, { - config: { - parseable: true, - }, - }).exec([]) + await t.test('should display only root outdated when ws disabled', t => + mockWorkspaces(t, { workspaces: false, exitCode: null })) - t.matchSnapshot(logs, 'should display ws outdated deps parseable output') - t.equal(process.exitCode, 1) - - await outdated(testDir, { - config: { - all: true, - }, - }).exec([]) - - t.matchSnapshot(logs, 'should display all dependencies') - t.equal(process.exitCode, 1) + await t.test('should display ws outdated deps json output', t => + mockWorkspaces(t, { json: true })) - await outdated(testDir, { - color: true, - }).exec([]) + await t.test('should display ws outdated deps parseable output', t => + mockWorkspaces(t, { parseable: true })) - t.matchSnapshot(logs, 'should highlight ws in dependend by section') - t.equal(process.exitCode, 1) + await t.test('should display all dependencies', t => + mockWorkspaces(t, { all: true })) - await outdated(testDir, {}).execWorkspaces([], ['a']) - t.matchSnapshot(logs, 'should display results filtered by ws') - t.equal(process.exitCode, 1) + await t.test('should highlight ws in dependend by section', t => + mockWorkspaces(t, { color: 'always' })) - await outdated(testDir, { - config: { - json: true, - }, - }).execWorkspaces([], ['a']) - t.matchSnapshot(logs, 'should display json results filtered by ws') - t.equal(process.exitCode, 1) + await t.test('should display results filtered by ws', t => + mockWorkspaces(t, { workspace: 'a' })) - await outdated(testDir, { - config: { - parseable: true, - }, - }).execWorkspaces([], ['a']) - t.matchSnapshot(logs, 'should display parseable results filtered by ws') - t.equal(process.exitCode, 1) + await t.test('should display json results filtered by ws', t => + mockWorkspaces(t, { json: true, workspace: 'a' })) - await outdated(testDir, { - config: { - all: true, - }, - }).execWorkspaces([], ['a']) + await t.test('should display parseable results filtered by ws', t => + mockWorkspaces(t, { parseable: true, workspace: 'a' })) - t.matchSnapshot(logs, - 'should display nested deps when filtering by ws and using --all') - t.equal(process.exitCode, 1) + await t.test('should display nested deps when filtering by ws and using --all', t => + mockWorkspaces(t, { all: true, workspace: 'a' })) - await outdated(testDir, {}).execWorkspaces([], ['b']) - t.matchSnapshot(logs, - 'should display no results if ws has no deps to display') + await t.test('should display no results if ws has no deps to display', t => + mockWorkspaces(t, { workspace: 'b', exitCode: null })) - await outdated(testDir, {}).execWorkspaces([], ['c']) - t.matchSnapshot(logs, - 'should display missing deps when filtering by ws') + await t.test('should display missing deps when filtering by ws', t => + mockWorkspaces(t, { workspace: 'c', exitCode: 1 })) }) t.test('aliases', async t => { - const testDir = t.testdir({ + const testDir = { 'package.json': JSON.stringify({ name: 'display-aliases', version: '1.0.0', @@ -642,10 +601,13 @@ t.test('aliases', async t => { }), }, }, - }) + } - await outdated(testDir, {}).exec([]) + const { exec, joinedOutput } = await mockNpm(t, { + prefixDir: testDir, + }) + await exec([]) - t.matchSnapshot(logs, 'should display aliased outdated dep output') + t.matchSnapshot(joinedOutput(), 'should display aliased outdated dep output') t.equal(process.exitCode, 1) }) diff --git a/deps/npm/test/lib/commands/owner.js b/deps/npm/test/lib/commands/owner.js index 5b6bb443712f02..f9399a60cdf81b 100644 --- a/deps/npm/test/lib/commands/owner.js +++ b/deps/npm/test/lib/commands/owner.js @@ -470,8 +470,10 @@ t.test('workspaces', async t => { t.test('owner no args --workspace', async t => { const { npm } = await loadMockNpm(t, { prefixDir: workspaceFixture, + config: { + workspace: 'workspace-a', + }, }) - npm.config.set('workspace', ['workspace-a']) await t.rejects( npm.exec('owner', []), { code: 'EUSAGE' }, @@ -482,9 +484,7 @@ t.test('workspaces', async t => { t.test('owner ls implicit workspace', async t => { const { npm, joinedOutput } = await loadMockNpm(t, { prefixDir: workspaceFixture, - globals: ({ prefix }) => ({ - 'process.cwd': () => path.join(prefix, 'workspace-a'), - }), + chdir: ({ prefix }) => path.join(prefix, 'workspace-a'), }) await registryPackage(t, npm.config.get('registry'), 'workspace-a') await npm.exec('owner', ['ls']) @@ -494,11 +494,10 @@ t.test('workspaces', async t => { t.test('owner ls explicit workspace', async t => { const { npm, joinedOutput } = await loadMockNpm(t, { prefixDir: workspaceFixture, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), + config: { + workspace: 'workspace-a', + }, }) - npm.config.set('workspace', ['workspace-a']) await registryPackage(t, npm.config.get('registry'), 'workspace-a') await npm.exec('owner', ['ls']) t.match(joinedOutput(), maintainers.map(m => `${m.name} <${m.email}>`).join('\n')) @@ -507,9 +506,7 @@ t.test('workspaces', async t => { t.test('owner ls implicit workspace', async t => { const { npm, joinedOutput } = await loadMockNpm(t, { prefixDir: workspaceFixture, - globals: ({ prefix }) => ({ - 'process.cwd': () => path.join(prefix, 'workspace-a'), - }), + chdir: ({ prefix }) => path.join(prefix, 'workspace-a'), }) await registryPackage(t, npm.config.get('registry'), packageName) await npm.exec('owner', ['ls', packageName]) @@ -519,11 +516,10 @@ t.test('workspaces', async t => { t.test('owner ls explicit workspace', async t => { const { npm, joinedOutput } = await loadMockNpm(t, { prefixDir: workspaceFixture, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), + config: { + workspace: 'workspace-a', + }, }) - npm.config.set('workspace', ['workspace-a']) await registryPackage(t, npm.config.get('registry'), packageName) await npm.exec('owner', ['ls', packageName]) t.match(joinedOutput(), maintainers.map(m => `${m.name} <${m.email}>`).join('\n')) @@ -532,9 +528,7 @@ t.test('workspaces', async t => { t.test('owner add implicit workspace', async t => { const { npm, joinedOutput } = await loadMockNpm(t, { prefixDir: workspaceFixture, - globals: ({ prefix }) => ({ - 'process.cwd': () => path.join(prefix, 'workspace-a'), - }), + chdir: ({ prefix }) => path.join(prefix, 'workspace-a'), }) const username = 'foo' const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) @@ -563,8 +557,10 @@ t.test('workspaces', async t => { t.test('owner add --workspace', async t => { const { npm, joinedOutput } = await loadMockNpm(t, { prefixDir: workspaceFixture, + config: { + workspace: 'workspace-a', + }, }) - npm.config.set('workspace', ['workspace-a']) const username = 'foo' const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) @@ -592,9 +588,7 @@ t.test('workspaces', async t => { t.test('owner rm --workspace', async t => { const { npm, joinedOutput } = await loadMockNpm(t, { prefixDir: workspaceFixture, - globals: ({ prefix }) => ({ - 'process.cwd': () => path.join(prefix, 'workspace-a'), - }), + chdir: ({ prefix }) => path.join(prefix, 'workspace-a'), }) const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) diff --git a/deps/npm/test/lib/commands/pack.js b/deps/npm/test/lib/commands/pack.js index 199afc640f0353..3e7c0225c3068c 100644 --- a/deps/npm/test/lib/commands/pack.js +++ b/deps/npm/test/lib/commands/pack.js @@ -3,11 +3,6 @@ const { load: loadMockNpm } = require('../../fixtures/mock-npm') const path = require('path') const fs = require('fs') -const cwd = process.cwd() -t.afterEach(t => { - process.chdir(cwd) -}) - t.test('should pack current directory with no arguments', async t => { const { npm, outputs, logs } = await loadMockNpm(t, { prefixDir: { @@ -17,7 +12,6 @@ t.test('should pack current directory with no arguments', async t => { }), }, }) - process.chdir(npm.prefix) await npm.exec('pack', []) const filename = 'test-package-1.0.0.tgz' t.strictSame(outputs, [[filename]]) @@ -35,7 +29,6 @@ t.test('follows pack-destination config', async t => { 'tar-destination': {}, }, }) - process.chdir(npm.prefix) npm.config.set('pack-destination', path.join(npm.prefix, 'tar-destination')) await npm.exec('pack', []) const filename = 'test-package-1.0.0.tgz' @@ -52,7 +45,6 @@ t.test('should pack given directory for scoped package', async t => { }), }, }) - process.chdir(npm.prefix) await npm.exec('pack', []) const filename = 'npm-test-package-1.0.0.tgz' t.strictSame(outputs, [[filename]]) @@ -68,7 +60,6 @@ t.test('should log output as valid json', async t => { }), }, }) - process.chdir(npm.prefix) npm.config.set('json', true) await npm.exec('pack', []) const filename = 'test-package-1.0.0.tgz' @@ -86,7 +77,6 @@ t.test('should log scoped package output as valid json', async t => { }), }, }) - process.chdir(npm.prefix) npm.config.set('json', true) await npm.exec('pack', []) const filename = 'myscope-test-package-1.0.0.tgz' @@ -105,7 +95,6 @@ t.test('dry run', async t => { }, }) npm.config.set('dry-run', true) - process.chdir(npm.prefix) await npm.exec('pack', []) const filename = 'test-package-1.0.0.tgz' t.strictSame(outputs, [[filename]]) @@ -119,7 +108,6 @@ t.test('invalid packument', async t => { 'package.json': '{}', }, }) - process.chdir(npm.prefix) await t.rejects( npm.exec('pack', []), /Invalid package, must have name and version/ @@ -162,28 +150,24 @@ t.test('workspaces', async t => { t.test('all workspaces', async t => { const { npm, outputs } = await loadWorkspaces(t) - process.chdir(npm.prefix) await npm.exec('pack', []) t.strictSame(outputs, [['workspace-a-1.0.0.tgz'], ['workspace-b-1.0.0.tgz']]) }) t.test('all workspaces, `.` first arg', async t => { const { npm, outputs } = await loadWorkspaces(t) - process.chdir(npm.prefix) await npm.exec('pack', ['.']) t.strictSame(outputs, [['workspace-a-1.0.0.tgz'], ['workspace-b-1.0.0.tgz']]) }) t.test('one workspace', async t => { const { npm, outputs } = await loadWorkspaces(t) - process.chdir(npm.prefix) await npm.exec('pack', ['workspace-a']) t.strictSame(outputs, [['workspace-a-1.0.0.tgz']]) }) t.test('specific package', async t => { const { npm, outputs } = await loadWorkspaces(t) - process.chdir(npm.prefix) await npm.exec('pack', [npm.prefix]) t.strictSame(outputs, [['workspaces-test-1.0.0.tgz']]) }) diff --git a/deps/npm/test/lib/commands/pkg.js b/deps/npm/test/lib/commands/pkg.js index 49234e4cce3230..ef38d537308a53 100644 --- a/deps/npm/test/lib/commands/pkg.js +++ b/deps/npm/test/lib/commands/pkg.js @@ -1,76 +1,61 @@ const { resolve } = require('path') const { readFileSync } = require('fs') const t = require('tap') -const { fake: mockNpm } = require('../../fixtures/mock-npm') - -const redactCwd = (path) => { - const normalizePath = p => p - .replace(/\\+/g, '/') - .replace(/\r\n/g, '\n') - return normalizePath(path) - .replace(new RegExp(normalizePath(process.cwd()), 'g'), '{CWD}') -} +const _mockNpm = require('../../fixtures/mock-npm') +const { cleanCwd } = require('../../fixtures/clean-snapshot') -t.cleanSnapshot = (str) => redactCwd(str) +t.cleanSnapshot = (str) => cleanCwd(str) -let OUTPUT = '' -const config = { - global: false, - force: false, - 'pkg-cast': 'string', -} -const npm = mockNpm({ - localPrefix: t.testdirName, - config, - output: (str) => { - OUTPUT += str - }, -}) +const mockNpm = async (t, { ...opts } = {}) => { + const res = await _mockNpm(t, opts) -const Pkg = require('../../../lib/commands/pkg.js') -const pkg = new Pkg(npm) + const readPackageJson = (dir = '') => + JSON.parse(readFileSync(resolve(res.prefix, dir, 'package.json'), 'utf8')) -const readPackageJson = (path) => { - path = path || npm.localPrefix - return JSON.parse(readFileSync(resolve(path, 'package.json'), 'utf8')) + return { + ...res, + pkg: (...args) => res.npm.exec('pkg', args), + readPackageJson, + OUTPUT: () => res.joinedOutput(), + } } -t.afterEach(() => { - config.global = false - config.json = false - npm.localPrefix = t.testdirName - OUTPUT = '' -}) - t.test('no args', async t => { + const { pkg } = await mockNpm(t) + await t.rejects( - pkg.exec([]), + pkg(), { code: 'EUSAGE' }, 'should throw usage error' ) }) t.test('no global mode', async t => { - config.global = true + const { pkg } = await mockNpm(t, { + config: { global: true }, + }) + await t.rejects( - pkg.exec(['get', 'foo']), + pkg('get', 'foo'), { code: 'EPKGGLOBAL' }, 'should throw no global mode error' ) }) t.test('get no args', async t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.1.1', - }), + const { pkg, OUTPUT } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.1.1', + }), + }, }) - await pkg.exec(['get']) + await pkg('get') t.strictSame( - JSON.parse(OUTPUT), + JSON.parse(OUTPUT()), { name: 'foo', version: '1.1.1', @@ -80,37 +65,41 @@ t.test('get no args', async t => { }) t.test('get single arg', async t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.1.1', - }), + const { pkg, OUTPUT } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.1.1', + }), + }, }) - await pkg.exec(['get', 'version']) + await pkg('get', 'version') t.strictSame( - JSON.parse(OUTPUT), + JSON.parse(OUTPUT()), '1.1.1', 'should print retrieved package.json field' ) }) t.test('get nested arg', async t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.1.1', - scripts: { - test: 'node test.js', - }, - }), + const { pkg, OUTPUT } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.1.1', + scripts: { + test: 'node test.js', + }, + }), + }, }) - await pkg.exec(['get', 'scripts.test']) + await pkg('get', 'scripts.test') t.strictSame( - JSON.parse(OUTPUT), + JSON.parse(OUTPUT()), 'node test.js', 'should print retrieved nested field' ) @@ -121,18 +110,20 @@ t.test('get array field', async t => { 'index.js', 'cli.js', ] - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.1.1', - files, - }), + const { pkg, OUTPUT } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.1.1', + files, + }), + }, }) - await pkg.exec(['get', 'files']) + await pkg('get', 'files') t.strictSame( - JSON.parse(OUTPUT), + JSON.parse(OUTPUT()), files, 'should print retrieved array field' ) @@ -143,18 +134,20 @@ t.test('get array item', async t => { 'index.js', 'cli.js', ] - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.1.1', - files, - }), + const { pkg, OUTPUT } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.1.1', + files, + }), + }, }) - await pkg.exec(['get', 'files[0]']) + await pkg('get', 'files[0]') t.strictSame( - JSON.parse(OUTPUT), + JSON.parse(OUTPUT()), 'index.js', 'should print retrieved array field' ) @@ -171,17 +164,19 @@ t.test('get array nested items notation', async t => { url: 'http://example.com/gar', }, ] - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.1.1', - contributors, - }), + const { pkg, OUTPUT } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.1.1', + contributors, + }), + }, }) - await pkg.exec(['get', 'contributors.name']) + await pkg('get', 'contributors.name') t.strictSame( - JSON.parse(OUTPUT), + JSON.parse(OUTPUT()), { 'contributors[0].name': 'Ruy', 'contributors[1].name': 'Gar', @@ -191,33 +186,39 @@ t.test('get array nested items notation', async t => { }) t.test('set no args', async t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ name: 'foo' }), + const { pkg } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify({ name: 'foo' }), + }, }) await t.rejects( - pkg.exec(['set']), + pkg('set'), { code: 'EUSAGE' }, 'should throw an error if no args' ) }) t.test('set missing value', async t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ name: 'foo' }), + const { pkg } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify({ name: 'foo' }), + }, }) await t.rejects( - pkg.exec(['set', 'key=']), + pkg('set', 'key='), { code: 'EUSAGE' }, 'should throw an error if missing value' ) }) t.test('set missing key', async t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ name: 'foo' }), + const { pkg } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify({ name: 'foo' }), + }, }) await t.rejects( - pkg.exec(['set', '=value']), + pkg('set', '=value'), { code: 'EUSAGE' }, 'should throw an error if missing key' ) @@ -228,11 +229,13 @@ t.test('set single field', async t => { name: 'foo', version: '1.1.1', } - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify(json), + const { pkg, readPackageJson } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify(json), + }, }) - await pkg.exec(['set', 'description=Awesome stuff']) + await pkg('set', 'description=Awesome stuff') t.strictSame( readPackageJson(), { @@ -251,11 +254,13 @@ t.test('push to array syntax', async t => { 'foo', ], } - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify(json), + const { pkg, readPackageJson } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify(json), + }, }) - await pkg.exec(['set', 'keywords[]=bar', 'keywords[]=baz']) + await pkg('set', 'keywords[]=bar', 'keywords[]=baz') t.strictSame( readPackageJson(), { @@ -275,11 +280,13 @@ t.test('set multiple fields', async t => { name: 'foo', version: '1.1.1', } - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify(json), + const { pkg, readPackageJson } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify(json), + }, }) - await pkg.exec(['set', 'bin.foo=foo.js', 'scripts.test=node test.js']) + await pkg('set', 'bin.foo=foo.js', 'scripts.test=node test.js') t.strictSame( readPackageJson(), { @@ -300,11 +307,13 @@ t.test('set = separate value', async t => { name: 'foo', version: '1.1.1', } - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify(json), + const { pkg, readPackageJson } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify(json), + }, }) - await pkg.exec(['set', 'tap[test-env][0]=LC_ALL=sk']) + await pkg('set', 'tap[test-env][0]=LC_ALL=sk') t.strictSame( readPackageJson(), { @@ -320,15 +329,17 @@ t.test('set = separate value', async t => { }) t.test('set --json', async t => { - config.json = true - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.1.1', - }), + const { pkg, readPackageJson } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.1.1', + }), + }, + config: { json: true }, }) - await pkg.exec(['set', 'private=true']) + await pkg('set', 'private=true') t.strictSame( readPackageJson(), { @@ -339,7 +350,7 @@ t.test('set --json', async t => { 'should add boolean field to package.json' ) - await pkg.exec(['set', 'tap.timeout=60']) + await pkg('set', 'tap.timeout=60') t.strictSame( readPackageJson(), { @@ -353,7 +364,7 @@ t.test('set --json', async t => { 'should add number field to package.json' ) - await pkg.exec(['set', 'foo={ "bar": { "baz": "BAZ" } }']) + await pkg('set', 'foo={ "bar": { "baz": "BAZ" } }') t.strictSame( readPackageJson(), { @@ -372,7 +383,7 @@ t.test('set --json', async t => { 'should add object field to package.json' ) - await pkg.exec(['set', 'workspaces=["packages/*"]']) + await pkg('set', 'workspaces=["packages/*"]') t.strictSame( readPackageJson(), { @@ -394,7 +405,7 @@ t.test('set --json', async t => { 'should add object field to package.json' ) - await pkg.exec(['set', 'description="awesome"']) + await pkg('set', 'description="awesome"') t.strictSame( readPackageJson(), { @@ -419,35 +430,41 @@ t.test('set --json', async t => { }) t.test('delete no args', async t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ name: 'foo' }), + const { pkg } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify({ name: 'foo' }), + }, }) await t.rejects( - pkg.exec(['delete']), + pkg('delete'), { code: 'EUSAGE' }, 'should throw an error if deleting no args' ) }) t.test('delete invalid key', async t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ name: 'foo' }), + const { pkg } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify({ name: 'foo' }), + }, }) await t.rejects( - pkg.exec(['delete', '']), + pkg('delete', ''), { code: 'EUSAGE' }, 'should throw an error if deleting invalid args' ) }) t.test('delete single field', async t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.0.0', - }), + const { pkg, readPackageJson } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.0.0', + }), + }, }) - await pkg.exec(['delete', 'version']) + await pkg('delete', 'version') t.strictSame( readPackageJson(), { @@ -458,14 +475,16 @@ t.test('delete single field', async t => { }) t.test('delete multiple field', async t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.0.0', - description: 'awesome', - }), + const { pkg, readPackageJson } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.0.0', + description: 'awesome', + }), + }, }) - await pkg.exec(['delete', 'version', 'description']) + await pkg('delete', 'version', 'description') t.strictSame( readPackageJson(), { @@ -476,22 +495,24 @@ t.test('delete multiple field', async t => { }) t.test('delete nested field', async t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.0.0', - info: { - foo: { - bar: [ - { - baz: 'deleteme', - }, - ], + const { pkg, readPackageJson } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.0.0', + info: { + foo: { + bar: [ + { + baz: 'deleteme', + }, + ], + }, }, - }, - }), + }), + }, }) - await pkg.exec(['delete', 'info.foo.bar[0].baz']) + await pkg('delete', 'info.foo.bar[0].baz') t.strictSame( readPackageJson(), { @@ -510,34 +531,37 @@ t.test('delete nested field', async t => { }) t.test('workspaces', async t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'root', - version: '1.0.0', - workspaces: [ - 'packages/*', - ], - }), - packages: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'b', - version: '1.2.3', - }), + const { pkg, OUTPUT, readPackageJson } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'root', + version: '1.0.0', + workspaces: [ + 'packages/*', + ], + }), + packages: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + }), + }, + b: { + 'package.json': JSON.stringify({ + name: 'b', + version: '1.2.3', + }), + }, }, }, + config: { workspaces: true }, }) - await pkg.execWorkspaces(['get', 'name', 'version'], []) + await pkg('get', 'name', 'version') t.strictSame( - JSON.parse(OUTPUT), + JSON.parse(OUTPUT()), { a: { name: 'a', @@ -551,10 +575,10 @@ t.test('workspaces', async t => { 'should return expected result for configured workspaces' ) - await pkg.execWorkspaces(['set', 'funding=http://example.com'], []) + await pkg('set', 'funding=http://example.com') t.strictSame( - readPackageJson(resolve(npm.localPrefix, 'packages/a')), + readPackageJson('packages/a'), { name: 'a', version: '1.0.0', @@ -564,7 +588,7 @@ t.test('workspaces', async t => { ) t.strictSame( - readPackageJson(resolve(npm.localPrefix, 'packages/b')), + readPackageJson('packages/b'), { name: 'b', version: '1.2.3', @@ -573,9 +597,10 @@ t.test('workspaces', async t => { 'should add field to workspace b' ) - await pkg.execWorkspaces(['delete', 'version'], []) + await pkg('delete', 'version') + t.strictSame( - readPackageJson(resolve(npm.localPrefix, 'packages/a')), + readPackageJson('packages/a'), { name: 'a', funding: 'http://example.com', @@ -584,7 +609,7 @@ t.test('workspaces', async t => { ) t.strictSame( - readPackageJson(resolve(npm.localPrefix, 'packages/b')), + readPackageJson('packages/b'), { name: 'b', funding: 'http://example.com', diff --git a/deps/npm/test/lib/commands/profile.js b/deps/npm/test/lib/commands/profile.js index 09fd08cfc5329e..00ccf2607524ad 100644 --- a/deps/npm/test/lib/commands/profile.js +++ b/deps/npm/test/lib/commands/profile.js @@ -1,50 +1,45 @@ const t = require('tap') -const { fake: mockNpm } = require('../../fixtures/mock-npm') - -let result = '' -const config = { - otp: '', - json: false, - parseable: false, - registry: 'https://registry.npmjs.org/', -} -const flatOptions = { - registry: 'https://registry.npmjs.org/', -} -const npm = mockNpm({ - config, - flatOptions, - output: (...msg) => { - result = result ? `${result}\n${msg.join('\n')}` : msg.join('\n') - }, -}) -const mocks = { - npmlog: { - gauge: { show () {} }, - }, - 'proc-log': { - info () {}, - notice () {}, - warn () {}, - }, - 'npm-profile': { - async get () {}, - async set () {}, - async createToken () {}, - }, - 'qrcode-terminal': { generate: (url, cb) => cb() }, - 'cli-table3': class extends Array { - toString () { - return this.filter(Boolean) - .map(i => [...Object.entries(i)].map(i => i.join(': '))) - .join('\n') - } - }, - '../../../lib/utils/read-user-info.js': { - async password () {}, - async otp () {}, - }, +const mockNpm = require('../../fixtures/mock-npm') + +const mockProfile = async (t, { npmProfile, readUserInfo, qrcode, ...opts } = {}) => { + const mocks = { + 'npm-profile': npmProfile || { + async get () {}, + async set () {}, + async createToken () {}, + }, + 'qrcode-terminal': qrcode || { generate: (url, cb) => cb() }, + 'cli-table3': class extends Array { + toString () { + return this.filter(Boolean) + .map(i => [...Object.entries(i)].map(v => v.join(': '))) + .join('\n') + } + }, + '{LIB}/utils/read-user-info.js': readUserInfo || { + async password () {}, + async otp () {}, + }, + } + + const mock = await mockNpm(t, { + ...opts, + mocks: { + ...mocks, + ...opts.mocks, + }, + }) + + return { + ...mock, + result: () => mock.joinedOutput(), + profile: { + exec: (args) => mock.npm.exec('profile', args), + usage: () => mock.npm.cmd('profile').then(c => c.usage), + }, + } } + const userProfile = { tfa: { pending: false, mode: 'auth-and-writes' }, name: 'foo', @@ -60,53 +55,44 @@ const userProfile = { github: 'https://github.com/npm', } -t.afterEach(() => { - result = '' - flatOptions.otp = '' - config.json = false - config.parseable = false - config.registry = 'https://registry.npmjs.org/' -}) - -const Profile = t.mock('../../../lib/commands/profile.js', mocks) -const profile = new Profile(npm) - t.test('no args', async t => { - await t.rejects(profile.exec([]), profile.usage) + const { profile } = await mockProfile(t) + await t.rejects(profile.exec([]), await profile.usage()) }) -t.test('profile get no args', t => { - const npmProfile = { +t.test('profile get no args', async t => { + const defaultNpmProfile = { async get () { return userProfile }, } - const Profile = t.mock('../../../lib/commands/profile.js', { - ...mocks, - 'npm-profile': npmProfile, - }) - const profile = new Profile(npm) - t.test('default output', async t => { + const { profile, result } = await mockProfile(t, { npmProfile: defaultNpmProfile }) await profile.exec(['get']) - t.matchSnapshot(result, 'should output table with contents') + t.matchSnapshot(result(), 'should output table with contents') }) t.test('--json', async t => { - config.json = true + const { profile, result } = await mockProfile(t, { + npmProfile: defaultNpmProfile, + config: { json: true }, + }) await profile.exec(['get']) - t.same(JSON.parse(result), userProfile, 'should output json profile result') + t.same(JSON.parse(result()), userProfile, 'should output json profile result') }) t.test('--parseable', async t => { - config.parseable = true + const { profile, result } = await mockProfile(t, { + npmProfile: defaultNpmProfile, + config: { parseable: true }, + }) await profile.exec(['get']) - t.matchSnapshot(result, 'should output all profile info as parseable result') + t.matchSnapshot(result(), 'should output all profile info as parseable result') }) t.test('no tfa enabled', async t => { @@ -118,15 +104,10 @@ t.test('profile get no args', t => { } }, } - - const Profile = t.mock('../../../lib/commands/profile.js', { - ...mocks, - 'npm-profile': npmProfile, - }) - const profile = new Profile(npm) + const { profile, result } = await mockProfile(t, { npmProfile }) await profile.exec(['get']) - t.matchSnapshot(result, 'should output expected profile values') + t.matchSnapshot(result(), 'should output expected profile values') }) t.test('unverified email', async t => { @@ -139,15 +120,11 @@ t.test('profile get no args', t => { }, } - const Profile = t.mock('../../../lib/commands/profile.js', { - ...mocks, - 'npm-profile': npmProfile, - }) - const profile = new Profile(npm) + const { profile, result } = await mockProfile(t, { npmProfile }) await profile.exec(['get']) - t.matchSnapshot(result, 'should output table with contents') + t.matchSnapshot(result(), 'should output table with contents') }) t.test('profile has cidr_whitelist item', async t => { @@ -160,127 +137,111 @@ t.test('profile get no args', t => { }, } - const Profile = t.mock('../../../lib/commands/profile.js', { - ...mocks, - 'npm-profile': npmProfile, - }) - const profile = new Profile(npm) + const { profile, result } = await mockProfile(t, { npmProfile }) await profile.exec(['get']) - t.matchSnapshot(result, 'should output table with contents') + t.matchSnapshot(result(), 'should output table with contents') }) - - t.end() }) -t.test('profile get ', t => { +t.test('profile get ', async t => { const npmProfile = { async get () { return userProfile }, } - const Profile = t.mock('../../../lib/commands/profile.js', { - ...mocks, - 'npm-profile': npmProfile, - }) - const profile = new Profile(npm) - t.test('default output', async t => { + const { profile, result } = await mockProfile(t, { npmProfile }) + await profile.exec(['get', 'name']) - t.equal(result, 'foo', 'should output value result') + t.equal(result(), 'foo', 'should output value result') }) t.test('--json', async t => { - config.json = true + const { profile, result } = await mockProfile(t, { + npmProfile, + config: { json: true }, + }) await profile.exec(['get', 'name']) t.same( - JSON.parse(result), + JSON.parse(result()), userProfile, 'should output json profile result ignoring args filter' ) }) t.test('--parseable', async t => { - config.parseable = true + const { profile, result } = await mockProfile(t, { + npmProfile, + config: { parseable: true }, + }) await profile.exec(['get', 'name']) - t.matchSnapshot(result, 'should output parseable result value') + t.matchSnapshot(result(), 'should output parseable result value') }) - - t.end() }) -t.test('profile get multiple args', t => { +t.test('profile get multiple args', async t => { const npmProfile = { async get () { return userProfile }, } - const Profile = t.mock('../../../lib/commands/profile.js', { - ...mocks, - 'npm-profile': npmProfile, - }) - const profile = new Profile(npm) - t.test('default output', async t => { + const { profile, result } = await mockProfile(t, { + npmProfile, + }) await profile.exec(['get', 'name', 'email', 'github']) - t.matchSnapshot(result, 'should output all keys') + t.matchSnapshot(result(), 'should output all keys') }) t.test('--json', async t => { - config.json = true + const config = { json: true } + const { profile, result } = await mockProfile(t, { + npmProfile, + config, + }) await profile.exec(['get', 'name', 'email', 'github']) - t.same(JSON.parse(result), userProfile, 'should output json profile result and ignore args') + t.same(JSON.parse(result()), userProfile, 'should output json profile result and ignore args') }) t.test('--parseable', async t => { - config.parseable = true + const config = { parseable: true } + const { profile, result } = await mockProfile(t, { + npmProfile, + config, + }) await profile.exec(['get', 'name', 'email', 'github']) - t.matchSnapshot(result, 'should output parseable profile value results') + t.matchSnapshot(result(), 'should output parseable profile value results') }) t.test('comma separated', async t => { + const { profile, result } = await mockProfile(t, { + npmProfile, + }) + await profile.exec(['get', 'name,email,github']) - t.matchSnapshot(result, 'should output all keys') + t.matchSnapshot(result(), 'should output all keys') }) - - t.end() }) -t.test('profile set ', t => { - const npmProfile = t => ({ - async get () { - return userProfile - }, - async set (newUser, conf) { - t.match( - newUser, - { - fullname: 'Lorem Ipsum', - }, - 'should set new value to key' - ) - return { - ...userProfile, - ...newUser, - } - }, - }) - +t.test('profile set ', async t => { t.test('no key', async t => { + const { profile } = await mockProfile(t) + await t.rejects( profile.exec(['set']), /npm profile set /, @@ -289,6 +250,7 @@ t.test('profile set ', t => { }) t.test('no value', async t => { + const { profile } = await mockProfile(t) await t.rejects( profile.exec(['set', 'email']), /npm profile set /, @@ -297,6 +259,7 @@ t.test('profile set ', t => { }) t.test('set password', async t => { + const { profile } = await mockProfile(t) await t.rejects( profile.exec(['set', 'password', '1234']), /Do not include your current or new passwords on the command line./, @@ -305,6 +268,7 @@ t.test('profile set ', t => { }) t.test('unwritable key', async t => { + const { profile } = await mockProfile(t) await await t.rejects( profile.exec(['set', 'name', 'foo']), /"name" is not a property we can set./, @@ -312,35 +276,51 @@ t.test('profile set ', t => { ) }) - t.test('writable key', t => { + const defaultNpmProfile = t => ({ + async get () { + return userProfile + }, + async set (newUser) { + t.match( + newUser, + { + fullname: 'Lorem Ipsum', + }, + 'should set new value to key' + ) + return { + ...userProfile, + ...newUser, + } + }, + }) + + t.test('writable key', async t => { t.test('default output', async t => { t.plan(2) - const Profile = t.mock('../../../lib/commands/profile.js', { - ...mocks, - 'npm-profile': npmProfile(t), + const { profile, result } = await mockProfile(t, { + npmProfile: defaultNpmProfile(t), }) - const profile = new Profile(npm) await profile.exec(['set', 'fullname', 'Lorem Ipsum']) - t.equal(result, 'Set\nfullname\nto\nLorem Ipsum', 'should output set key success msg') + t.equal(result(), 'Set fullname to Lorem Ipsum', 'should output set key success msg') }) t.test('--json', async t => { t.plan(2) - config.json = true + const config = { json: true } - const Profile = t.mock('../../../lib/commands/profile.js', { - ...mocks, - 'npm-profile': npmProfile(t), + const { profile, result } = await mockProfile(t, { + npmProfile: defaultNpmProfile(t), + config, }) - const profile = new Profile(npm) await profile.exec(['set', 'fullname', 'Lorem Ipsum']) t.same( - JSON.parse(result), + JSON.parse(result()), { fullname: 'Lorem Ipsum', }, @@ -351,30 +331,26 @@ t.test('profile set ', t => { t.test('--parseable', async t => { t.plan(2) - config.parseable = true - - const Profile = t.mock('../../../lib/commands/profile.js', { - ...mocks, - 'npm-profile': npmProfile(t), + const config = { parseable: true } + const { profile, result } = await mockProfile(t, { + npmProfile: defaultNpmProfile(t), + config, }) - const profile = new Profile(npm) await profile.exec(['set', 'fullname', 'Lorem Ipsum']) - t.matchSnapshot(result, 'should output parseable set key success msg') + t.matchSnapshot(result(), 'should output parseable set key success msg') }) - - t.end() }) t.test('write new email', async t => { - t.plan(3) + t.plan(2) const npmProfile = { async get () { return userProfile }, - async set (newUser, conf) { + async set (newUser) { t.match( newUser, { @@ -382,7 +358,6 @@ t.test('profile set ', t => { }, 'should set new value to email' ) - t.match(conf, npm.flatOptions, 'should forward flatOptions config') return { ...userProfile, ...newUser, @@ -390,24 +365,22 @@ t.test('profile set ', t => { }, } - const Profile = t.mock('../../../lib/commands/profile.js', { - ...mocks, - 'npm-profile': npmProfile, + const { profile, result } = await mockProfile(t, { + npmProfile, }) - const profile = new Profile(npm) await profile.exec(['set', 'email', 'foo@npmjs.com']) - t.equal(result, 'Set\nemail\nto\nfoo@npmjs.com', 'should output set key success msg') + t.equal(result(), 'Set email to foo@npmjs.com', 'should output set key success msg') }) t.test('change password', async t => { - t.plan(6) + t.plan(5) const npmProfile = { async get () { return userProfile }, - async set (newUser, conf) { + async set (newUser) { t.match( newUser, { @@ -418,7 +391,6 @@ t.test('profile set ', t => { }, 'should set new password' ) - t.match(conf, npm.flatOptions, 'should forward flatOptions config') return { ...userProfile, } @@ -441,30 +413,27 @@ t.test('profile set ', t => { }, } - const Profile = t.mock('../../../lib/commands/profile.js', { - ...mocks, - 'npm-profile': npmProfile, - '../../../lib/utils/read-user-info.js': readUserInfo, + const { profile, result } = await mockProfile(t, { + npmProfile, + readUserInfo, }) - const profile = new Profile(npm) await profile.exec(['set', 'password']) - t.equal(result, 'Set\npassword', 'should output set password success msg') + t.equal(result(), 'Set password', 'should output set password success msg') }) t.test('password confirmation mismatch', async t => { - t.plan(3) + t.plan(2) + let passwordPromptCount = 0 const npmProfile = { async get () { return userProfile }, - async set (newUser, conf) { - return { - ...userProfile, - } + async set () { + return { ...userProfile } }, } @@ -485,38 +454,26 @@ t.test('profile set ', t => { }, } - const Profile = t.mock('../../../lib/commands/profile.js', { - ...mocks, - npmlog: { - gauge: { - show () {}, - }, - }, - 'proc-log': { - warn (title, msg) { - t.equal(title, 'profile', 'should use expected profile') - t.equal( - msg, - 'Passwords do not match, please try again.', - 'should log password mismatch message' - ) - }, - }, - 'npm-profile': npmProfile, - '../../../lib/utils/read-user-info.js': readUserInfo, + const { profile, result, logs } = await mockProfile(t, { + npmProfile, + readUserInfo, }) - const profile = new Profile(npm) await profile.exec(['set', 'password']) - t.equal(result, 'Set\npassword', 'should output set password success msg') - }) + t.equal( + logs.warn[0][1], + 'Passwords do not match, please try again.', + 'should log password mismatch message' + ) - t.end() + t.equal(result(), 'Set password', 'should output set password success msg') + }) }) -t.test('enable-2fa', t => { +t.test('enable-2fa', async t => { t.test('invalid args', async t => { + const { profile } = await mockProfile(t) await t.rejects( profile.exec(['enable-2fa', 'foo', 'bar']), /npm profile enable-2fa \[auth-and-writes|auth-only\]/, @@ -525,6 +482,7 @@ t.test('enable-2fa', t => { }) t.test('invalid two factor auth mode', async t => { + const { profile } = await mockProfile(t) await t.rejects( profile.exec(['enable-2fa', 'foo']), /Invalid two-factor authentication mode "foo"/, @@ -533,7 +491,8 @@ t.test('enable-2fa', t => { }) t.test('no support for --json output', async t => { - config.json = true + const config = { json: true } + const { profile } = await mockProfile(t, { config }) await t.rejects( profile.exec(['enable-2fa', 'auth-only']), @@ -544,7 +503,8 @@ t.test('enable-2fa', t => { }) t.test('no support for --parseable output', async t => { - config.parseable = true + const config = { parseable: true } + const { profile } = await mockProfile(t, { config }) await t.rejects( profile.exec(['enable-2fa', 'auth-only']), @@ -557,12 +517,6 @@ t.test('enable-2fa', t => { t.test('no bearer tokens returned by registry', async t => { t.plan(3) - // mock legacy basic auth style - npm.config.getCredentialsByURI = reg => { - t.equal(reg, flatOptions.registry, 'should use expected registry') - return { auth: Buffer.from('foo:bar').toString('base64') } - } - const npmProfile = { async createToken (pass) { t.match(pass, 'bar', 'should use password for basic auth') @@ -570,11 +524,16 @@ t.test('enable-2fa', t => { }, } - const Profile = t.mock('../../../lib/commands/profile.js', { - ...mocks, - 'npm-profile': npmProfile, + const { npm, profile } = await mockProfile(t, { + npmProfile, }) - const profile = new Profile(npm) + + // mock legacy basic auth style + // XXX: use mock registry + npm.config.getCredentialsByURI = reg => { + t.equal(reg, npm.flatOptions.registry, 'should use expected registry') + return { auth: Buffer.from('foo:bar').toString('base64') } + } await t.rejects( profile.exec(['enable-2fa', 'auth-only']), @@ -586,22 +545,21 @@ t.test('enable-2fa', t => { }) t.test('from basic username/password auth', async t => { - // mock legacy basic auth style with user/pass - npm.config.getCredentialsByURI = () => { - return { username: 'foo', password: 'bar' } - } - const npmProfile = { async createToken (pass) { return {} }, } - const Profile = t.mock('../../../lib/commands/profile.js', { - ...mocks, - 'npm-profile': npmProfile, + const { npm, profile } = await mockProfile(t, { + npmProfile, }) - const profile = new Profile(npm) + + // mock legacy basic auth style with user/pass + // XXX: use mock registry + npm.config.getCredentialsByURI = () => { + return { username: 'foo', password: 'bar' } + } await t.rejects( profile.exec(['enable-2fa', 'auth-only']), @@ -613,12 +571,10 @@ t.test('enable-2fa', t => { }) t.test('no auth found', async t => { - npm.config.getCredentialsByURI = () => ({}) + const { npm, profile } = await mockProfile(t) - const Profile = t.mock('../../../lib/commands/profile.js', { - ...mocks, - }) - const profile = new Profile(npm) + // XXX: use mock registry + npm.config.getCredentialsByURI = () => ({}) await t.rejects( profile.exec(['enable-2fa', 'auth-only']), @@ -627,20 +583,7 @@ t.test('enable-2fa', t => { }) t.test('from basic auth, asks for otp', async t => { - t.plan(10) - - // mock legacy basic auth style - npm.config.getCredentialsByURI = reg => { - t.equal(reg, flatOptions.registry, 'should use expected registry') - return { auth: Buffer.from('foo:bar').toString('base64') } - } - npm.config.setCredentialsByURI = (registry, { token }) => { - t.equal(registry, flatOptions.registry, 'should set expected registry') - t.equal(token, 'token', 'should set expected token') - } - npm.config.save = type => { - t.equal(type, 'user', 'should save to user config') - } + t.plan(9) const npmProfile = { async createToken (pass) { @@ -660,14 +603,6 @@ t.test('enable-2fa', t => { }, 'should set tfa mode' ) - t.match( - conf, - { - ...npm.flatOptions, - otp: '123456', - }, - 'should forward flatOptions config' - ) return { ...userProfile, tfa: null, @@ -690,16 +625,28 @@ t.test('enable-2fa', t => { }, } - const Profile = t.mock('../../../lib/commands/profile.js', { - ...mocks, - 'npm-profile': npmProfile, - '../../../lib/utils/read-user-info.js': readUserInfo, + const { npm, profile, result } = await mockProfile(t, { + npmProfile, + readUserInfo, }) - const profile = new Profile(npm) + + // mock legacy basic auth style + // XXX: use mock registry + npm.config.getCredentialsByURI = reg => { + t.equal(reg, npm.flatOptions.registry, 'should use expected registry') + return { auth: Buffer.from('foo:bar').toString('base64') } + } + npm.config.setCredentialsByURI = (registry, { token }) => { + t.equal(registry, npm.flatOptions.registry, 'should set expected registry') + t.equal(token, 'token', 'should set expected token') + } + npm.config.save = type => { + t.equal(type, 'user', 'should save to user config') + } await profile.exec(['enable-2fa', 'auth-only']) t.equal( - result, + result(), 'Two factor authentication mode changed to: auth-only', 'should output success msg' ) @@ -708,12 +655,6 @@ t.test('enable-2fa', t => { t.test('from token and set otp, retries on pending and verifies with qrcode', async t => { t.plan(4) - flatOptions.otp = '1234' - - npm.config.getCredentialsByURI = () => { - return { token: 'token' } - } - let setCount = 0 const npmProfile = { async get () { @@ -775,7 +716,7 @@ t.test('enable-2fa', t => { async password () { return 'password1234' }, - async otp (label) { + async otp () { return '123456' }, } @@ -785,26 +726,24 @@ t.test('enable-2fa', t => { generate: (url, cb) => cb('qrcode'), } - const Profile = t.mock('../../../lib/commands/profile.js', { - ...mocks, - 'npm-profile': npmProfile, - 'qrcode-terminal': qrcode, - '../../../lib/utils/read-user-info.js': readUserInfo, + const { npm, profile, result } = await mockProfile(t, { + npmProfile, + qrcode, + readUserInfo, + config: { otp: '1234' }, }) - const profile = new Profile(npm) + + // XXX: use mock registry + npm.config.getCredentialsByURI = () => { + return { token: 'token' } + } await profile.exec(['enable-2fa', 'auth-only']) - t.matchSnapshot(result, 'should output 2fa enablement success msgs') + t.matchSnapshot(result(), 'should output 2fa enablement success msgs') }) t.test('from token and set otp, retrieves invalid otp', async t => { - flatOptions.otp = '1234' - - npm.config.getCredentialsByURI = () => { - return { token: 'token' } - } - const npmProfile = { async get () { return { @@ -831,12 +770,15 @@ t.test('enable-2fa', t => { }, } - const Profile = t.mock('../../../lib/commands/profile.js', { - ...mocks, - 'npm-profile': npmProfile, - '../../../lib/utils/read-user-info.js': readUserInfo, + const { npm, profile } = await mockProfile(t, { + npmProfile, + readUserInfo, + config: { otp: '1234' }, }) - const profile = new Profile(npm) + + npm.config.getCredentialsByURI = () => { + return { token: 'token' } + } await t.rejects( profile.exec(['enable-2fa', 'auth-only']), @@ -846,13 +788,6 @@ t.test('enable-2fa', t => { }) t.test('from token auth provides --otp config arg', async t => { - flatOptions.otp = '123456' - flatOptions.otp = '123456' - - npm.config.getCredentialsByURI = reg => { - return { token: 'token' } - } - const npmProfile = { async get () { return userProfile @@ -874,27 +809,26 @@ t.test('enable-2fa', t => { }, } - const Profile = t.mock('../../../lib/commands/profile.js', { - ...mocks, - 'npm-profile': npmProfile, - '../../../lib/utils/read-user-info.js': readUserInfo, + const { npm, profile, result } = await mockProfile(t, { + npmProfile, + readUserInfo, + config: { otp: '123456' }, }) - const profile = new Profile(npm) + + npm.config.getCredentialsByURI = reg => { + return { token: 'token' } + } await profile.exec(['enable-2fa', 'auth-and-writes']) t.equal( - result, + result(), 'Two factor authentication mode changed to: auth-and-writes', 'should output success msg' ) }) t.test('missing tfa from user profile', async t => { - npm.config.getCredentialsByURI = reg => { - return { token: 'token' } - } - const npmProfile = { async get () { return { @@ -919,27 +853,25 @@ t.test('enable-2fa', t => { }, } - const Profile = t.mock('../../../lib/commands/profile.js', { - ...mocks, - 'npm-profile': npmProfile, - '../../../lib/utils/read-user-info.js': readUserInfo, + const { npm, profile, result } = await mockProfile(t, { + npmProfile, + readUserInfo, }) - const profile = new Profile(npm) + + npm.config.getCredentialsByURI = reg => { + return { token: 'token' } + } await profile.exec(['enable-2fa', 'auth-only']) t.equal( - result, + result(), 'Two factor authentication mode changed to: auth-only', 'should output success msg' ) }) t.test('defaults to auth-and-writes permission if no mode specified', async t => { - npm.config.getCredentialsByURI = reg => { - return { token: 'token' } - } - const npmProfile = { async get () { return { @@ -964,25 +896,25 @@ t.test('enable-2fa', t => { }, } - const Profile = t.mock('../../../lib/commands/profile.js', { - ...mocks, - 'npm-profile': npmProfile, - '../../../lib/utils/read-user-info.js': readUserInfo, + const { npm, profile, result } = await mockProfile(t, { + npmProfile, + readUserInfo, }) - const profile = new Profile(npm) + + npm.config.getCredentialsByURI = reg => { + return { token: 'token' } + } await profile.exec(['enable-2fa']) t.equal( - result, + result(), 'Two factor authentication mode changed to: auth-and-writes', 'should enable 2fa with auth-and-writes permission' ) }) - - t.end() }) -t.test('disable-2fa', t => { +t.test('disable-2fa', async t => { t.test('no tfa enabled', async t => { const npmProfile = { async get () { @@ -993,17 +925,16 @@ t.test('disable-2fa', t => { }, } - const Profile = t.mock('../../../lib/commands/profile.js', { - ...mocks, - 'npm-profile': npmProfile, + const { profile, result } = await mockProfile(t, { + npmProfile, }) - const profile = new Profile(npm) await profile.exec(['disable-2fa']) - t.equal(result, 'Two factor authentication not enabled.', 'should output already disalbed msg') + t.equal(result(), 'Two factor authentication not enabled.', + 'should output already disalbed msg') }) - t.test('requests otp', t => { + t.test('requests otp', async t => { const npmProfile = t => ({ async get () { return userProfile @@ -1019,14 +950,6 @@ t.test('disable-2fa', t => { }, 'should send the new info for setting in profile' ) - t.match( - conf, - { - ...npm.flatOptions, - otp: '1234', - }, - 'should forward flatOptions config' - ) }, }) @@ -1046,54 +969,52 @@ t.test('disable-2fa', t => { }) t.test('default output', async t => { - const Profile = t.mock('../../../lib/commands/profile.js', { - ...mocks, - 'npm-profile': npmProfile(t), - '../../../lib/utils/read-user-info.js': readUserInfo(t), + t.plan(4) + + const { profile, result } = await mockProfile(t, { + npmProfile: npmProfile(t), + readUserInfo: readUserInfo(t), }) - const profile = new Profile(npm) await profile.exec(['disable-2fa']) - t.equal(result, 'Two factor authentication disabled.', 'should output already disabled msg') + t.equal(result(), 'Two factor authentication disabled.', 'should output already disabled msg') }) t.test('--json', async t => { - config.json = true + t.plan(4) - const Profile = t.mock('../../../lib/commands/profile.js', { - ...mocks, - 'npm-profile': npmProfile(t), - '../../../lib/utils/read-user-info.js': readUserInfo(t), + const config = { json: true } + + const { profile, result } = await mockProfile(t, { + npmProfile: npmProfile(t), + readUserInfo: readUserInfo(t), + config, }) - const profile = new Profile(npm) await profile.exec(['disable-2fa']) - t.same(JSON.parse(result), { tfa: false }, 'should output json already disabled msg') + t.same(JSON.parse(result()), { tfa: false }, 'should output json already disabled msg') }) t.test('--parseable', async t => { - config.parseable = true + t.plan(4) + + const config = { parseable: true } - const Profile = t.mock('../../../lib/commands/profile.js', { - ...mocks, - 'npm-profile': npmProfile(t), - '../../../lib/utils/read-user-info.js': readUserInfo(t), + const { profile, result } = await mockProfile(t, { + npmProfile: npmProfile(t), + readUserInfo: readUserInfo(t), + config, }) - const profile = new Profile(npm) await profile.exec(['disable-2fa']) - t.equal(result, 'tfa\tfalse', 'should output parseable already disabled msg') + t.equal(result(), 'tfa\tfalse', 'should output parseable already disabled msg') }) - - t.end() }) t.test('--otp config already set', async t => { - t.plan(3) - - flatOptions.otp = '123456' + t.plan(2) const npmProfile = { async get () { @@ -1110,14 +1031,6 @@ t.test('disable-2fa', t => { }, 'should send the new info for setting in profile' ) - t.match( - conf, - { - ...npm.flatOptions, - otp: '123456', - }, - 'should forward flatOptions config' - ) }, } @@ -1130,22 +1043,21 @@ t.test('disable-2fa', t => { }, } - const Profile = t.mock('../../../lib/commands/profile.js', { - ...mocks, - 'npm-profile': npmProfile, - '../../../lib/utils/read-user-info.js': readUserInfo, + const { profile, result } = await mockProfile(t, { + npmProfile, + readUserInfo, + config: { otp: '123456' }, }) - const profile = new Profile(npm) await profile.exec(['disable-2fa']) - t.equal(result, 'Two factor authentication disabled.', 'should output already disalbed msg') + t.equal(result(), 'Two factor authentication disabled.', 'should output already disalbed msg') }) - - t.end() }) t.test('unknown subcommand', async t => { + const { profile } = await mockProfile(t) + await t.rejects( profile.exec(['asfd']), /Unknown profile command: asfd/, @@ -1153,55 +1065,47 @@ t.test('unknown subcommand', async t => { ) }) -t.test('completion', t => { - const testComp = async ({ t, argv, expect, title }) => { +t.test('completion', async t => { + const testComp = async (t, { argv, expect, title } = {}) => { + const { npm } = await mockProfile(t) + const profile = await npm.cmd('profile') t.resolveMatch(profile.completion({ conf: { argv: { remain: argv } } }), expect, title) } t.test('npm profile autocomplete', async t => { - await testComp({ - t, + await testComp(t, { argv: ['npm', 'profile'], expect: ['enable-2fa', 'disable-2fa', 'get', 'set'], title: 'should auto complete with subcommands', }) - - t.end() }) t.test('npm profile enable autocomplete', async t => { - await testComp({ - t, + await testComp(t, { argv: ['npm', 'profile', 'enable-2fa'], expect: ['auth-and-writes', 'auth-only'], title: 'should auto complete with auth types', }) - - t.end() }) t.test('npm profile no autocomplete', async t => { const noAutocompleteCmds = ['disable-2fa', 'disable-tfa', 'get', 'set'] for (const subcmd of noAutocompleteCmds) { - await testComp({ - t, + await t.test(subcmd, t => testComp(t, { argv: ['npm', 'profile', subcmd], expect: [], title: `${subcmd} should have no autocomplete`, - }) + })) } - - t.end() }) t.test('npm profile unknown subcommand autocomplete', async t => { + const { npm } = await mockProfile(t) + const profile = await npm.cmd('profile') t.rejects( profile.completion({ conf: { argv: { remain: ['npm', 'profile', 'asdf'] } } }), { message: 'asdf not recognized' }, 'should throw unknown cmd error' ) - t.end() }) - - t.end() }) diff --git a/deps/npm/test/lib/commands/prune.js b/deps/npm/test/lib/commands/prune.js index a7f56547b105db..81245bcfca1671 100644 --- a/deps/npm/test/lib/commands/prune.js +++ b/deps/npm/test/lib/commands/prune.js @@ -13,7 +13,7 @@ t.test('should prune using Arborist', async (t) => { t.ok(true, 'prune is called') } }, - '../../lib/utils/reify-finish.js': (arb) => { + '{LIB}/utils/reify-finish.js': (arb) => { t.ok(arb, 'gets arborist tree') }, }, diff --git a/deps/npm/test/lib/commands/publish.js b/deps/npm/test/lib/commands/publish.js index 496c02394eb171..39696066130f9b 100644 --- a/deps/npm/test/lib/commands/publish.js +++ b/deps/npm/test/lib/commands/publish.js @@ -44,9 +44,6 @@ t.test('respects publishConfig.registry, runs appropriate scripts', async t => { publishConfig: { registry: alternateRegistry }, }, null, 2), }, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), }) const registry = new MockRegistry({ tap: t, @@ -103,9 +100,6 @@ t.test('re-loads publishConfig.registry if added during script process', async t publishConfig: { registry: alternateRegistry }, }), }, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), }) const registry = new MockRegistry({ tap: t, @@ -150,9 +144,6 @@ t.test('json', async t => { prefixDir: { 'package.json': JSON.stringify(pkgJson, null, 2), }, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), }) const registry = new MockRegistry({ tap: t, @@ -174,9 +165,6 @@ t.test('dry-run', async t => { prefixDir: { 'package.json': JSON.stringify(pkgJson, null, 2), }, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), }) await npm.exec('publish', []) t.equal(joinedOutput(), `+ ${pkg}@1.0.0`) @@ -184,10 +172,8 @@ t.test('dry-run', async t => { }) t.test('shows usage with wrong set of arguments', async t => { - t.plan(1) - const Publish = t.mock('../../../lib/commands/publish.js') - const publish = new Publish({ config: { validate: () => {} } }) - + const { npm } = await loadMockNpm(t) + const publish = await npm.cmd('publish') await t.rejects(publish.exec(['a', 'b', 'c']), publish.usage) }) @@ -199,9 +185,6 @@ t.test('throws when invalid tag', async t => { prefixDir: { 'package.json': JSON.stringify(pkgJson, null, 2), }, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), }) await t.rejects( npm.exec('publish', []), @@ -247,9 +230,6 @@ t.test('no auth default registry', async t => { prefixDir: { 'package.json': JSON.stringify(pkgJson, null, 2), }, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), }) await t.rejects( npm.exec('publish', []), @@ -268,9 +248,6 @@ t.test('no auth dry-run', async t => { prefixDir: { 'package.json': JSON.stringify(pkgJson, null, 2), }, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), }) await npm.exec('publish', []) t.matchSnapshot(joinedOutput()) @@ -286,9 +263,6 @@ t.test('no auth for configured registry', async t => { prefixDir: { 'package.json': JSON.stringify(pkgJson, null, 2), }, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), }) await t.rejects( npm.exec('publish', []), @@ -302,7 +276,8 @@ t.test('no auth for configured registry', async t => { t.test('no auth for scope configured registry', async t => { const { npm } = await loadMockNpm(t, { config: { - '@npm:registry': alternateRegistry, + scope: '@npm', + registry: alternateRegistry, ...auth, }, prefixDir: { @@ -311,9 +286,6 @@ t.test('no auth for scope configured registry', async t => { version: '1.0.0', }, null, 2), }, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), }) await t.rejects( npm.exec('publish', []), @@ -328,7 +300,8 @@ t.test('has token auth for scope configured registry', async t => { const spec = npa('@npm/test-package') const { npm, joinedOutput } = await loadMockNpm(t, { config: { - '@npm:registry': alternateRegistry, + scope: '@npm', + registry: alternateRegistry, [`${alternateRegistry.slice(6)}/:_authToken`]: 'test-scope-token', }, prefixDir: { @@ -337,9 +310,6 @@ t.test('has token auth for scope configured registry', async t => { version: '1.0.0', }, null, 2), }, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), }) const registry = new MockRegistry({ tap: t, @@ -357,7 +327,8 @@ t.test('has mTLS auth for scope configured registry', async t => { const spec = npa('@npm/test-package') const { npm, joinedOutput } = await loadMockNpm(t, { config: { - '@npm:registry': alternateRegistry, + scope: '@npm', + registry: alternateRegistry, [`${alternateRegistry.slice(6)}/:certfile`]: '/some.cert', [`${alternateRegistry.slice(6)}/:keyfile`]: '/some.key', }, @@ -367,9 +338,6 @@ t.test('has mTLS auth for scope configured registry', async t => { version: '1.0.0', }, null, 2), }, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), }) const registry = new MockRegistry({ tap: t, @@ -425,9 +393,6 @@ t.test('workspaces', t => { ...auth, workspaces: true, }, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), prefixDir: dir, }) const registry = new MockRegistry({ @@ -457,9 +422,6 @@ t.test('workspaces', t => { color: 'always', workspaces: true, }, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), prefixDir: dir, }) const registry = new MockRegistry({ @@ -488,9 +450,6 @@ t.test('workspaces', t => { ...auth, workspace: ['workspace-a'], }, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), prefixDir: dir, }) const registry = new MockRegistry({ @@ -512,9 +471,6 @@ t.test('workspaces', t => { ...auth, workspace: ['workspace-a'], }, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), prefixDir: dir, }) const registry = new MockRegistry({ @@ -535,9 +491,6 @@ t.test('workspaces', t => { ...auth, workspace: ['workspace-x'], }, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), prefixDir: dir, }) await t.rejects( @@ -553,9 +506,6 @@ t.test('workspaces', t => { workspaces: true, json: true, }, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), prefixDir: dir, }) const registry = new MockRegistry({ @@ -596,9 +546,6 @@ t.test('ignore-scripts', async t => { }, }, null, 2), }, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), }) const registry = new MockRegistry({ tap: t, @@ -638,9 +585,6 @@ t.test('_auth config default registry', async t => { prefixDir: { 'package.json': JSON.stringify(pkgJson), }, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), }) const registry = new MockRegistry({ tap: t, @@ -665,9 +609,6 @@ t.test('bare _auth and registry config', async t => { version: '1.0.0', }, null, 2), }, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), }) const registry = new MockRegistry({ tap: t, @@ -682,7 +623,8 @@ t.test('bare _auth and registry config', async t => { t.test('bare _auth config scoped registry', async t => { const { npm } = await loadMockNpm(t, { config: { - '@npm:registry': alternateRegistry, + scope: '@npm', + registry: alternateRegistry, _auth: basic, }, prefixDir: { @@ -691,9 +633,6 @@ t.test('bare _auth config scoped registry', async t => { version: '1.0.0', }, null, 2), }, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), }) await t.rejects( npm.exec('publish', []), @@ -705,7 +644,8 @@ t.test('scoped _auth config scoped registry', async t => { const spec = npa('@npm/test-package') const { npm, joinedOutput } = await loadMockNpm(t, { config: { - '@npm:registry': alternateRegistry, + scope: '@npm', + registry: alternateRegistry, [`${alternateRegistry.slice(6)}/:_auth`]: basic, }, prefixDir: { @@ -714,9 +654,6 @@ t.test('scoped _auth config scoped registry', async t => { version: '1.0.0', }, null, 2), }, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), }) const registry = new MockRegistry({ tap: t, @@ -741,9 +678,6 @@ t.test('restricted access', async t => { version: '1.0.0', }, null, 2), }, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), }) const registry = new MockRegistry({ tap: t, @@ -772,9 +706,6 @@ t.test('public access', async t => { version: '1.0.0', }, null, 2), }, - globals: ({ prefix }) => ({ - 'process.cwd': () => prefix, - }), }) const registry = new MockRegistry({ tap: t, diff --git a/deps/npm/test/lib/commands/query.js b/deps/npm/test/lib/commands/query.js index fb5b4843c34ee7..2b9a5b49763235 100644 --- a/deps/npm/test/lib/commands/query.js +++ b/deps/npm/test/lib/commands/query.js @@ -1,15 +1,8 @@ const t = require('tap') const { load: loadMockNpm } = require('../../fixtures/mock-npm') +const { cleanCwd } = require('../../fixtures/clean-snapshot.js') -t.cleanSnapshot = (str) => { - const normalizePath = p => p - .replace(/\\+/g, '/') - .replace(/\r\n/g, '\n') - return normalizePath(str) - .replace(new RegExp(normalizePath(process.cwd()), 'g'), '{CWD}') - // normalize between windows and posix - .replace(new RegExp('lib/node_modules', 'g'), 'node_modules') -} +t.cleanSnapshot = (str) => cleanCwd(str) t.test('simple query', async t => { const { npm, joinedOutput } = await loadMockNpm(t, { @@ -71,7 +64,7 @@ t.test('recursive tree', async t => { t.test('workspace query', async t => { const { npm, joinedOutput } = await loadMockNpm(t, { config: { - workspaces: ['c'], + workspace: ['c'], }, prefixDir: { node_modules: { @@ -101,7 +94,7 @@ t.test('workspace query', async t => { }), }, }) - await npm.exec('query', [':scope'], ['c']) + await npm.exec('query', [':scope']) t.matchSnapshot(joinedOutput(), 'should return workspace object') }) @@ -109,7 +102,7 @@ t.test('include-workspace-root', async t => { const { npm, joinedOutput } = await loadMockNpm(t, { config: { 'include-workspace-root': true, - workspaces: ['c'], + workspace: ['c'], }, prefixDir: { node_modules: { @@ -139,7 +132,7 @@ t.test('include-workspace-root', async t => { }), }, }) - await npm.exec('query', [':scope'], ['c']) + await npm.exec('query', [':scope']) t.matchSnapshot(joinedOutput(), 'should return workspace object and root object') }) t.test('linked node', async t => { @@ -171,8 +164,6 @@ t.test('global', async t => { config: { global: true, }, - // This is a global dir that works in both windows and non-windows, that's - // why it has two node_modules folders globalPrefixDir: { node_modules: { lorem: { @@ -182,16 +173,7 @@ t.test('global', async t => { }), }, }, - lib: { - node_modules: { - lorem: { - 'package.json': JSON.stringify({ - name: 'lorem', - version: '2.0.0', - }), - }, - }, - }, + }, }) await npm.exec('query', ['[name=lorem]']) diff --git a/deps/npm/test/lib/commands/rebuild.js b/deps/npm/test/lib/commands/rebuild.js index 3bfd3707f588c7..bda161772ddfc5 100644 --- a/deps/npm/test/lib/commands/rebuild.js +++ b/deps/npm/test/lib/commands/rebuild.js @@ -1,53 +1,32 @@ const t = require('tap') const fs = require('fs') const { resolve } = require('path') -const { fake: mockNpm } = require('../../fixtures/mock-npm') - -let result = '' - -const config = { - global: false, -} -const npm = mockNpm({ - globalDir: '', - config, - prefix: '', - output: (...msg) => { - result += msg.join('\n') - }, -}) -const Rebuild = require('../../../lib/commands/rebuild.js') -const rebuild = new Rebuild(npm) - -t.afterEach(() => { - npm.prefix = '' - config.global = false - npm.globalDir = '' - result = '' -}) +const setupMockNpm = require('../../fixtures/mock-npm') t.test('no args', async t => { - const path = t.testdir({ - node_modules: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - bin: 'cwd', - scripts: { - preinstall: "node -e \"require('fs').writeFileSync('cwd', '')\"", - }, - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'b', - version: '1.0.0', - bin: 'cwd', - scripts: { - preinstall: "node -e \"require('fs').writeFileSync('cwd', '')\"", - }, - }), + const { npm, joinedOutput, prefix: path } = await setupMockNpm(t, { + prefixDir: { + node_modules: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + bin: 'cwd', + scripts: { + preinstall: "node -e \"require('fs').writeFileSync('cwd', '')\"", + }, + }), + }, + b: { + 'package.json': JSON.stringify({ + name: 'b', + version: '1.0.0', + bin: 'cwd', + scripts: { + preinstall: "node -e \"require('fs').writeFileSync('cwd', '')\"", + }, + }), + }, }, }, }) @@ -61,9 +40,7 @@ t.test('no args', async t => { t.throws(() => fs.statSync(aBinFile)) t.throws(() => fs.statSync(bBinFile)) - npm.prefix = path - - await rebuild.exec([]) + await npm.exec('rebuild', []) t.ok(() => fs.statSync(aBuildFile)) t.ok(() => fs.statSync(bBuildFile)) @@ -71,136 +48,141 @@ t.test('no args', async t => { t.ok(() => fs.statSync(bBinFile)) t.equal( - result, + joinedOutput(), 'rebuilt dependencies successfully', 'should output success msg' ) }) t.test('filter by pkg name', async t => { - const path = t.testdir({ - node_modules: { - a: { - 'index.js': '', - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - bin: 'index.js', - }), - }, - b: { - 'index.js': '', - 'package.json': JSON.stringify({ - name: 'b', - version: '1.0.0', - bin: 'index.js', - }), + const { npm, prefix: path } = await setupMockNpm(t, { + prefixDir: { + node_modules: { + a: { + 'index.js': '', + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + bin: 'index.js', + }), + }, + b: { + 'index.js': '', + 'package.json': JSON.stringify({ + name: 'b', + version: '1.0.0', + bin: 'index.js', + }), + }, }, }, }) - npm.prefix = path - const aBinFile = resolve(path, 'node_modules/.bin/a') const bBinFile = resolve(path, 'node_modules/.bin/b') t.throws(() => fs.statSync(aBinFile)) t.throws(() => fs.statSync(bBinFile)) - await rebuild.exec(['b']) + await npm.exec('rebuild', ['b']) t.throws(() => fs.statSync(aBinFile), 'should not link a bin') t.ok(() => fs.statSync(bBinFile), 'should link filtered pkg bin') }) t.test('filter by pkg@', async t => { - const path = t.testdir({ - node_modules: { - a: { - 'index.js': '', - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - bin: 'index.js', - }), - node_modules: { - b: { - 'index.js': '', - 'package.json': JSON.stringify({ - name: 'b', - version: '2.0.0', - bin: 'index.js', - }), + const { npm, prefix: path } = await setupMockNpm(t, { + prefixDir: { + node_modules: { + a: { + 'index.js': '', + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + bin: 'index.js', + }), + node_modules: { + b: { + 'index.js': '', + 'package.json': JSON.stringify({ + name: 'b', + version: '2.0.0', + bin: 'index.js', + }), + }, }, }, - }, - b: { - 'index.js': '', - 'package.json': JSON.stringify({ - name: 'b', - version: '1.0.0', - bin: 'index.js', - }), + b: { + 'index.js': '', + 'package.json': JSON.stringify({ + name: 'b', + version: '1.0.0', + bin: 'index.js', + }), + }, }, }, }) - npm.prefix = path - const bBinFile = resolve(path, 'node_modules/.bin/b') const nestedBinFile = resolve(path, 'node_modules/a/node_modules/.bin/b') - await rebuild.exec(['b@2']) + await npm.exec('rebuild', ['b@2']) t.throws(() => fs.statSync(bBinFile), 'should not link b bin') t.ok(() => fs.statSync(nestedBinFile), 'should link filtered pkg bin') }) t.test('filter by directory', async t => { - const path = t.testdir({ - node_modules: { - a: { - 'index.js': '', - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - bin: 'index.js', - }), - }, - b: { - 'index.js': '', - 'package.json': JSON.stringify({ - name: 'b', - version: '1.0.0', - bin: 'index.js', - }), + const { npm, prefix: path } = await setupMockNpm(t, { + prefixDir: { + node_modules: { + a: { + 'index.js': '', + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + bin: 'index.js', + }), + }, + b: { + 'index.js': '', + 'package.json': JSON.stringify({ + name: 'b', + version: '1.0.0', + bin: 'index.js', + }), + }, }, }, }) - npm.prefix = path - const aBinFile = resolve(path, 'node_modules/.bin/a') const bBinFile = resolve(path, 'node_modules/.bin/b') t.throws(() => fs.statSync(aBinFile)) t.throws(() => fs.statSync(bBinFile)) - await rebuild.exec(['file:node_modules/b']) + await npm.exec('rebuild', ['file:node_modules/b']) t.throws(() => fs.statSync(aBinFile), 'should not link a bin') t.ok(() => fs.statSync(bBinFile), 'should link filtered pkg bin') }) t.test('filter must be a semver version/range, or directory', async t => { + const { npm } = await setupMockNpm(t) + await t.rejects( - rebuild.exec(['git+ssh://github.com/npm/arborist']), + npm.exec('rebuild', ['git+ssh://github.com/npm/arborist']), /`npm rebuild` only supports SemVer version\/range specifiers/, 'should throw type error' ) }) t.test('global prefix', async t => { - const globalPath = t.testdir({ - lib: { + const { npm, globalPrefix, joinedOutput } = await setupMockNpm(t, { + config: { + global: true, + }, + globalPrefixDir: { node_modules: { a: { 'index.js': '', @@ -214,14 +196,11 @@ t.test('global prefix', async t => { }, }) - config.global = true - npm.globalDir = resolve(globalPath, 'lib', 'node_modules') - - await rebuild.exec([]) - t.ok(() => fs.statSync(resolve(globalPath, 'lib/node_modules/.bin/a'))) + await npm.exec('rebuild', []) + t.ok(() => fs.statSync(resolve(globalPrefix, 'lib/node_modules/.bin/a'))) t.equal( - result, + joinedOutput(), 'rebuilt dependencies successfully', 'should output success msg' ) diff --git a/deps/npm/test/lib/commands/repo.js b/deps/npm/test/lib/commands/repo.js index 86f1b8e27411f8..114cdf919510af 100644 --- a/deps/npm/test/lib/commands/repo.js +++ b/deps/npm/test/lib/commands/repo.js @@ -1,5 +1,5 @@ const t = require('tap') -const { load: _loadMockNpm } = require('../../fixtures/mock-npm.js') +const mockNpm = require('../../fixtures/mock-npm.js') const { sep } = require('path') const fixture = { @@ -180,24 +180,30 @@ const workspaceFixture = { }), } -// keep a tally of which urls got opened -let opened = {} -const openUrl = async (npm, url, errMsg) => { - opened[url] = opened[url] || 0 - opened[url]++ -} -t.afterEach(() => opened = {}) +const loadMockNpm = async (t, prefixDir, config = {}) => { + // keep a tally of which urls got opened + const opened = {} -const loadMockNpm = async (t, prefixDir) => { - const res = await _loadMockNpm(t, { - mocks: { '../../lib/utils/open-url.js': openUrl }, + const mock = await mockNpm(t, { + command: 'repo', + mocks: { + '{LIB}/utils/open-url.js': async (_, url) => { + opened[url] = opened[url] || 0 + opened[url]++ + }, + }, + config, prefixDir, }) - return res + + return { + ...mock, + opened, + } } t.test('open repo urls', async t => { - const { npm } = await loadMockNpm(t, fixture) + const { repo, opened } = await loadMockNpm(t, fixture) const expect = { hostedgit: 'https://github.com/foo/hostedgit', hostedgitat: 'https://github.com/foo/hostedgitat', @@ -224,22 +230,14 @@ t.test('open repo urls', async t => { directory: 'https://github.com/foo/test-repo-with-directory/tree/HEAD/some/directory', '.': 'https://example.com/thispkg', } - const keys = Object.keys(expect) - t.plan(keys.length) - keys.forEach(pkg => { - t.test(pkg, async t => { - await npm.exec('repo', [['.', pkg].join(sep)]) - const url = expect[pkg] - t.match({ - [url]: 1, - }, opened, `opened ${url}`, { opened }) - t.end() - }) - }) + for (const [pkg, url] of Object.entries(expect)) { + await repo.exec([['.', pkg].join(sep)]) + t.equal(opened[url], 1, `opened ${url}`) + } }) t.test('fail if cannot figure out repo url', async t => { - const { npm } = await loadMockNpm(t, fixture) + const { repo } = await loadMockNpm(t, fixture) const cases = [ 'norepo', @@ -248,37 +246,29 @@ t.test('fail if cannot figure out repo url', async t => { 'unhostedgitatobj', ] - t.plan(cases.length) - - cases.forEach(pkg => { - t.test(pkg, async t => { - t.rejects( - npm.exec('repo', [['.', pkg].join(sep)]), - { pkgid: pkg } - ) - }) - }) + for (const pkg of cases) { + await t.rejects( + repo.exec([['.', pkg].join(sep)]), + { pkgid: pkg } + ) + } }) t.test('open default package if none specified', async t => { - const { npm } = await loadMockNpm(t, fixture) - await npm.exec('repo', []) + const { repo, opened } = await loadMockNpm(t, fixture) + await repo.exec([]) t.equal(opened['https://example.com/thispkg'], 1, 'opened expected url', { opened }) }) t.test('workspaces', async t => { - const { npm } = await loadMockNpm(t, workspaceFixture) - - t.afterEach(() => { - npm.config.set('workspaces', null) - npm.config.set('workspace', []) - npm.config.set('include-workspace-root', false) - }) + const mockWorkspaces = (t, config) => loadMockNpm(t, workspaceFixture, config) t.test('include workspace root', async (t) => { - npm.config.set('workspaces', true) - npm.config.set('include-workspace-root', true) - await npm.exec('repo', []) + const { opened, repo } = await mockWorkspaces(t, { + workspaces: true, + 'include-workspace-root': true, + }) + await repo.exec([]) t.match({ 'https://github.com/npm/workspaces-test': 1, 'https://repo.workspace-a/': 1, // Gets translated to https! @@ -287,8 +277,10 @@ t.test('workspaces', async t => { }) t.test('all workspaces', async (t) => { - npm.config.set('workspaces', true) - await npm.exec('repo', []) + const { opened, repo } = await mockWorkspaces(t, { + workspaces: true, + }) + await repo.exec([]) t.match({ 'https://repo.workspace-a/': 1, // Gets translated to https! 'https://github.com/npm/workspace-b': 1, @@ -296,25 +288,31 @@ t.test('workspaces', async t => { }) t.test('one workspace', async (t) => { - npm.config.set('workspace', ['workspace-a']) - await npm.exec('repo', []) + const { opened, repo } = await mockWorkspaces(t, { + workspace: ['workspace-a'], + }) + await repo.exec([]) t.match({ 'https://repo.workspace-a/': 1, }, opened, 'opened one requested repo urls') }) t.test('invalid workspace', async (t) => { - npm.config.set('workspace', ['workspace-x']) + const { opened, repo } = await mockWorkspaces(t, { + workspace: ['workspace-x'], + }) await t.rejects( - npm.exec('repo', []), + repo.exec([]), /workspace-x/ ) t.match({}, opened, 'opened no repo urls') }) t.test('package arg and workspace', async (t) => { - npm.config.set('workspace', ['workspace-a']) - await npm.exec('repo', ['.']) + const { opened, repo } = await mockWorkspaces(t, { + workspace: ['workspace-x'], + }) + await repo.exec(['.']) t.match({ 'https://github.com/npm/workspaces-test': 1, }, opened, 'opened url for package arg, not workspace') diff --git a/deps/npm/test/lib/commands/restart.js b/deps/npm/test/lib/commands/restart.js index f9745acdd11b7d..b8b760675f7c5e 100644 --- a/deps/npm/test/lib/commands/restart.js +++ b/deps/npm/test/lib/commands/restart.js @@ -19,11 +19,11 @@ t.test('should run restart script from package.json', async t => { }, config: { loglevel: 'silent', - scriptShell: process.platform === 'win32' ? process.env.COMSPEC : 'sh', + 'script-shell': process.platform === 'win32' ? process.env.COMSPEC : 'sh', }, }) - const scriptShell = npm.config.get('scriptShell') + const scriptShell = npm.config.get('script-shell') const scriptArgs = isCmdRe.test(scriptShell) ? ['/d', '/s', '/c', 'node ./test-restart.js foo'] : ['-c', 'node ./test-restart.js foo'] diff --git a/deps/npm/test/lib/commands/run-script.js b/deps/npm/test/lib/commands/run-script.js index 8aafebcaf8d110..a265db3cc040da 100644 --- a/deps/npm/test/lib/commands/run-script.js +++ b/deps/npm/test/lib/commands/run-script.js @@ -1,125 +1,84 @@ const t = require('tap') const { resolve } = require('path') -const { fake: mockNpm } = require('../../fixtures/mock-npm') - -const normalizePath = p => p.replace(/\\+/g, '/').replace(/\r\n/g, '\n') - -const cleanOutput = str => normalizePath(str).replace(normalizePath(process.cwd()), '{CWD}') - -const RUN_SCRIPTS = [] -const flatOptions = { - scriptShell: undefined, -} -const defaultLoglevel = 'info' -const config = { - json: false, - parseable: false, - 'if-present': false, - loglevel: defaultLoglevel, -} - -const npm = mockNpm({ - localPrefix: __dirname, - flatOptions, - config, - cmd: c => { - return { description: `test ${c} description` } - }, - output: (...msg) => output.push(msg), -}) - -const setLoglevel = (t, level) => { - npm.config.set('loglevel', level) - t.teardown(() => { - npm.config.set('loglevel', defaultLoglevel) +const realRunScript = require('@npmcli/run-script') +const mockNpm = require('../../fixtures/mock-npm') +const { cleanCwd } = require('../../fixtures/clean-snapshot') + +const mockRs = async (t, { windows = false, runScript, ...opts } = {}) => { + let RUN_SCRIPTS = [] + + t.afterEach(() => RUN_SCRIPTS = []) + + const mock = await mockNpm(t, { + ...opts, + mocks: { + '@npmcli/run-script': Object.assign( + async rs => { + if (runScript) { + await runScript(rs) + } + RUN_SCRIPTS.push(rs) + }, + realRunScript + ), + '{LIB}/utils/is-windows.js': { isWindowsShell: windows }, + }, }) -} - -const output = [] - -const log = { - error: () => null, -} - -t.afterEach(() => { - npm.color = false - log.error = () => null - output.length = 0 - RUN_SCRIPTS.length = 0 - config['if-present'] = false - config.json = false - config.parseable = false -}) -const getRS = windows => { - const RunScript = t.mock('../../../lib/commands/run-script.js', { - '@npmcli/run-script': Object.assign( - async opts => { - RUN_SCRIPTS.push(opts) - }, - { - isServerPackage: require('@npmcli/run-script').isServerPackage, - } - ), - 'proc-log': log, - '../../../lib/utils/is-windows.js': { isWindowsShell: windows }, - }) - return new RunScript(npm) + return { + ...mock, + RUN_SCRIPTS: () => RUN_SCRIPTS, + runScript: { exec: (args) => mock.npm.exec('run-script', args) }, + cleanLogs: () => mock.logs.error.flat().map(v => v.toString()).map(cleanCwd), + } } -const runScript = getRS(false) -const runScriptWin = getRS(true) +t.test('completion', async t => { + const completion = async (t, remain, pkg) => { + const { npm } = await mockRs(t, + pkg ? { prefixDir: { 'package.json': JSON.stringify(pkg) } } : {} + ) + const cmd = await npm.cmd('run-script') + return cmd.completion({ conf: { argv: { remain } } }) + } -const { writeFileSync } = require('fs') -t.test('completion', t => { - const dir = t.testdir() - npm.localPrefix = dir t.test('already have a script name', async t => { - const res = await runScript.completion({ conf: { argv: { remain: ['npm', 'run', 'x'] } } }) + const res = await completion(t, ['npm', 'run', 'x']) t.equal(res, undefined) - t.end() }) t.test('no package.json', async t => { - const res = await runScript.completion({ conf: { argv: { remain: ['npm', 'run'] } } }) + const res = await completion(t, ['npm', 'run']) t.strictSame(res, []) - t.end() }) t.test('has package.json, no scripts', async t => { - writeFileSync(`${dir}/package.json`, JSON.stringify({})) - const res = await runScript.completion({ conf: { argv: { remain: ['npm', 'run'] } } }) + const res = await completion(t, ['npm', 'run'], {}) t.strictSame(res, []) - t.end() }) t.test('has package.json, with scripts', async t => { - writeFileSync( - `${dir}/package.json`, - JSON.stringify({ - scripts: { hello: 'echo hello', world: 'echo world' }, - }) - ) - const res = await runScript.completion({ conf: { argv: { remain: ['npm', 'run'] } } }) + const res = await completion(t, ['npm', 'run'], { + scripts: { hello: 'echo hello', world: 'echo world' }, + }) t.strictSame(res, ['hello', 'world']) - t.end() }) - t.end() }) t.test('fail if no package.json', async t => { - t.plan(2) - npm.localPrefix = t.testdir() + const { runScript } = await mockRs(t) await t.rejects(runScript.exec([]), { code: 'ENOENT' }) await t.rejects(runScript.exec(['test']), { code: 'ENOENT' }) }) -t.test('default env, start, and restart scripts', t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ name: 'x', version: '1.2.3' }), - 'server.js': 'console.log("hello, world")', +t.test('default env, start, and restart scripts', async t => { + const { npm, runScript, RUN_SCRIPTS } = await mockRs(t, { + prefixDir: { + 'package.json': JSON.stringify({ name: 'x', version: '1.2.3' }), + 'server.js': 'console.log("hello, world")', + }, }) t.test('start', async t => { await runScript.exec(['start']) - t.match(RUN_SCRIPTS, [ + t.match(RUN_SCRIPTS(), [ { path: npm.localPrefix, args: [], @@ -133,7 +92,7 @@ t.test('default env, start, and restart scripts', t => { t.test('env', async t => { await runScript.exec(['env']) - t.match(RUN_SCRIPTS, [ + t.match(RUN_SCRIPTS(), [ { path: npm.localPrefix, args: [], @@ -152,31 +111,10 @@ t.test('default env, start, and restart scripts', t => { ]) }) - t.test('windows env', async t => { - await runScriptWin.exec(['env']) - t.match(RUN_SCRIPTS, [ - { - path: npm.localPrefix, - args: [], - scriptShell: undefined, - stdio: 'inherit', - pkg: { - name: 'x', - version: '1.2.3', - _id: 'x@1.2.3', - scripts: { - env: 'SET', - }, - }, - event: 'env', - }, - ]) - }) - t.test('restart', async t => { await runScript.exec(['restart']) - t.match(RUN_SCRIPTS, [ + t.match(RUN_SCRIPTS(), [ { path: npm.localPrefix, args: [], @@ -194,23 +132,52 @@ t.test('default env, start, and restart scripts', t => { }, ]) }) - t.end() }) -t.test('non-default env script', t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'x', - version: '1.2.3', - scripts: { - env: 'hello', +t.test('default windows env', async t => { + const { npm, runScript, RUN_SCRIPTS } = await mockRs(t, { + windows: true, + prefixDir: { + 'package.json': JSON.stringify({ name: 'x', version: '1.2.3' }), + 'server.js': 'console.log("hello, world")', + }, + }) + await runScript.exec(['env']) + t.match(RUN_SCRIPTS(), [ + { + path: npm.localPrefix, + args: [], + scriptShell: undefined, + stdio: 'inherit', + pkg: { + name: 'x', + version: '1.2.3', + _id: 'x@1.2.3', + scripts: { + env: 'SET', + }, }, - }), + event: 'env', + }, + ]) +}) + +t.test('non-default env script', async t => { + const { npm, runScript, RUN_SCRIPTS } = await mockRs(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'x', + version: '1.2.3', + scripts: { + env: 'hello', + }, + }), + }, }) t.test('env', async t => { await runScript.exec(['env']) - t.match(RUN_SCRIPTS, [ + t.match(RUN_SCRIPTS(), [ { path: npm.localPrefix, args: [], @@ -228,71 +195,98 @@ t.test('non-default env script', t => { }, ]) }) +}) - t.test('env windows', async t => { - await runScriptWin.exec(['env']) - t.match(RUN_SCRIPTS, [ - { - path: npm.localPrefix, - args: [], - scriptShell: undefined, - stdio: 'inherit', - pkg: { - name: 'x', - version: '1.2.3', - _id: 'x@1.2.3', - scripts: { - env: 'hello', - }, +t.test('non-default env script windows', async t => { + const { npm, runScript, RUN_SCRIPTS } = await mockRs(t, { + windows: true, + prefixDir: { + 'package.json': JSON.stringify({ + name: 'x', + version: '1.2.3', + scripts: { + env: 'hello', }, - event: 'env', - }, - ]) + }), + }, }) - t.end() + + await runScript.exec(['env']) + + t.match(RUN_SCRIPTS(), [ + { + path: npm.localPrefix, + args: [], + scriptShell: undefined, + stdio: 'inherit', + pkg: { + name: 'x', + version: '1.2.3', + _id: 'x@1.2.3', + scripts: { + env: 'hello', + }, + }, + event: 'env', + }, + ]) }) -t.test('try to run missing script', t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - scripts: { hello: 'world' }, - bin: { goodnight: 'moon' }, - }), - }) - t.test('no suggestions', async t => { - await t.rejects(runScript.exec(['notevenclose']), 'Missing script: "notevenclose"') - }) - t.test('script suggestions', async t => { - await t.rejects(runScript.exec(['helo']), /Missing script: "helo"/) - await t.rejects(runScript.exec(['helo']), /npm run hello/) - }) - t.test('bin suggestions', async t => { - await t.rejects(runScript.exec(['goodneght']), /Missing script: "goodneght"/) - await t.rejects(runScript.exec(['goodneght']), /npm exec goodnight/) +t.test('try to run missing script', async t => { + t.test('errors', async t => { + const { runScript } = await mockRs(t, { + prefixDir: { + 'package.json': JSON.stringify({ + scripts: { hello: 'world' }, + bin: { goodnight: 'moon' }, + }), + }, + }) + t.test('no suggestions', async t => { + await t.rejects(runScript.exec(['notevenclose']), 'Missing script: "notevenclose"') + }) + t.test('script suggestions', async t => { + await t.rejects(runScript.exec(['helo']), /Missing script: "helo"/) + await t.rejects(runScript.exec(['helo']), /npm run hello/) + }) + t.test('bin suggestions', async t => { + await t.rejects(runScript.exec(['goodneght']), /Missing script: "goodneght"/) + await t.rejects(runScript.exec(['goodneght']), /npm exec goodnight/) + }) }) + t.test('with --if-present', async t => { - config['if-present'] = true + const { runScript, RUN_SCRIPTS } = await mockRs(t, { + config: { 'if-present': true }, + prefixDir: { + 'package.json': JSON.stringify({ + scripts: { hello: 'world' }, + bin: { goodnight: 'moon' }, + }), + }, + }) await runScript.exec(['goodbye']) - t.strictSame(RUN_SCRIPTS, [], 'did not try to run anything') + t.strictSame(RUN_SCRIPTS(), [], 'did not try to run anything') }) - t.end() }) t.test('run pre/post hooks', async t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'x', - version: '1.2.3', - scripts: { - preenv: 'echo before the env', - postenv: 'echo after the env', - }, - }), + const { npm, runScript, RUN_SCRIPTS } = await mockRs(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'x', + version: '1.2.3', + scripts: { + preenv: 'echo before the env', + postenv: 'echo after the env', + }, + }), + }, }) await runScript.exec(['env']) - t.match(RUN_SCRIPTS, [ + t.match(RUN_SCRIPTS(), [ { event: 'preenv' }, { path: npm.localPrefix, @@ -314,22 +308,23 @@ t.test('run pre/post hooks', async t => { }) t.test('skip pre/post hooks when using ignoreScripts', async t => { - config['ignore-scripts'] = true - - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'x', - version: '1.2.3', - scripts: { - preenv: 'echo before the env', - postenv: 'echo after the env', - }, - }), + const { npm, runScript, RUN_SCRIPTS } = await mockRs(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'x', + version: '1.2.3', + scripts: { + preenv: 'echo before the env', + postenv: 'echo after the env', + }, + }), + }, + config: { 'ignore-scripts': true }, }) await runScript.exec(['env']) - t.same(RUN_SCRIPTS, [ + t.same(RUN_SCRIPTS(), [ { path: npm.localPrefix, args: [], @@ -349,25 +344,25 @@ t.test('skip pre/post hooks when using ignoreScripts', async t => { event: 'env', }, ]) - delete config['ignore-scripts'] }) t.test('run silent', async t => { - setLoglevel(t, 'silent') - - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'x', - version: '1.2.3', - scripts: { - preenv: 'echo before the env', - postenv: 'echo after the env', - }, - }), + const { npm, runScript, RUN_SCRIPTS } = await mockRs(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'x', + version: '1.2.3', + scripts: { + preenv: 'echo before the env', + postenv: 'echo after the env', + }, + }), + }, + config: { silent: true }, }) await runScript.exec(['env']) - t.match(RUN_SCRIPTS, [ + t.match(RUN_SCRIPTS(), [ { event: 'preenv', stdio: 'inherit', @@ -395,7 +390,7 @@ t.test('run silent', async t => { ]) }) -t.test('list scripts', t => { +t.test('list scripts', async t => { const scripts = { test: 'exit 2', start: 'node server.js', @@ -403,16 +398,26 @@ t.test('list scripts', t => { preenv: 'echo before the env', postenv: 'echo after the env', } - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'x', - version: '1.2.3', - scripts, - }), - }) + + const mockList = async (t, config = {}) => { + const mock = await mockRs(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'x', + version: '1.2.3', + scripts, + }), + }, + config, + }) + + await mock.runScript.exec([]) + + return mock.outputs + } t.test('no args', async t => { - await runScript.exec([]) + const output = await mockList(t) t.strictSame( output, [ @@ -430,20 +435,17 @@ t.test('list scripts', t => { }) t.test('silent', async t => { - setLoglevel(t, 'silent') - await runScript.exec([]) - t.strictSame(output, []) + const outputs = await mockList(t, { silent: true }) + t.strictSame(outputs, []) }) t.test('warn json', async t => { - config.json = true - await runScript.exec([]) - t.strictSame(output, [[JSON.stringify(scripts, 0, 2)]], 'json report') + const outputs = await mockList(t, { json: true }) + t.strictSame(outputs, [[JSON.stringify(scripts, 0, 2)]], 'json report') }) t.test('parseable', async t => { - config.parseable = true - await runScript.exec([]) - t.strictSame(output, [ + const outputs = await mockList(t, { parseable: true }) + t.strictSame(outputs, [ ['test:exit 2'], ['start:node server.js'], ['stop:node kill-server.js'], @@ -451,32 +453,35 @@ t.test('list scripts', t => { ['postenv:echo after the env'], ]) }) - t.end() }) t.test('list scripts when no scripts', async t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'x', - version: '1.2.3', - }), + const { runScript, outputs } = await mockRs(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'x', + version: '1.2.3', + }), + }, }) await runScript.exec([]) - t.strictSame(output, [], 'nothing to report') + t.strictSame(outputs, [], 'nothing to report') }) t.test('list scripts, only commands', async t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'x', - version: '1.2.3', - scripts: { preversion: 'echo doing the version dance' }, - }), + const { runScript, outputs } = await mockRs(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'x', + version: '1.2.3', + scripts: { preversion: 'echo doing the version dance' }, + }), + }, }) await runScript.exec([]) - t.strictSame(output, [ + t.strictSame(outputs, [ ['Lifecycle scripts included in x@1.2.3:'], [' preversion\n echo doing the version dance'], [''], @@ -484,83 +489,104 @@ t.test('list scripts, only commands', async t => { }) t.test('list scripts, only non-commands', async t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'x', - version: '1.2.3', - scripts: { glorp: 'echo doing the glerp glop' }, - }), + const { runScript, outputs } = await mockRs(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'x', + version: '1.2.3', + scripts: { glorp: 'echo doing the glerp glop' }, + }), + }, }) await runScript.exec([]) - t.strictSame(output, [ + t.strictSame(outputs, [ ['Scripts available in x@1.2.3 via `npm run-script`:'], [' glorp\n echo doing the glerp glop'], [''], ]) }) -t.test('workspaces', t => { - npm.localPrefix = t.testdir({ - packages: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - scripts: { glorp: 'echo a doing the glerp glop' }, - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'b', - version: '2.0.0', - scripts: { glorp: 'echo b doing the glerp glop' }, - }), - }, - c: { - 'package.json': JSON.stringify({ - name: 'c', - version: '1.0.0', - scripts: { - test: 'exit 0', - posttest: 'echo posttest', - lorem: 'echo c lorem', +t.test('workspaces', async t => { + const mockWorkspaces = async (t, { + runScript, + prefixDir, + workspaces = true, + exec = [], + ...config + } = {}) => { + const mock = await mockRs(t, { + prefixDir: prefixDir || { + packages: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + scripts: { glorp: 'echo a doing the glerp glop' }, + }), }, - }), - }, - d: { - 'package.json': JSON.stringify({ - name: 'd', - version: '1.0.0', - scripts: { - test: 'exit 0', - posttest: 'echo posttest', + b: { + 'package.json': JSON.stringify({ + name: 'b', + version: '2.0.0', + scripts: { glorp: 'echo b doing the glerp glop' }, + }), }, - }), - }, - e: { + c: { + 'package.json': JSON.stringify({ + name: 'c', + version: '1.0.0', + scripts: { + test: 'exit 0', + posttest: 'echo posttest', + lorem: 'echo c lorem', + }, + }), + }, + d: { + 'package.json': JSON.stringify({ + name: 'd', + version: '1.0.0', + scripts: { + test: 'exit 0', + posttest: 'echo posttest', + }, + }), + }, + e: { + 'package.json': JSON.stringify({ + name: 'e', + scripts: { test: 'exit 0', start: 'echo start something' }, + }), + }, + noscripts: { + 'package.json': JSON.stringify({ + name: 'noscripts', + version: '1.0.0', + }), + }, + }, 'package.json': JSON.stringify({ - name: 'e', - scripts: { test: 'exit 0', start: 'echo start something' }, + name: 'x', + version: '1.2.3', + workspaces: ['packages/*'], }), }, - noscripts: { - 'package.json': JSON.stringify({ - name: 'noscripts', - version: '1.0.0', - }), + config: { + ...Array.isArray(workspaces) ? { workspace: workspaces } : { workspaces }, + ...config, }, - }, - 'package.json': JSON.stringify({ - name: 'x', - version: '1.2.3', - workspaces: ['packages/*'], - }), - }) + runScript, + }) + if (exec) { + await mock.runScript.exec(exec) + } + return mock + } t.test('list all scripts', async t => { - await runScript.execWorkspaces([], []) - t.strictSame(output, [ + const { outputs } = await mockWorkspaces(t) + t.strictSame(outputs, [ ['Scripts available in a@1.0.0 via `npm run-script`:'], [' glorp\n echo a doing the glerp glop'], [''], @@ -585,8 +611,8 @@ t.test('workspaces', t => { }) t.test('list regular scripts, filtered by name', async t => { - await runScript.execWorkspaces([], ['a', 'b']) - t.strictSame(output, [ + const { outputs } = await mockWorkspaces(t, { workspaces: ['a', 'b'] }) + t.strictSame(outputs, [ ['Scripts available in a@1.0.0 via `npm run-script`:'], [' glorp\n echo a doing the glerp glop'], [''], @@ -597,8 +623,8 @@ t.test('workspaces', t => { }) t.test('list regular scripts, filtered by path', async t => { - await runScript.execWorkspaces([], ['./packages/a']) - t.strictSame(output, [ + const { outputs } = await mockWorkspaces(t, { workspaces: ['./packages/a'] }) + t.strictSame(outputs, [ ['Scripts available in a@1.0.0 via `npm run-script`:'], [' glorp\n echo a doing the glerp glop'], [''], @@ -606,8 +632,8 @@ t.test('workspaces', t => { }) t.test('list regular scripts, filtered by parent folder', async t => { - await runScript.execWorkspaces([], ['./packages']) - t.strictSame(output, [ + const { outputs } = await mockWorkspaces(t, { workspaces: ['./packages'] }) + t.strictSame(outputs, [ ['Scripts available in a@1.0.0 via `npm run-script`:'], [' glorp\n echo a doing the glerp glop'], [''], @@ -632,9 +658,8 @@ t.test('workspaces', t => { }) t.test('list all scripts with colors', async t => { - npm.color = true - await runScript.execWorkspaces([], []) - t.strictSame(output, [ + const { outputs } = await mockWorkspaces(t, { color: 'always' }) + t.strictSame(outputs, [ [ /* eslint-disable-next-line max-len */ '\u001b[1mScripts\u001b[22m available in \x1B[32ma@1.0.0\x1B[39m via `\x1B[34mnpm run-script\x1B[39m`:', @@ -665,9 +690,8 @@ t.test('workspaces', t => { }) t.test('list all scripts --json', async t => { - config.json = true - await runScript.execWorkspaces([], []) - t.strictSame(output, [ + const { outputs } = await mockWorkspaces(t, { json: true }) + t.strictSame(outputs, [ [ '{\n' + ' "a": {\n' + @@ -696,9 +720,8 @@ t.test('workspaces', t => { }) t.test('list all scripts --parseable', async t => { - config.parseable = true - await runScript.execWorkspaces([], []) - t.strictSame(output, [ + const { outputs } = await mockWorkspaces(t, { parseable: true }) + t.strictSame(outputs, [ ['a:glorp:echo a doing the glerp glop'], ['b:glorp:echo b doing the glerp glop'], ['c:test:exit 0'], @@ -712,15 +735,14 @@ t.test('workspaces', t => { }) t.test('list no scripts --loglevel=silent', async t => { - setLoglevel(t, 'silent') - await runScript.execWorkspaces([], []) - t.strictSame(output, []) + const { outputs } = await mockWorkspaces(t, { silent: true }) + t.strictSame(outputs, []) }) t.test('run scripts across all workspaces', async t => { - await runScript.execWorkspaces(['test'], []) + const { npm, RUN_SCRIPTS } = await mockWorkspaces(t, { exec: ['test'] }) - t.match(RUN_SCRIPTS, [ + t.match(RUN_SCRIPTS(), [ { path: resolve(npm.localPrefix, 'packages/c'), pkg: { name: 'c', version: '1.0.0' }, @@ -750,70 +772,65 @@ t.test('workspaces', t => { }) t.test('missing scripts in all workspaces', async t => { - const LOG = [] - log.error = err => { - LOG.push(String(err)) - } + const { runScript, RUN_SCRIPTS, cleanLogs } = await mockWorkspaces(t, { exec: null }) + await t.rejects( - runScript.execWorkspaces(['missing-script'], []), + runScript.exec(['missing-script']), /Missing script: missing-script/, 'should throw missing script error' ) - process.exitCode = 0 // clean exit code - - t.match(RUN_SCRIPTS, []) + t.match(RUN_SCRIPTS(), []) t.strictSame( - LOG.map(cleanOutput), + cleanLogs(), [ 'Lifecycle script `missing-script` failed with error:', 'Error: Missing script: "missing-script"\n\nTo see a list of scripts, run:\n npm run', ' in workspace: a@1.0.0', - ' at location: {CWD}/test/lib/commands/tap-testdir-run-script-workspaces/packages/a', + ' at location: {CWD}/prefix/packages/a', 'Lifecycle script `missing-script` failed with error:', 'Error: Missing script: "missing-script"\n\nTo see a list of scripts, run:\n npm run', ' in workspace: b@2.0.0', - ' at location: {CWD}/test/lib/commands/tap-testdir-run-script-workspaces/packages/b', + ' at location: {CWD}/prefix/packages/b', 'Lifecycle script `missing-script` failed with error:', 'Error: Missing script: "missing-script"\n\nTo see a list of scripts, run:\n npm run', ' in workspace: c@1.0.0', - ' at location: {CWD}/test/lib/commands/tap-testdir-run-script-workspaces/packages/c', + ' at location: {CWD}/prefix/packages/c', 'Lifecycle script `missing-script` failed with error:', 'Error: Missing script: "missing-script"\n\nTo see a list of scripts, run:\n npm run', ' in workspace: d@1.0.0', - ' at location: {CWD}/test/lib/commands/tap-testdir-run-script-workspaces/packages/d', + ' at location: {CWD}/prefix/packages/d', 'Lifecycle script `missing-script` failed with error:', 'Error: Missing script: "missing-script"\n\nTo see a list of scripts, run:\n npm run', ' in workspace: e', - ' at location: {CWD}/test/lib/commands/tap-testdir-run-script-workspaces/packages/e', + ' at location: {CWD}/prefix/packages/e', 'Lifecycle script `missing-script` failed with error:', 'Error: Missing script: "missing-script"\n\nTo see a list of scripts, run:\n npm run', ' in workspace: noscripts@1.0.0', - /* eslint-disable-next-line max-len */ - ' at location: {CWD}/test/lib/commands/tap-testdir-run-script-workspaces/packages/noscripts', + ' at location: {CWD}/prefix/packages/noscripts', ], 'should log error msgs for each workspace script' ) }) t.test('missing scripts in some workspaces', async t => { - const LOG = [] - log.error = err => { - LOG.push(String(err)) - } - await runScript.execWorkspaces(['test'], ['a', 'b', 'c', 'd']) - t.match(RUN_SCRIPTS, []) + const { RUN_SCRIPTS, cleanLogs } = await mockWorkspaces(t, { + exec: ['test'], + workspaces: ['a', 'b', 'c', 'd'], + }) + + t.match(RUN_SCRIPTS(), []) t.strictSame( - LOG.map(cleanOutput), + cleanLogs(), [ 'Lifecycle script `test` failed with error:', 'Error: Missing script: "test"\n\nTo see a list of scripts, run:\n npm run', ' in workspace: a@1.0.0', - ' at location: {CWD}/test/lib/commands/tap-testdir-run-script-workspaces/packages/a', + ' at location: {CWD}/prefix/packages/a', 'Lifecycle script `test` failed with error:', 'Error: Missing script: "test"\n\nTo see a list of scripts, run:\n npm run', ' in workspace: b@2.0.0', - ' at location: {CWD}/test/lib/commands/tap-testdir-run-script-workspaces/packages/b', + ' at location: {CWD}/prefix/packages/b', ], 'should log error msgs for each workspace script' ) @@ -821,68 +838,76 @@ t.test('workspaces', t => { t.test('no workspaces when filtering by user args', async t => { await t.rejects( - runScript.execWorkspaces([], ['foo', 'bar']), + mockWorkspaces(t, { workspaces: ['foo', 'bar'] }), 'No workspaces found:\n --workspace=foo --workspace=bar', 'should throw error msg' ) }) t.test('no workspaces', async t => { - const _prevPrefix = npm.localPrefix - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.0.0', - }), - }) - await t.rejects( - runScript.execWorkspaces([], []), + mockWorkspaces(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.0.0', + }), + }, + }), /No workspaces found!/, 'should throw error msg' ) - npm.localPrefix = _prevPrefix }) t.test('single failed workspace run', async t => { - const RunScript = t.mock('../../../lib/commands/run-script.js', { - '@npmcli/run-script': () => { + const { cleanLogs } = await mockWorkspaces(t, { + runScript: () => { throw new Error('err') }, - 'proc-log': log, - '../../../lib/utils/is-windows.js': { isWindowsShell: false }, + exec: ['test'], + workspaces: ['c'], }) - const runScript = new RunScript(npm) - await runScript.execWorkspaces(['test'], ['c']) - process.exitCode = 0 // clean up exit code + t.strictSame( + cleanLogs(), + [ + 'Lifecycle script `test` failed with error:', + 'Error: err', + ' in workspace: c@1.0.0', + ' at location: {CWD}/prefix/packages/c', + ], + 'should log error msgs for each workspace script' + ) }) t.test('failed workspace run with succeeded runs', async t => { - const RunScript = t.mock('../../../lib/commands/run-script.js', { - '@npmcli/run-script': async opts => { + const { cleanLogs, RUN_SCRIPTS, prefix } = await mockWorkspaces(t, { + runScript: (opts) => { if (opts.pkg.name === 'a') { throw new Error('ERR') } - - RUN_SCRIPTS.push(opts) }, - 'proc-log': log, - '../../../lib/utils/is-windows.js': { isWindowsShell: false }, + exec: ['glorp'], + workspaces: ['a', 'b'], }) - const runScript = new RunScript(npm) - await runScript.execWorkspaces(['glorp'], ['a', 'b']) - t.match(RUN_SCRIPTS, [ + t.strictSame( + cleanLogs(), + [ + 'Lifecycle script `glorp` failed with error:', + 'Error: ERR', + ' in workspace: a@1.0.0', + ' at location: {CWD}/prefix/packages/a', + ], + 'should log error msgs for each workspace script' + ) + + t.match(RUN_SCRIPTS(), [ { - path: resolve(npm.localPrefix, 'packages/b'), + path: resolve(prefix, 'packages/b'), pkg: { name: 'b', version: '2.0.0' }, event: 'glorp', }, ]) - - process.exitCode = 0 // clean up exit code }) - - t.end() }) diff --git a/deps/npm/test/lib/commands/set.js b/deps/npm/test/lib/commands/set.js index ce59870e2fec4a..69c4dd87056af9 100644 --- a/deps/npm/test/lib/commands/set.js +++ b/deps/npm/test/lib/commands/set.js @@ -1,60 +1,49 @@ const t = require('tap') - -// can't run this until npm set can save to project level npmrc -t.skip('npm set', async t => { - // XXX: convert to loadMockNpm - const { real: mockNpm } = require('../../fixtures/mock-npm') - const { joinedOutput, Npm } = mockNpm(t) - const npm = new Npm() - await npm.load() - - t.test('no args', async t => { - t.rejects(npm.exec('set', []), /Usage:/, 'prints usage') - }) - - t.test('test-config-item', async t => { - npm.localPrefix = t.testdir({}) - t.not( - npm.config.get('test-config-item', 'project'), - 'test config value', - 'config is not already new value' - ) - // This will write to ~/.npmrc! - // Don't unskip until we can write to project level - await npm.exec('set', ['test-config-item=test config value']) - t.equal(joinedOutput(), '', 'outputs nothing') - t.equal( - npm.config.get('test-config-item', 'project'), - 'test config value', - 'config is set to new value' - ) - }) +const fs = require('fs/promises') +const mockNpm = require('../../fixtures/mock-npm') +const { join } = require('path') +const { cleanNewlines } = require('../../fixtures/clean-snapshot') + +t.test('no args', async t => { + const { npm } = await mockNpm(t) + t.rejects(npm.exec('set', []), /Usage:/, 'prints usage') }) -// Everything after this can go away once the above test is unskipped - -let configArgs = null -const npm = { - exec: async (cmd, args) => { - if (cmd === 'config') { - configArgs = args - } - }, - config: { - validate: () => {}, - isDefault: () => {}, - }, -} - -const Set = t.mock('../../../lib/commands/set.js') -const set = new Set(npm) - -t.test('npm set - no args', async t => { - await t.rejects(set.exec([]), set.usage) -}) - -t.test('npm set', async t => { - await set.exec(['email', 'me@me.me']) +t.test('test-config-item', async t => { + const { npm, home, joinedOutput } = await mockNpm(t, { + homeDir: { + '.npmrc': 'original-config-test=original value', + }, + }) - t.strictSame(configArgs, ['set', 'email', 'me@me.me'], 'passed the correct arguments to config') + t.equal( + npm.config.get('original-config-test'), + 'original value', + 'original config is set from npmrc' + ) + + t.not( + npm.config.get('fund'), + false, + 'config is not already new value' + ) + + await npm.exec('set', ['fund=true']) + t.equal(joinedOutput(), '', 'outputs nothing') + + t.equal( + npm.config.get('fund'), + true, + 'config is set to new value' + ) + + t.equal( + cleanNewlines(await fs.readFile(join(home, '.npmrc'), 'utf-8')), + [ + 'original-config-test=original value', + 'fund=true', + '', + ].join('\n'), + 'npmrc is written with new value' + ) }) diff --git a/deps/npm/test/lib/commands/stars.js b/deps/npm/test/lib/commands/stars.js index 44de6ba1fb9607..124d2d344d8dae 100644 --- a/deps/npm/test/lib/commands/stars.js +++ b/deps/npm/test/lib/commands/stars.js @@ -1,34 +1,36 @@ const t = require('tap') +const realFetch = require('npm-registry-fetch') +const mockNpm = require('../../fixtures/mock-npm') -let result = '' +const noop = () => {} -const noop = () => null -const npm = { - config: { get () {}, validate: () => {} }, - flatOptions: {}, - output: (...msg) => { - result = [result, ...msg].join('\n') - }, -} -const npmFetch = { json: noop } -const log = { warn: noop } -const mocks = { - 'proc-log': log, - 'npm-registry-fetch': npmFetch, - '../../../lib/utils/get-identity.js': async () => 'foo', -} +const mockStars = async (t, { npmFetch = noop, exec = true, ...opts }) => { + const mock = await mockNpm(t, { + mocks: { + 'npm-registry-fetch': Object.assign(noop, realFetch, { json: npmFetch }), + '{LIB}/utils/get-identity.js': async () => 'foo', + }, + ...opts, + }) -const Stars = t.mock('../../../lib/commands/stars.js', mocks) -const stars = new Stars(npm) + const stars = { exec: (args) => mock.npm.exec('stars', args) } -t.afterEach(() => { - npm.config = { get () {} } - log.warn = noop - result = '' -}) + if (exec) { + await stars.exec(Array.isArray(exec) ? exec : []) + mock.result = mock.joinedOutput() + } + + return { + ...mock, + stars, + logs: () => mock.logs.filter(l => l[1] === 'stars').map(l => l[2]), + } +} t.test('no args', async t => { - npmFetch.json = async (uri, opts) => { + t.plan(3) + + const npmFetch = async (uri, opts) => { t.equal(uri, '/-/_view/starredByUser', 'should fetch from expected uri') t.equal(opts.query.key, '"foo"', 'should match logged in username') @@ -43,7 +45,7 @@ t.test('no args', async t => { } } - await stars.exec([]) + const { result } = await mockStars(t, { npmFetch, exec: true }) t.matchSnapshot( result, @@ -53,7 +55,8 @@ t.test('no args', async t => { t.test('npm star ', async t => { t.plan(3) - npmFetch.json = async (uri, opts) => { + + const npmFetch = async (uri, opts) => { t.equal(uri, '/-/_view/starredByUser', 'should fetch from expected uri') t.equal(opts.query.key, '"ruyadorno"', 'should match username') @@ -62,7 +65,7 @@ t.test('npm star ', async t => { } } - await stars.exec(['ruyadorno']) + const { result } = await mockStars(t, { npmFetch, exec: ['ruyadorno'] }) t.match( result, @@ -72,22 +75,14 @@ t.test('npm star ', async t => { }) t.test('unauthorized request', async t => { - t.plan(4) - npmFetch.json = async () => { + const npmFetch = async () => { throw Object.assign( new Error('Not logged in'), { code: 'ENEEDAUTH' } ) } - log.warn = (title, msg) => { - t.equal(title, 'stars', 'should use expected title') - t.equal( - msg, - 'auth is required to look up your username', - 'should warn auth required msg' - ) - } + const { joinedOutput, stars, logs } = await mockStars(t, { npmFetch, exec: false }) await t.rejects( stars.exec([]), @@ -95,41 +90,43 @@ t.test('unauthorized request', async t => { 'should throw unauthorized request msg' ) + t.strictSame( + logs(), + ['auth is required to look up your username'], + 'should warn auth required msg' + ) + t.equal( - result, + joinedOutput(), '', 'should have empty output' ) }) t.test('unexpected error', async t => { - npmFetch.json = async () => { + const npmFetch = async () => { throw new Error('ERROR') } - log.warn = (title, msg) => { - throw new Error('Should not output extra warning msgs') - } + const { stars, logs } = await mockStars(t, { npmFetch, exec: false }) await t.rejects( stars.exec([]), /ERROR/, 'should throw unexpected error message' ) + + t.strictSame(logs(), [], 'no logs') }) t.test('no pkg starred', async t => { - t.plan(2) - npmFetch.json = async (uri, opts) => ({ rows: [] }) - - log.warn = (title, msg) => { - t.equal(title, 'stars', 'should use expected title') - t.equal( - msg, - 'user has not starred any packages', - 'should warn no starred packages msg' - ) - } + const npmFetch = async () => ({ rows: [] }) - await stars.exec([]) + const { logs } = await mockStars(t, { npmFetch, exec: true }) + + t.strictSame( + logs(), + ['user has not starred any packages'], + 'should warn no starred packages msg' + ) }) diff --git a/deps/npm/test/lib/commands/start.js b/deps/npm/test/lib/commands/start.js index 47f7f1a6e0f517..b0e908b6ae372b 100644 --- a/deps/npm/test/lib/commands/start.js +++ b/deps/npm/test/lib/commands/start.js @@ -19,11 +19,11 @@ t.test('should run start script from package.json', async t => { }, config: { loglevel: 'silent', - scriptShell: process.platform === 'win32' ? process.env.COMSPEC : 'sh', + 'script-shell': process.platform === 'win32' ? process.env.COMSPEC : 'sh', }, }) - const scriptShell = npm.config.get('scriptShell') + const scriptShell = npm.config.get('script-shell') const scriptArgs = isCmdRe.test(scriptShell) ? ['/d', '/s', '/c', 'node ./test-start.js foo'] : ['-c', 'node ./test-start.js foo'] diff --git a/deps/npm/test/lib/commands/stop.js b/deps/npm/test/lib/commands/stop.js index 9ca774288446b4..560f7deb75cc90 100644 --- a/deps/npm/test/lib/commands/stop.js +++ b/deps/npm/test/lib/commands/stop.js @@ -19,11 +19,11 @@ t.test('should run stop script from package.json', async t => { }, config: { loglevel: 'silent', - scriptShell: process.platform === 'win32' ? process.env.COMSPEC : 'sh', + 'script-shell': process.platform === 'win32' ? process.env.COMSPEC : 'sh', }, }) - const scriptShell = npm.config.get('scriptShell') + const scriptShell = npm.config.get('script-shell') const scriptArgs = isCmdRe.test(scriptShell) ? ['/d', '/s', '/c', 'node ./test-stop.js foo'] : ['-c', 'node ./test-stop.js foo'] diff --git a/deps/npm/test/lib/commands/team.js b/deps/npm/test/lib/commands/team.js index 792418788bcd10..a13a56d986e35e 100644 --- a/deps/npm/test/lib/commands/team.js +++ b/deps/npm/test/lib/commands/team.js @@ -1,39 +1,33 @@ const t = require('tap') -const { fake: mockNpm } = require('../../fixtures/mock-npm') - -let result = '' -const libnpmteam = { - async add () {}, - async create () {}, - async destroy () {}, - async lsTeams () {}, - async lsUsers () {}, - async rm () {}, -} -const npm = mockNpm({ - flatOptions: {}, - config: { - loglevel: 'info', - }, - output: (...msg) => { - result += msg.join('\n') - }, -}) -const mocks = { - libnpmteam, - 'cli-columns': a => a.join(' '), -} - -t.afterEach(() => { - result = '' - npm.flatOptions = {} - npm.config.set('loglevel', 'info') -}) +const mockNpm = require('../../fixtures/mock-npm') + +t.cleanSnapshot = s => s.trim().replace(/\n+/g, '\n') + +const mockTeam = async (t, { libnpmteam, ...opts } = {}) => { + const mock = await mockNpm(t, { + ...opts, + mocks: { + // XXX: this should be refactored to use the mock registry + libnpmteam: libnpmteam || { + async add () {}, + async create () {}, + async destroy () {}, + async lsTeams () {}, + async lsUsers () {}, + async rm () {}, + }, + }, + }) -const Team = t.mock('../../../lib/commands/team.js', mocks) -const team = new Team(npm) + return { + ...mock, + team: { exec: (args) => mock.npm.exec('team', args) }, + result: () => mock.joinedOutput(), + } +} t.test('no args', async t => { + const { team } = await mockTeam(t) await t.rejects( team.exec([]), 'usage instructions', @@ -43,29 +37,35 @@ t.test('no args', async t => { t.test('team add ', async t => { t.test('default output', async t => { + const { team, result } = await mockTeam(t) + await team.exec(['add', '@npmcli:developers', 'foo']) - t.matchSnapshot(result, 'should output success result for add user') + t.matchSnapshot(result(), 'should output success result for add user') }) t.test('--parseable', async t => { - npm.flatOptions.parseable = true + const { team, result } = await mockTeam(t, { + config: { parseable: true }, + }) await team.exec(['add', '@npmcli:developers', 'foo']) t.matchSnapshot( - result, + result(), 'should output success result for parseable add user' ) }) t.test('--json', async t => { - npm.flatOptions.json = true + const { team, result } = await mockTeam(t, { + config: { json: true }, + }) await team.exec(['add', '@npmcli:developers', 'foo']) t.same( - JSON.parse(result), + JSON.parse(result()), { added: true, team: 'npmcli:developers', @@ -76,39 +76,47 @@ t.test('team add ', async t => { }) t.test('--silent', async t => { - npm.config.set('loglevel', 'silent') + const { team, result } = await mockTeam(t, { + config: { silent: true }, + }) await team.exec(['add', '@npmcli:developers', 'foo']) - t.same(result, '', 'should not output success if silent') + t.same(result(), '', 'should not output success if silent') }) }) t.test('team create ', async t => { t.test('default output', async t => { + const { team, result } = await mockTeam(t) + await team.exec(['create', '@npmcli:newteam']) - t.matchSnapshot(result, 'should output success result for create team') + t.matchSnapshot(result(), 'should output success result for create team') }) t.test('--parseable', async t => { - npm.flatOptions.parseable = true + const { team, result } = await mockTeam(t, { + config: { parseable: true }, + }) await team.exec(['create', '@npmcli:newteam']) t.matchSnapshot( - result, + result(), 'should output parseable success result for create team' ) }) t.test('--json', async t => { - npm.flatOptions.json = true + const { team, result } = await mockTeam(t, { + config: { json: true }, + }) await team.exec(['create', '@npmcli:newteam']) t.same( - JSON.parse(result), + JSON.parse(result()), { created: true, team: 'npmcli:newteam', @@ -118,31 +126,38 @@ t.test('team create ', async t => { }) t.test('--silent', async t => { - npm.config.set('loglevel', 'silent') + const { team, result } = await mockTeam(t, { + config: { silent: true }, + }) await team.exec(['create', '@npmcli:newteam']) - t.same(result, '', 'should not output create success if silent') + t.same(result(), '', 'should not output create success if silent') }) }) t.test('team destroy ', async t => { t.test('default output', async t => { + const { team, result } = await mockTeam(t) await team.exec(['destroy', '@npmcli:newteam']) - t.matchSnapshot(result, 'should output success result for destroy team') + t.matchSnapshot(result(), 'should output success result for destroy team') }) t.test('--parseable', async t => { - npm.flatOptions.parseable = true + const { team, result } = await mockTeam(t, { + config: { parseable: true }, + }) await team.exec(['destroy', '@npmcli:newteam']) - t.matchSnapshot(result, 'should output parseable result for destroy team') + t.matchSnapshot(result(), 'should output parseable result for destroy team') }) t.test('--json', async t => { - npm.flatOptions.json = true + const { team, result } = await mockTeam(t, { + config: { json: true }, + }) await team.exec(['destroy', '@npmcli:newteam']) t.same( - JSON.parse(result), + JSON.parse(result()), { deleted: true, team: 'npmcli:newteam', @@ -152,14 +167,16 @@ t.test('team destroy ', async t => { }) t.test('--silent', async t => { - npm.config.set('loglevel', 'silent') + const { team, result } = await mockTeam(t, { + config: { silent: true }, + }) await team.exec(['destroy', '@npmcli:newteam']) - t.same(result, '', 'should not output destroy if silent') + t.same(result(), '', 'should not output destroy if silent') }) }) t.test('team ls ', async t => { - const libnpmteam = { + const teams = { async lsTeams () { return [ 'npmcli:developers', @@ -169,28 +186,43 @@ t.test('team ls ', async t => { }, } - const Team = t.mock('../../../lib/commands/team.js', { - ...mocks, - libnpmteam, - }) - const team = new Team(npm) + const noTeam = { + async lsTeams () { + return [] + }, + } + + const singleTeam = { + async lsTeams () { + return ['npmcli:developers'] + }, + } t.test('default output', async t => { + const { team, result } = await mockTeam(t, { + libnpmteam: teams, + }) await team.exec(['ls', '@npmcli']) - t.matchSnapshot(result, 'should list teams for a given scope') + t.matchSnapshot(result(), 'should list teams for a given scope') }) t.test('--parseable', async t => { - npm.flatOptions.parseable = true + const { team, result } = await mockTeam(t, { + libnpmteam: teams, + config: { parseable: true }, + }) await team.exec(['ls', '@npmcli']) - t.matchSnapshot(result, 'should list teams for a parseable scope') + t.matchSnapshot(result(), 'should list teams for a parseable scope') }) t.test('--json', async t => { - npm.flatOptions.json = true + const { team, result } = await mockTeam(t, { + libnpmteam: teams, + config: { json: true }, + }) await team.exec(['ls', '@npmcli']) t.same( - JSON.parse(result), + JSON.parse(result()), [ 'npmcli:designers', 'npmcli:developers', @@ -201,75 +233,78 @@ t.test('team ls ', async t => { }) t.test('--silent', async t => { - npm.config.set('loglevel', 'silent') + const { team, result } = await mockTeam(t, { + libnpmteam: teams, + config: { silent: true }, + }) await team.exec(['ls', '@npmcli']) - t.same(result, '', 'should not list teams if silent') + t.same(result(), '', 'should not list teams if silent') }) t.test('no teams', async t => { - const libnpmteam = { - async lsTeams () { - return [] - }, - } - - const Team = t.mock('../../../lib/commands/team.js', { - ...mocks, - libnpmteam, + const { team, result } = await mockTeam(t, { + libnpmteam: noTeam, }) - const team = new Team(npm) await team.exec(['ls', '@npmcli']) - t.matchSnapshot(result, 'should list no teams for a given scope') + t.matchSnapshot(result(), 'should list no teams for a given scope') }) t.test('single team', async t => { - const libnpmteam = { - async lsTeams () { - return ['npmcli:developers'] - }, - } - - const Team = t.mock('../../../lib/commands/team.js', { - ...mocks, - libnpmteam, + const { team, result } = await mockTeam(t, { + libnpmteam: singleTeam, }) - const team = new Team(npm) await team.exec(['ls', '@npmcli']) - t.matchSnapshot(result, 'should list single team for a given scope') + t.matchSnapshot(result(), 'should list single team for a given scope') }) }) t.test('team ls ', async t => { - const libnpmteam = { + const users = { async lsUsers () { return ['nlf', 'ruyadorno', 'darcyclarke', 'isaacs'] }, } - const Team = t.mock('../../../lib/commands/team.js', { - ...mocks, - libnpmteam, - }) - const team = new Team(npm) + + const singleUser = { + async lsUsers () { + return ['foo'] + }, + } + + const noUsers = { + async lsUsers () { + return [] + }, + } t.test('default output', async t => { + const { team, result } = await mockTeam(t, { + libnpmteam: users, + }) await team.exec(['ls', '@npmcli:developers']) - t.matchSnapshot(result, 'should list users for a given scope:team') + t.matchSnapshot(result(), 'should list users for a given scope:team') }) t.test('--parseable', async t => { - npm.flatOptions.parseable = true + const { team, result } = await mockTeam(t, { + libnpmteam: users, + config: { parseable: true }, + }) await team.exec(['ls', '@npmcli:developers']) - t.matchSnapshot(result, 'should list users for a parseable scope:team') + t.matchSnapshot(result(), 'should list users for a parseable scope:team') }) t.test('--json', async t => { - npm.flatOptions.json = true + const { team, result } = await mockTeam(t, { + libnpmteam: users, + config: { json: true }, + }) await team.exec(['ls', '@npmcli:developers']) t.same( - JSON.parse(result), + JSON.parse(result()), [ 'darcyclarke', 'isaacs', @@ -281,63 +316,55 @@ t.test('team ls ', async t => { }) t.test('--silent', async t => { - npm.config.set('loglevel', 'silent') + const { team, result } = await mockTeam(t, { + libnpmteam: users, + config: { silent: true }, + }) await team.exec(['ls', '@npmcli:developers']) - t.same(result, '', 'should not output users if silent') + t.same(result(), '', 'should not output users if silent') }) t.test('no users', async t => { - const libnpmteam = { - async lsUsers () { - return [] - }, - } - - const Team = t.mock('../../../lib/commands/team.js', { - ...mocks, - libnpmteam, + const { team, result } = await mockTeam(t, { + libnpmteam: noUsers, }) - const team = new Team(npm) await team.exec(['ls', '@npmcli:developers']) - t.matchSnapshot(result, 'should list no users for a given scope') + t.matchSnapshot(result(), 'should list no users for a given scope') }) t.test('single user', async t => { - const libnpmteam = { - async lsUsers () { - return ['foo'] - }, - } - - const Team = t.mock('../../../lib/commands/team.js', { - ...mocks, - libnpmteam, + const { team, result } = await mockTeam(t, { + libnpmteam: singleUser, }) - const team = new Team(npm) await team.exec(['ls', '@npmcli:developers']) - t.matchSnapshot(result, 'should list single user for a given scope') + t.matchSnapshot(result(), 'should list single user for a given scope') }) }) t.test('team rm ', async t => { t.test('default output', async t => { + const { team, result } = await mockTeam(t) await team.exec(['rm', '@npmcli:newteam', 'foo']) - t.matchSnapshot(result, 'should output success result for remove user') + t.matchSnapshot(result(), 'should output success result for remove user') }) t.test('--parseable', async t => { - npm.flatOptions.parseable = true + const { team, result } = await mockTeam(t, { + config: { parseable: true }, + }) await team.exec(['rm', '@npmcli:newteam', 'foo']) - t.matchSnapshot(result, 'should output parseable result for remove user') + t.matchSnapshot(result(), 'should output parseable result for remove user') }) t.test('--json', async t => { - npm.flatOptions.json = true + const { team, result } = await mockTeam(t, { + config: { json: true }, + }) await team.exec(['rm', '@npmcli:newteam', 'foo']) t.same( - JSON.parse(result), + JSON.parse(result()), { removed: true, team: 'npmcli:newteam', @@ -348,14 +375,17 @@ t.test('team rm ', async t => { }) t.test('--silent', async t => { - npm.config.set('loglevel', 'silent') + const { team, result } = await mockTeam(t, { + config: { silent: true }, + }) await team.exec(['rm', '@npmcli:newteam', 'foo']) - t.same(result, '', 'should not output rm result if silent') + t.same(result(), '', 'should not output rm result if silent') }) }) -t.test('completion', t => { - const { completion } = team +t.test('completion', async t => { + const { npm } = await mockTeam(t) + const { completion } = await npm.cmd('team') t.test('npm team autocomplete', async t => { const res = await completion({ diff --git a/deps/npm/test/lib/commands/test.js b/deps/npm/test/lib/commands/test.js index 3a62b6a2d31b89..4786d72de2725e 100644 --- a/deps/npm/test/lib/commands/test.js +++ b/deps/npm/test/lib/commands/test.js @@ -19,11 +19,11 @@ t.test('should run test script from package.json', async t => { }, config: { loglevel: 'silent', - scriptShell: process.platform === 'win32' ? process.env.COMSPEC : 'sh', + 'script-shell': process.platform === 'win32' ? process.env.COMSPEC : 'sh', }, }) - const scriptShell = npm.config.get('scriptShell') + const scriptShell = npm.config.get('script-shell') const scriptArgs = isCmdRe.test(scriptShell) ? ['/d', '/s', '/c', 'node ./test-test.js foo'] : ['-c', 'node ./test-test.js foo'] diff --git a/deps/npm/test/lib/commands/token.js b/deps/npm/test/lib/commands/token.js index af53f49a130f5a..1fd686a4427c9b 100644 --- a/deps/npm/test/lib/commands/token.js +++ b/deps/npm/test/lib/commands/token.js @@ -1,73 +1,43 @@ const t = require('tap') +const mockNpm = require('../../fixtures/mock-npm') -const mocks = { - profile: {}, - output: () => {}, - readUserInfo: {}, -} -const npm = { - output: (...args) => mocks.output(...args), - config: { validate: () => {} }, -} +const mockToken = async (t, { profile, getCredentialsByURI, readUserInfo, ...opts } = {}) => { + const mocks = {} -const mockToken = (otherMocks) => t.mock('../../../lib/commands/token.js', { - '../../../lib/utils/read-user-info.js': mocks.readUserInfo, - 'npm-profile': mocks.profile, - ...otherMocks, -}) + if (profile) { + mocks['npm-profile'] = profile + } -const tokenWithMocks = (options = {}) => { - const { log, ...mockRequests } = options - - for (const mod in mockRequests) { - if (mod === 'npm') { - mockRequests.npm = { ...npm, ...mockRequests.npm } - mockRequests.npm.config.validate = () => {} - } else { - if (typeof mockRequests[mod] === 'function') { - mocks[mod] = mockRequests[mod] - } else { - for (const key in mockRequests[mod]) { - mocks[mod][key] = mockRequests[mod][key] - } - } - } + if (readUserInfo) { + mocks['{LIB}/utils/read-user-info.js'] = readUserInfo } - const reset = () => { - for (const mod in mockRequests) { - if (mod !== 'npm') { - if (typeof mockRequests[mod] === 'function') { - mocks[mod] = () => {} - } else { - for (const key in mockRequests[mod]) { - delete mocks[mod][key] - } - } - } - } + const mock = await mockNpm(t, { + ...opts, + mocks, + }) + + // XXX: replace with mock registry + if (getCredentialsByURI) { + mock.npm.config.getCredentialsByURI = getCredentialsByURI } - const MockedToken = mockToken(log ? { - 'proc-log': { - info: log.info, - }, - npmlog: { - gauge: log.gauge, - newItem: log.newItem, - }, - } : {}) - const token = new MockedToken(mockRequests.npm || npm) - return [token, reset] -} + const token = { + exec: (args) => mock.npm.exec('token', args), + } -t.test('completion', t => { - t.plan(5) + return { + ...mock, + token, + } +} - const [token] = tokenWithMocks() +t.test('completion', async t => { + const { npm } = await mockToken(t) + const { completion } = await npm.cmd('token') const testComp = (argv, expect) => { - t.resolveMatch(token.completion({ conf: { argv: { remain: argv } } }), expect, argv.join(' ')) + t.resolveMatch(completion({ conf: { argv: { remain: argv } } }), expect, argv.join(' ')) } testComp(['npm', 'token'], ['list', 'revoke', 'create']) @@ -75,32 +45,18 @@ t.test('completion', t => { testComp(['npm', 'token', 'revoke'], []) testComp(['npm', 'token', 'create'], []) - t.rejects(token.completion({ conf: { argv: { remain: ['npm', 'token', 'foobar'] } } }), { + t.rejects(completion({ conf: { argv: { remain: ['npm', 'token', 'foobar'] } } }), { message: 'foobar not recognize', }) }) t.test('token foobar', async t => { - t.plan(2) - - const [token, reset] = tokenWithMocks({ - log: { - gauge: { - show: name => { - t.equal(name, 'token', 'shows a gauge') - }, - }, - }, - }) - - t.teardown(reset) + const { token } = await mockToken(t) await t.rejects(token.exec(['foobar']), /foobar is not a recognized subcommand/) }) t.test('token list', async t => { - t.plan(14) - const now = new Date().toISOString() const tokens = [ { @@ -121,15 +77,11 @@ t.test('token list', async t => { }, ] - const [token, reset] = tokenWithMocks({ - npm: { - flatOptions: { registry: 'https://registry.npmjs.org', otp: '123456' }, - config: { - getCredentialsByURI: uri => { - t.equal(uri, 'https://registry.npmjs.org', 'requests correct registry') - return { token: 'thisisnotarealtoken' } - }, - }, + const { token, joinedOutput } = await mockToken(t, { + config: { registry: 'https://registry.npmjs.org', otp: '123456' }, + getCredentialsByURI: uri => { + t.equal(uri, 'https://registry.npmjs.org/', 'requests correct registry') + return { token: 'thisisnotarealtoken' } }, profile: { listTokens: conf => { @@ -137,39 +89,23 @@ t.test('token list', async t => { 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/) - t.match(lines[3], ' abcd123 ', 'includes the trimmed key') - t.match(lines[3], ' efgh56… ', 'includes the trimmed token') - t.match(lines[3], ` ${now.slice(0, 10)} `, 'includes the trimmed creation timestamp') - t.match(lines[3], ' no ', 'includes the "no" string for readonly state') - t.match(lines[5], ' abcd125 ', 'includes the trimmed key') - t.match(lines[5], ' hgfe87… ', 'includes the trimmed token') - 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) - await token.exec([]) + + const lines = joinedOutput().split(/\r?\n/) + t.match(lines[3], ' abcd123 ', 'includes the trimmed key') + t.match(lines[3], ' efgh56… ', 'includes the trimmed token') + t.match(lines[3], ` ${now.slice(0, 10)} `, 'includes the trimmed creation timestamp') + t.match(lines[3], ' no ', 'includes the "no" string for readonly state') + t.match(lines[5], ' abcd125 ', 'includes the trimmed key') + t.match(lines[5], ' hgfe87… ', 'includes the trimmed token') + 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.test('token list json output', async t => { - t.plan(7) - const now = new Date().toISOString() const tokens = [ { @@ -182,15 +118,11 @@ t.test('token list json output', async t => { }, ] - const [token, reset] = tokenWithMocks({ - npm: { - flatOptions: { registry: 'https://registry.npmjs.org', json: true }, - config: { - getCredentialsByURI: uri => { - t.equal(uri, 'https://registry.npmjs.org', 'requests correct registry') - return { username: 'foo', password: 'bar' } - }, - }, + const { token, joinedOutput } = await mockToken(t, { + config: { registry: 'https://registry.npmjs.org', json: true }, + getCredentialsByURI: uri => { + t.equal(uri, 'https://registry.npmjs.org/', 'requests correct registry') + return { username: 'foo', password: 'bar' } }, profile: { listTokens: conf => { @@ -202,32 +134,16 @@ t.test('token list json output', async t => { 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) + }) await token.exec(['list']) + + const parsed = JSON.parse(joinedOutput()) + t.match(parsed, tokens, 'prints the json parsed tokens') }) t.test('token list parseable output', async t => { - t.plan(11) - const now = new Date().toISOString() const tokens = [ { @@ -248,17 +164,11 @@ t.test('token list parseable output', async t => { }, ] - let callCount = 0 - - const [token, reset] = tokenWithMocks({ - npm: { - flatOptions: { registry: 'https://registry.npmjs.org', parseable: true }, - config: { - getCredentialsByURI: uri => { - t.equal(uri, 'https://registry.npmjs.org', 'requests correct registry') - return { auth: Buffer.from('foo:bar').toString('base64') } - }, - }, + const { token, joinedOutput } = await mockToken(t, { + config: { registry: 'https://registry.npmjs.org', parseable: true }, + getCredentialsByURI: uri => { + t.equal(uri, 'https://registry.npmjs.org/', 'requests correct registry') + return { auth: Buffer.from('foo:bar').toString('base64') } }, profile: { listTokens: conf => { @@ -270,82 +180,43 @@ t.test('token list parseable output', async t => { 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) { - t.equal( - spec, - ['key', 'token', 'created', 'readonly', 'CIDR whitelist'].join('\t'), - 'prints header' - ) - } 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 { - 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) - await token.exec(['list']) + + const lines = joinedOutput().split(/\r?\n/) + + t.equal( + lines[0], + ['key', 'token', 'created', 'readonly', 'CIDR whitelist'].join('\t'), + 'prints header' + ) + + t.equal( + lines[1], + [tokens[0].key, tokens[0].token, tokens[0].created, tokens[0].readonly, ''].join('\t'), + 'prints token info' + ) + + t.equal( + lines[2], + [ + tokens[1].key, + tokens[1].token, + tokens[1].created, + tokens[1].readonly, + tokens[1].cidr_whitelist.join(','), + ].join('\t'), + 'prints token info' + ) }) t.test('token revoke', async t => { - t.plan(9) - - const [token, reset] = tokenWithMocks({ - npm: { - flatOptions: { registry: 'https://registry.npmjs.org' }, - config: { - 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') - t.equal(len, 0) - return { - info: (name, progress) => { - t.equal(name, 'token') - t.equal(progress, 'getting existing list') - }, - } - }, + const { token, joinedOutput } = await mockToken(t, { + config: { registry: 'https://registry.npmjs.org' }, + getCredentialsByURI: uri => { + t.equal(uri, 'https://registry.npmjs.org/', 'requests correct registry') + return {} }, profile: { listTokens: conf => { @@ -356,45 +227,19 @@ t.test('token revoke', async t => { t.equal(key, 'abcd1234', 'deletes the correct token') }, }, - output: spec => { - t.equal(spec, 'Removed 1 token') - }, }) - t.teardown(reset) - await token.exec(['rm', 'abcd']) + + t.equal(joinedOutput(), 'Removed 1 token') }) t.test('token revoke multiple tokens', async t => { - t.plan(9) - - const [token, reset] = tokenWithMocks({ - npm: { - flatOptions: { registry: 'https://registry.npmjs.org' }, - 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') - }, - }, - newItem: (action, len) => { - t.equal(action, 'removing tokens') - t.equal(len, 0) - return { - info: (name, progress) => { - t.equal(name, 'token') - t.equal(progress, 'getting existing list') - }, - } - }, + const { token, joinedOutput } = await mockToken(t, { + config: { registry: 'https://registry.npmjs.org' }, + getCredentialsByURI: uri => { + t.equal(uri, 'https://registry.npmjs.org/', 'requests correct registry') + return { token: 'thisisnotarealtoken' } }, profile: { listTokens: () => Promise.resolve([{ key: 'abcd1234' }, { key: 'efgh5678' }]), @@ -403,45 +248,19 @@ t.test('token revoke multiple tokens', async t => { t.ok(['abcd1234', 'efgh5678'].includes(key), 'deletes the correct token') }, }, - output: spec => { - t.equal(spec, 'Removed 2 tokens') - }, }) - t.teardown(reset) - await token.exec(['revoke', 'abcd', 'efgh']) + + t.equal(joinedOutput(), 'Removed 2 tokens') }) t.test('token revoke json output', async t => { - t.plan(9) - - const [token, reset] = tokenWithMocks({ - npm: { - flatOptions: { registry: 'https://registry.npmjs.org', json: true }, - 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') - }, - }, - newItem: (action, len) => { - t.equal(action, 'removing tokens') - t.equal(len, 0) - return { - info: (name, progress) => { - t.equal(name, 'token') - t.equal(progress, 'getting existing list') - }, - } - }, + const { token, joinedOutput } = await mockToken(t, { + config: { registry: 'https://registry.npmjs.org', json: true }, + getCredentialsByURI: uri => { + t.equal(uri, 'https://registry.npmjs.org/', 'requests correct registry') + return { token: 'thisisnotarealtoken' } }, profile: { listTokens: () => Promise.resolve([{ key: 'abcd1234' }]), @@ -449,47 +268,21 @@ t.test('token revoke json output', async t => { 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) + }) await token.exec(['delete', 'abcd']) + + const parsed = JSON.parse(joinedOutput()) + t.same(parsed, ['abcd1234'], 'logs the token as json') }) t.test('token revoke parseable output', async t => { - t.plan(8) - - const [token, reset] = tokenWithMocks({ - npm: { - flatOptions: { registry: 'https://registry.npmjs.org', parseable: true }, - 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') - }, - }, - newItem: (action, len) => { - t.equal(action, 'removing tokens') - t.equal(len, 0) - return { - info: (name, progress) => { - t.equal(name, 'token') - t.equal(progress, 'getting existing list') - }, - } - }, + const { token, joinedOutput } = await mockToken(t, { + config: { registry: 'https://registry.npmjs.org', parseable: true }, + getCredentialsByURI: uri => { + t.equal(uri, 'https://registry.npmjs.org/', 'requests correct registry') + return { token: 'thisisnotarealtoken' } }, profile: { listTokens: () => Promise.resolve([{ key: 'abcd1234' }]), @@ -497,45 +290,19 @@ t.test('token revoke parseable output', async t => { t.equal(key, 'abcd1234', 'deletes the correct token') }, }, - output: spec => { - t.equal(spec, 'abcd1234', 'logs the token as a string') - }, }) - t.teardown(reset) - await token.exec(['remove', 'abcd']) + + t.equal(joinedOutput(), 'abcd1234', 'logs the token as a string') }) t.test('token revoke by token', async t => { - t.plan(8) - - const [token, reset] = tokenWithMocks({ - npm: { - flatOptions: { registry: 'https://registry.npmjs.org' }, - 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') - }, - }, - newItem: (action, len) => { - t.equal(action, 'removing tokens') - t.equal(len, 0) - return { - info: (name, progress) => { - t.equal(name, 'token') - t.equal(progress, 'getting existing list') - }, - } - }, + const { token, joinedOutput } = await mockToken(t, { + config: { registry: 'https://registry.npmjs.org' }, + getCredentialsByURI: uri => { + t.equal(uri, 'https://registry.npmjs.org/', 'requests correct registry') + return { token: 'thisisnotarealtoken' } }, profile: { listTokens: () => Promise.resolve([{ key: 'abcd1234', token: 'efgh5678' }]), @@ -543,143 +310,60 @@ t.test('token revoke by token', async t => { t.equal(key, 'efgh5678', 'passes through user input') }, }, - output: spec => { - t.equal(spec, 'Removed 1 token') - }, }) - t.teardown(reset) - await token.exec(['rm', 'efgh5678']) + t.equal(joinedOutput(), 'Removed 1 token') }) t.test('token revoke requires an id', async t => { - t.plan(2) - - const [token, reset] = tokenWithMocks({ - log: { - gauge: { - show: name => { - t.equal(name, 'token') - }, - }, - }, - }) - - t.teardown(reset) + const { token } = await mockToken(t) await t.rejects(token.exec(['rm']), /`` argument is required/) }) t.test('token revoke ambiguous id errors', async t => { - t.plan(7) - - const [token, reset] = tokenWithMocks({ - npm: { - flatOptions: { registry: 'https://registry.npmjs.org' }, - 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') - }, - }, - newItem: (action, len) => { - t.equal(action, 'removing tokens') - t.equal(len, 0) - return { - info: (name, progress) => { - t.equal(name, 'token') - t.equal(progress, 'getting existing list') - }, - } - }, + const { token } = await mockToken(t, { + config: { registry: 'https://registry.npmjs.org' }, + getCredentialsByURI: uri => { + t.equal(uri, 'https://registry.npmjs.org/', 'requests correct registry') + return { token: 'thisisnotarealtoken' } }, profile: { listTokens: () => Promise.resolve([{ key: 'abcd1234' }, { key: 'abcd5678' }]), }, }) - t.teardown(reset) - await t.rejects(token.exec(['rm', 'abcd']), /Token ID "abcd" was ambiguous/) }) t.test('token revoke unknown id errors', async t => { - t.plan(7) - - const [token, reset] = tokenWithMocks({ - npm: { - flatOptions: { registry: 'https://registry.npmjs.org' }, - 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') - }, - }, - newItem: (action, len) => { - t.equal(action, 'removing tokens') - t.equal(len, 0) - return { - info: (name, progress) => { - t.equal(name, 'token') - t.equal(progress, 'getting existing list') - }, - } - }, + const { token } = await mockToken(t, { + config: { registry: 'https://registry.npmjs.org' }, + getCredentialsByURI: uri => { + t.equal(uri, 'https://registry.npmjs.org/', 'requests correct registry') + return { token: 'thisisnotarealtoken' } }, profile: { listTokens: () => Promise.resolve([{ key: 'abcd1234' }]), }, }) - t.teardown(reset) - await t.rejects(token.exec(['rm', 'efgh']), /Unknown token id or value "efgh"./) }) t.test('token create', async t => { - t.plan(14) - const now = new Date().toISOString() const password = 'thisisnotreallyapassword' - const [token, reset] = tokenWithMocks({ - npm: { - flatOptions: { - registry: 'https://registry.npmjs.org', - cidr: ['10.0.0.0/8', '192.168.1.0/24'], - }, - config: { - getCredentialsByURI: uri => { - t.equal(uri, 'https://registry.npmjs.org', 'requests correct registry') - return { token: 'thisisnotarealtoken' } - }, - }, + const { token, joinedOutput } = await mockToken(t, { + config: { + registry: 'https://registry.npmjs.org', + cidr: ['10.0.0.0/8', '192.168.1.0/24'], }, - log: { - gauge: { - show: name => { - t.equal(name, 'token', 'starts a gauge') - }, - }, - info: (name, message) => { - t.equal(name, 'token') - t.equal(message, 'creating') - }, + getCredentialsByURI: uri => { + t.equal(uri, 'https://registry.npmjs.org/', 'requests correct registry') + return { token: 'thisisnotarealtoken' } }, readUserInfo: { password: () => Promise.resolve(password), @@ -687,7 +371,7 @@ t.test('token create', async t => { profile: { createToken: (pw, readonly, cidr) => { t.equal(pw, password) - t.equal(readonly, undefined) + t.equal(readonly, false) t.same(cidr, ['10.0.0.0/8', '192.168.1.0/24'], 'defaults to empty array') return { key: 'abcd1234', @@ -699,49 +383,30 @@ t.test('token create', async t => { } }, }, - output: spec => { - const lines = spec.split(/\r?\n/) - t.match(lines[1], 'token') - t.match(lines[1], 'efgh5678', 'prints the whole token') - t.match(lines[3], 'created') - t.match(lines[3], now, 'prints the correct timestamp') - t.match(lines[5], 'readonly') - t.match(lines[5], 'false', 'prints the readonly flag') - t.match(lines[7], 'cidr_whitelist') - }, - }) - t.teardown(reset) + }) await token.exec(['create']) + + const lines = joinedOutput().split(/\r?\n/) + t.match(lines[1], 'token') + t.match(lines[1], 'efgh5678', 'prints the whole token') + t.match(lines[3], 'created') + t.match(lines[3], now, 'prints the correct timestamp') + t.match(lines[5], 'readonly') + t.match(lines[5], 'false', 'prints the readonly flag') + t.match(lines[7], 'cidr_whitelist') }) t.test('token create json output', async t => { - t.plan(9) - const now = new Date().toISOString() const password = 'thisisnotreallyapassword' - const [token, reset] = tokenWithMocks({ - npm: { - flatOptions: { registry: 'https://registry.npmjs.org', json: true }, - 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') - }, - }, - info: (name, message) => { - t.equal(name, 'token') - t.equal(message, 'creating') - }, + const { token } = await mockToken(t, { + config: { registry: 'https://registry.npmjs.org', json: true }, + getCredentialsByURI: uri => { + t.equal(uri, 'https://registry.npmjs.org/', 'requests correct registry') + return { token: 'thisisnotarealtoken' } }, readUserInfo: { password: () => Promise.resolve(password), @@ -749,7 +414,7 @@ t.test('token create json output', async t => { profile: { createToken: (pw, readonly, cidr) => { t.equal(pw, password) - t.equal(readonly, undefined) + t.equal(readonly, false) t.same(cidr, [], 'defaults to empty array') return { key: 'abcd1234', @@ -772,38 +437,18 @@ t.test('token create json output', async t => { }, }) - t.teardown(reset) - await token.exec(['create']) }) t.test('token create parseable output', async t => { - t.plan(11) - const now = new Date().toISOString() const password = 'thisisnotreallyapassword' - let callCount = 0 - const [token, reset] = tokenWithMocks({ - npm: { - flatOptions: { registry: 'https://registry.npmjs.org', parseable: true }, - 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') - }, - }, - info: (name, message) => { - t.equal(name, 'token') - t.equal(message, 'creating') - }, + const { token, joinedOutput } = await mockToken(t, { + config: { registry: 'https://registry.npmjs.org', parseable: true }, + getCredentialsByURI: uri => { + t.equal(uri, 'https://registry.npmjs.org/', 'requests correct registry') + return { token: 'thisisnotarealtoken' } }, readUserInfo: { password: () => Promise.resolve(password), @@ -811,7 +456,7 @@ t.test('token create parseable output', async t => { profile: { createToken: (pw, readonly, cidr) => { t.equal(pw, password) - t.equal(readonly, undefined) + t.equal(readonly, false) t.same(cidr, [], 'defaults to empty array') return { key: 'abcd1234', @@ -823,54 +468,32 @@ t.test('token create parseable output', async t => { } }, }, - output: spec => { - ++callCount - if (callCount === 1) { - t.match(spec, 'token\tefgh5678', 'prints the token') - } else if (callCount === 2) { - t.match(spec, `created\t${now}`, 'prints the created timestamp') - } else if (callCount === 3) { - t.match(spec, 'readonly\tfalse', 'prints the readonly flag') - } else { - t.match(spec, 'cidr_whitelist\t', 'prints the cidr whitelist') - } - }, }) - t.teardown(reset) - await token.exec(['create']) + + const spec = joinedOutput().split(/\r?\n/) + + t.match(spec[0], 'token\tefgh5678', 'prints the token') + t.match(spec[1], `created\t${now}`, 'prints the created timestamp') + t.match(spec[2], 'readonly\tfalse', 'prints the readonly flag') + t.match(spec[3], 'cidr_whitelist\t', 'prints the cidr whitelist') }) t.test('token create ipv6 cidr', async t => { - t.plan(3) - const password = 'thisisnotreallyapassword' - const [token, reset] = tokenWithMocks({ - npm: { - 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') - }, - }, + const { token } = await mockToken(t, { + config: { registry: 'https://registry.npmjs.org', cidr: '::1/128' }, + getCredentialsByURI: uri => { + t.equal(uri, 'https://registry.npmjs.org/', 'requests correct registry') + return { token: 'thisisnotarealtoken' } }, readUserInfo: { password: () => Promise.resolve(password), }, }) - t.teardown(reset) - await t.rejects( token.exec(['create']), { @@ -882,34 +505,19 @@ t.test('token create ipv6 cidr', async t => { }) t.test('token create invalid cidr', async t => { - t.plan(3) - const password = 'thisisnotreallyapassword' - const [token, reset] = tokenWithMocks({ - npm: { - 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') - }, - }, + const { token } = await mockToken(t, { + config: { registry: 'https://registry.npmjs.org', cidr: 'apple/cider' }, + getCredentialsByURI: uri => { + t.equal(uri, 'https://registry.npmjs.org/', 'requests correct registry') + return { token: 'thisisnotarealtoken' } }, readUserInfo: { password: () => Promise.resolve(password), }, }) - t.teardown(reset) - await t.rejects( token.exec(['create']), { code: 'EINVALIDCIDR', message: /CIDR whitelist contains invalid CIDR entry: apple\/cider/ }, diff --git a/deps/npm/test/lib/commands/uninstall.js b/deps/npm/test/lib/commands/uninstall.js index ec7961f9c96c4e..59a517d144d38a 100644 --- a/deps/npm/test/lib/commands/uninstall.js +++ b/deps/npm/test/lib/commands/uninstall.js @@ -1,225 +1,205 @@ const t = require('tap') const fs = require('fs') const { resolve } = require('path') -const { fake: mockNpm } = require('../../fixtures/mock-npm') - -const npm = mockNpm({ - globalDir: '', - config: { - global: false, - prefix: '', - }, - localPrefix: '', -}) -const mocks = { - '../../../lib/utils/reify-finish.js': () => Promise.resolve(), -} - -const Uninstall = t.mock('../../../lib/commands/uninstall.js', mocks) -const uninstall = new Uninstall(npm) +const _mockNpm = require('../../fixtures/mock-npm') + +const mockNpm = async (t, opts = {}) => { + const res = await _mockNpm(t, { + ...opts, + mocks: { + ...opts.mocks, + '{LIB}/utils/reify-finish.js': async () => {}, + }, + }) -t.afterEach(() => { - npm.globalDir = '' - npm.prefix = '' - npm.localPrefix = '' - npm.flatOptions.global = false - npm.flatOptions.prefix = '' -}) + return { + ...res, + uninstall: (args) => res.npm.exec('uninstall', args), + } +} t.test('remove single installed lib', async t => { - const path = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-rm-single-lib', - version: '1.0.0', - dependencies: { - a: '*', - b: '*', - }, - }), - node_modules: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'b', - version: '1.0.0', - }), - }, - }, - 'package-lock.json': JSON.stringify({ - name: 'test-rm-single-lib', - version: '1.0.0', - lockfileVersion: 2, - requires: true, - packages: { - '': { - name: 'test-rm-single-lib', - version: '1.0.0', - dependencies: { - a: '*', - }, - }, - 'node_modules/a': { - version: '1.0.0', - }, - 'node_modules/b': { - version: '1.0.0', + const { uninstall, prefix } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-rm-single-lib', + version: '1.0.0', + dependencies: { + a: '*', + b: '*', }, - }, - dependencies: { + }), + node_modules: { a: { - version: '1.0.0', + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + }), }, b: { - version: '1.0.0', + 'package.json': JSON.stringify({ + name: 'b', + version: '1.0.0', + }), }, }, - }), + 'package-lock.json': JSON.stringify({ + name: 'test-rm-single-lib', + version: '1.0.0', + lockfileVersion: 2, + requires: true, + packages: { + '': { + name: 'test-rm-single-lib', + version: '1.0.0', + dependencies: { + a: '*', + }, + }, + 'node_modules/a': { + version: '1.0.0', + }, + 'node_modules/b': { + version: '1.0.0', + }, + }, + dependencies: { + a: { + version: '1.0.0', + }, + b: { + version: '1.0.0', + }, + }, + }), + }, }) - const b = resolve(path, 'node_modules/b') - t.ok(() => fs.statSync(b)) + const b = resolve(prefix, 'node_modules/b') + t.ok(fs.statSync(b)) - npm.localPrefix = path - - await uninstall.exec(['b']) + await uninstall(['b']) t.throws(() => fs.statSync(b), 'should have removed package from npm') }) t.test('remove multiple installed libs', async t => { - const path = t.testdir({ - node_modules: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'b', - version: '1.0.0', - }), - }, - }, - 'package-lock.json': JSON.stringify({ - name: 'test-rm-single-lib', - version: '1.0.0', - lockfileVersion: 2, - requires: true, - packages: { - '': { - name: 'test-rm-single-lib', - version: '1.0.0', - dependencies: { - a: '*', - }, - }, - 'node_modules/a': { - version: '1.0.0', - }, - 'node_modules/b': { - version: '1.0.0', - }, - }, - dependencies: { + const { uninstall, prefix } = await mockNpm(t, { + prefixDir: { + node_modules: { a: { - version: '1.0.0', + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + }), }, b: { - version: '1.0.0', + 'package.json': JSON.stringify({ + name: 'b', + version: '1.0.0', + }), }, }, - }), + 'package-lock.json': JSON.stringify({ + name: 'test-rm-single-lib', + version: '1.0.0', + lockfileVersion: 2, + requires: true, + packages: { + '': { + name: 'test-rm-single-lib', + version: '1.0.0', + dependencies: { + a: '*', + }, + }, + 'node_modules/a': { + version: '1.0.0', + }, + 'node_modules/b': { + version: '1.0.0', + }, + }, + dependencies: { + a: { + version: '1.0.0', + }, + b: { + version: '1.0.0', + }, + }, + }), + }, }) - const a = resolve(path, 'node_modules/a') - const b = resolve(path, 'node_modules/b') - t.ok(() => fs.statSync(a)) - t.ok(() => fs.statSync(b)) - - npm.localPrefix = path + const a = resolve(prefix, 'node_modules/a') + const b = resolve(prefix, 'node_modules/b') + t.ok(fs.statSync(a)) + t.ok(fs.statSync(b)) - await uninstall.exec(['b']) + await uninstall(['b']) t.throws(() => fs.statSync(a), 'should have removed a package from nm') t.throws(() => fs.statSync(b), 'should have removed b package from nm') }) t.test('no args local', async t => { - const path = t.testdir() - - npm.flatOptions.prefix = path + const { uninstall } = await mockNpm(t) await t.rejects( - uninstall.exec([]), + uninstall([]), /Must provide a package name to remove/, 'should throw package name required error' ) }) t.test('no args global', async t => { - const path = t.testdir({ - lib: { - node_modules: { - a: t.fixture('symlink', '../../projects/a'), - }, + const { uninstall, npm } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + }), }, - projects: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - }), + globalPrefixDir: { + node_modules: { + a: t.fixture('symlink', '../../prefix'), }, }, + config: { global: true }, }) - npm.localPrefix = resolve(path, 'projects', 'a') - npm.globalDir = resolve(path, 'lib', 'node_modules') - npm.config.set('global', true) - - const a = resolve(path, 'lib/node_modules/a') - t.ok(() => fs.statSync(a)) + const a = resolve(npm.globalDir, 'a') + t.ok(fs.statSync(a)) - await uninstall.exec([]) + await uninstall([]) t.throws(() => fs.statSync(a), 'should have removed global nm symlink') }) t.test('no args global but no package.json', async t => { - const path = t.testdir({}) - - npm.prefix = path - npm.localPrefix = path - npm.flatOptions.global = true + const { uninstall } = await mockNpm(t, { + config: { global: true }, + }) await t.rejects( - uninstall.exec([]), + uninstall([]), /npm uninstall/ ) }) t.test('unknown error reading from localPrefix package.json', async t => { - const path = t.testdir({}) - - const Uninstall = t.mock('../../../lib/commands/uninstall.js', { - ...mocks, - 'read-package-json-fast': () => Promise.reject(new Error('ERR')), + const { uninstall } = await mockNpm(t, { + config: { global: true }, + mocks: { + 'read-package-json-fast': async () => { + throw new Error('ERR') + }, + }, }) - const uninstall = new Uninstall(npm) - - npm.prefix = path - npm.localPrefix = path - npm.flatOptions.global = true await t.rejects( - uninstall.exec([]), + uninstall([]), /ERR/, 'should throw unknown error' ) diff --git a/deps/npm/test/lib/commands/update.js b/deps/npm/test/lib/commands/update.js index fe52554c95f255..f42fb8a4146b02 100644 --- a/deps/npm/test/lib/commands/update.js +++ b/deps/npm/test/lib/commands/update.js @@ -1,166 +1,83 @@ const t = require('tap') -const { resolve } = require('path') -const { fake: mockNpm } = require('../../fixtures/mock-npm') +const _mockNpm = require('../../fixtures/mock-npm') + +// XXX: this test has been refactored to use the new mockNpm +// but it still only asserts the options passed to arborist. +// TODO: make this really test npm update scenarios +const mockUpdate = async (t, { exec = [], ...opts } = {}) => { + let ctor = null + let reify = null + let finish = null + + const res = await _mockNpm(t, { + ...opts, + mocks: { + '@npmcli/arborist': class Arborist { + constructor (o) { + ctor = o + } + + reify (o) { + reify = o + } + }, + '{LIB}/utils/reify-finish.js': (_, o) => { + finish = o + }, + }, + }) -const config = { - depth: 0, - global: false, -} -const noop = () => null -const npm = mockNpm({ - globalDir: '', - config, - prefix: '', -}) -const mocks = { - '@npmcli/arborist': class { - reify () {} - }, - '../../../lib/utils/reify-finish.js': noop, -} + await res.npm.exec('update', exec) -t.afterEach(() => { - npm.prefix = '' - config.global = false - npm.globalDir = '' -}) + return { + ...res, + ctor, + reify, + finish, + } +} t.test('no args', async t => { - t.plan(4) - - npm.prefix = '/project/a' - - class Arborist { - constructor (args) { - const { log, ...rest } = args - t.same( - rest, - { - ...npm.flatOptions, - path: npm.prefix, - save: false, - workspaces: null, - }, - 'should call arborist contructor with expected args' - ) - } + const { ctor, reify, finish, prefix } = await mockUpdate(t) - reify ({ save, update }) { - t.equal(save, false, 'should default to save=false') - t.equal(update, true, 'should update all deps') - } - } + t.equal(ctor.path, prefix, 'path') + t.equal(ctor.save, false, 'should default to save=false') + t.equal(ctor.workspaces, undefined, 'workspaces') - const Update = t.mock('../../../lib/commands/update.js', { - ...mocks, - '../../../lib/utils/reify-finish.js': (npm, arb) => { - t.match(arb, Arborist, 'should reify-finish with arborist instance') - }, - '@npmcli/arborist': Arborist, - }) - const update = new Update(npm) + t.equal(reify.update, true, 'should update all deps') - await update.exec([]) + t.equal(finish.constructor.name, 'Arborist') }) t.test('with args', async t => { - t.plan(4) - - npm.prefix = '/project/a' - config.save = true - - class Arborist { - constructor (args) { - const { log, ...rest } = args - t.same( - rest, - { - ...npm.flatOptions, - path: npm.prefix, - save: true, - workspaces: null, - }, - 'should call arborist contructor with expected args' - ) - } - - reify ({ save, update }) { - t.equal(save, true, 'should pass save if manually set') - t.same(update, ['ipt'], 'should update listed deps') - } - } - - const Update = t.mock('../../../lib/commands/update.js', { - ...mocks, - '../../../lib/utils/reify-finish.js': (npm, arb) => { - t.match(arb, Arborist, 'should reify-finish with arborist instance') - }, - '@npmcli/arborist': Arborist, + const { ctor, reify } = await mockUpdate(t, { + config: { save: true }, + exec: ['ipt'], }) - const update = new Update(npm) - await update.exec(['ipt']) + t.equal(ctor.save, true, 'save') + t.strictSame(reify.update, ['ipt'], 'ipt') }) t.test('update --depth=', async t => { - t.plan(2) - - npm.prefix = '/project/a' - config.depth = 1 - - const Update = t.mock('../../../lib/commands/update.js', { - ...mocks, - 'proc-log': { - warn: (title, msg) => { - t.equal(title, 'update', 'should print expected title') - t.match( - msg, - /The --depth option no longer has any effect/, - 'should print expected warning message' - ) - }, - }, + const { logs } = await mockUpdate(t, { + config: { depth: 1 }, }) - const update = new Update(npm) - await update.exec([]) + const [title, msg] = logs.warn[0] + t.equal(title, 'update', 'should print expected title') + t.match( + msg, + /The --depth option no longer has any effect/, + 'should print expected warning message' + ) }) t.test('update --global', async t => { - t.plan(2) - - const normalizePath = p => p.replace(/\\+/g, '/') - const redactCwd = (path) => normalizePath(path) - .replace(new RegExp(normalizePath(process.cwd()), 'g'), '{CWD}') - - npm.prefix = '/project/a' - npm.globalDir = resolve(process.cwd(), 'global/lib/node_modules') - config.global = true - - class Arborist { - constructor (args) { - const { path, log, ...rest } = args - t.same( - rest, - { ...npm.flatOptions, save: true, workspaces: undefined }, - 'should call arborist contructor with expected options' - ) - - t.equal( - redactCwd(path), - '{CWD}/global/lib', - 'should run with expected prefix' - ) - } - - reify () {} - } - - const Update = t.mock('../../../lib/commands/update.js', { - ...mocks, - '@npmcli/arborist': Arborist, + const { ctor, globalPrefix } = await mockUpdate(t, { + config: { global: true }, }) - const update = new Update(npm) - await update.exec([]) + t.match(ctor.path, globalPrefix) + t.ok(ctor.path.startsWith(globalPrefix)) }) diff --git a/deps/npm/test/lib/commands/version.js b/deps/npm/test/lib/commands/version.js index 154f6a6f83361a..c48ff827fa28cb 100644 --- a/deps/npm/test/lib/commands/version.js +++ b/deps/npm/test/lib/commands/version.js @@ -1,75 +1,52 @@ const { readFileSync, statSync } = require('fs') const { resolve } = require('path') const t = require('tap') -const { fake: mockNpm } = require('../../fixtures/mock-npm') +const _mockNpm = require('../../fixtures/mock-npm') const mockGlobals = require('../../fixtures/mock-globals.js') -let result = [] - -const noop = () => null -const config = { - 'git-tag-version': true, - 'tag-version-prefix': 'v', - json: false, -} -const flatOptions = { - workspacesUpdate: true, -} -const npm = mockNpm({ - config, - flatOptions, - localPrefix: '', - prefix: '', - version: '1.0.0', - output: (...msg) => { - for (const m of msg) { - result.push(m) - } - }, -}) -const mocks = { - '../../../lib/utils/reify-finish.js': noop, +const mockNpm = async (t, opts = {}) => { + const res = await _mockNpm(t, { + ...opts, + mocks: { + ...opts.mocks, + '{ROOT}/package.json': { version: '1.0.0' }, + }, + }) + return { + ...res, + version: { exec: (args) => res.npm.exec('version', args) }, + result: () => res.outputs[0], + } } -const Version = t.mock('../../../lib/commands/version.js', mocks) -const version = new Version(npm) - -t.afterEach(() => { - flatOptions.workspacesUpdate = true - config.json = false - npm.localPrefix = '' - npm.prefix = '' - result = [] -}) - -t.test('node@1', t => { +t.test('node@1', async t => { mockGlobals(t, { 'process.versions': { node: '1.0.0' } }, { replace: true }) t.test('no args', async t => { - const prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'test-version-no-args', - version: '3.2.1', - }), + const { version, result } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: 'test-version-no-args', + version: '3.2.1', + }), + }, }) - npm.prefix = prefix await version.exec([]) - t.same( - result, - [ - { - 'test-version-no-args': '3.2.1', - node: '1.0.0', - npm: '1.0.0', - }, - ], + t.strictSame( + result(), + [{ + 'test-version-no-args': '3.2.1', + node: '1.0.0', + npm: '1.0.0', + }], 'should output expected values for various versions in npm' ) }) t.test('too many args', async t => { + const { version } = await mockNpm(t) await t.rejects( version.exec(['foo', 'bar']), /npm version/, @@ -78,6 +55,8 @@ t.test('node@1', t => { }) t.test('completion', async t => { + const { npm } = await mockNpm(t) + const version = await npm.cmd('version') const testComp = async (argv, expect) => { const res = await version.completion({ conf: { argv: { remain: argv } } }) t.strictSame(res, expect, argv.join(' ')) @@ -88,99 +67,79 @@ t.test('node@1', t => { ['major', 'minor', 'patch', 'premajor', 'preminor', 'prepatch', 'prerelease', 'from-git'] ) await testComp(['npm', 'version', 'major'], []) - - t.end() }) t.test('failure reading package.json', async t => { - const prefix = t.testdir({}) - npm.prefix = prefix + const { version, result } = await mockNpm(t) await version.exec([]) - t.same( - result, - [ - { - npm: '1.0.0', - node: '1.0.0', - }, - ], + t.strictSame( + result(), + [{ + npm: '1.0.0', + node: '1.0.0', + }], 'should not have package name on returning object' ) }) - t.end() }) -t.test('empty versions', t => { +t.test('empty versions', async t => { mockGlobals(t, { 'process.versions': {} }, { replace: true }) t.test('--json option', async t => { - const prefix = t.testdir({}) - config.json = true - npm.prefix = prefix + const { version, result } = await mockNpm(t, { + config: { json: true }, + }) await version.exec([]) - t.same(result, ['{\n "npm": "1.0.0"\n}'], 'should return json stringified result') + t.same(result(), ['{\n "npm": "1.0.0"\n}'], 'should return json stringified result') }) t.test('with one arg', async t => { - const Version = t.mock('../../../lib/commands/version.js', { - ...mocks, - libnpmversion: (arg, opts) => { - t.equal(arg, 'major', 'should forward expected value') - t.match( - opts, - { - path: '', - }, - 'should forward expected options' - ) - return '4.0.0' + const { version, result } = await mockNpm(t, { + mocks: { + libnpmversion: () => '4.0.0', }, }) - const version = new Version(npm) await version.exec(['major']) - t.same(result, ['v4.0.0'], 'outputs the new version prefixed by the tagVersionPrefix') + t.same(result(), ['v4.0.0'], 'outputs the new version prefixed by the tagVersionPrefix') }) t.test('workspaces', async t => { - t.teardown(() => { - npm.localPrefix = '' - npm.prefix = '' - }) - t.test('no args, all workspaces', async t => { - const testDir = t.testdir({ - 'package.json': JSON.stringify( - { - name: 'workspaces-test', - version: '1.0.0', - workspaces: ['workspace-a', 'workspace-b'], + const { version, result } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify( + { + name: 'workspaces-test', + version: '1.0.0', + workspaces: ['workspace-a', 'workspace-b'], + }, + null, + 2 + ), + 'workspace-a': { + 'package.json': JSON.stringify({ + name: 'workspace-a', + version: '1.0.0', + }), + }, + 'workspace-b': { + 'package.json': JSON.stringify({ + name: 'workspace-b', + version: '1.0.0', + }), }, - null, - 2 - ), - 'workspace-a': { - 'package.json': JSON.stringify({ - name: 'workspace-a', - version: '1.0.0', - }), - }, - 'workspace-b': { - 'package.json': JSON.stringify({ - name: 'workspace-b', - version: '1.0.0', - }), }, + config: { workspaces: true }, }) - npm.localPrefix = testDir - npm.prefix = testDir - const version = new Version(npm) - await version.execWorkspaces([], []) + + await version.exec([]) t.same( - result, + result(), [ { 'workspaces-test': '1.0.0', @@ -194,35 +153,38 @@ t.test('empty versions', t => { }) t.test('no args, single workspaces', async t => { - const testDir = t.testdir({ - 'package.json': JSON.stringify( - { - name: 'workspaces-test', - version: '1.0.0', - workspaces: ['workspace-a', 'workspace-b'], + const { version, result } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify( + { + name: 'workspaces-test', + version: '1.0.0', + workspaces: ['workspace-a', 'workspace-b'], + }, + null, + 2 + ), + 'workspace-a': { + 'package.json': JSON.stringify({ + name: 'workspace-a', + version: '1.0.0', + }), + }, + 'workspace-b': { + 'package.json': JSON.stringify({ + name: 'workspace-b', + version: '1.0.0', + }), }, - null, - 2 - ), - 'workspace-a': { - 'package.json': JSON.stringify({ - name: 'workspace-a', - version: '1.0.0', - }), }, - 'workspace-b': { - 'package.json': JSON.stringify({ - name: 'workspace-b', - version: '1.0.0', - }), + config: { + workspace: 'workspace-a', }, }) - npm.localPrefix = testDir - npm.prefix = testDir - const version = new Version(npm) - await version.execWorkspaces([], ['workspace-a']) + + await version.exec([]) t.same( - result, + result(), [ { 'workspaces-test': '1.0.0', @@ -235,39 +197,40 @@ t.test('empty versions', t => { }) t.test('no args, all workspaces, workspace with missing name or version', async t => { - const testDir = t.testdir({ - 'package.json': JSON.stringify( - { - name: 'workspaces-test', - version: '1.0.0', - workspaces: ['workspace-a', 'workspace-b', 'workspace-c'], + const { version, result } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify( + { + name: 'workspaces-test', + version: '1.0.0', + workspaces: ['workspace-a', 'workspace-b', 'workspace-c'], + }, + null, + 2 + ), + 'workspace-a': { + 'package.json': JSON.stringify({ + name: 'workspace-a', + version: '1.0.0', + }), + }, + 'workspace-b': { + 'package.json': JSON.stringify({ + name: 'workspace-b', + }), + }, + 'workspace-c': { + 'package.json': JSON.stringify({ + version: '1.0.0', + }), }, - null, - 2 - ), - 'workspace-a': { - 'package.json': JSON.stringify({ - name: 'workspace-a', - version: '1.0.0', - }), - }, - 'workspace-b': { - 'package.json': JSON.stringify({ - name: 'workspace-b', - }), - }, - 'workspace-c': { - 'package.json': JSON.stringify({ - version: '1.0.0', - }), }, + config: { workspaces: true }, }) - npm.localPrefix = testDir - npm.prefix = testDir - const version = new Version(npm) - await version.execWorkspaces([], []) + + await version.exec([]) t.same( - result, + result(), [ { 'workspaces-test': '1.0.0', @@ -280,151 +243,145 @@ t.test('empty versions', t => { }) t.test('with one arg, all workspaces', async t => { - const testDir = t.testdir({ - 'package.json': JSON.stringify( - { - name: 'workspaces-test', - version: '1.0.0', - workspaces: ['workspace-a', 'workspace-b'], + const { version, outputs, prefix } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify( + { + name: 'workspaces-test', + version: '1.0.0', + workspaces: ['workspace-a', 'workspace-b'], + }, + null, + 2 + ), + 'workspace-a': { + 'package.json': JSON.stringify({ + name: 'workspace-a', + version: '1.0.0', + }), + }, + 'workspace-b': { + 'package.json': JSON.stringify({ + name: 'workspace-b', + version: '1.0.0', + }), }, - null, - 2 - ), - 'workspace-a': { - 'package.json': JSON.stringify({ - name: 'workspace-a', - version: '1.0.0', - }), - }, - 'workspace-b': { - 'package.json': JSON.stringify({ - name: 'workspace-b', - version: '1.0.0', - }), }, + config: { workspaces: true }, }) - const Version = t.mock('../../../lib/commands/version.js', { - '../../../lib/utils/reify-finish.js': noop, - }) - npm.localPrefix = testDir - npm.prefix = testDir - const version = new Version(npm) - await version.execWorkspaces(['major'], []) + await version.exec(['major']) t.same( - result, + outputs.map(o => o[0]).slice(0, 4), ['workspace-a', 'v2.0.0', 'workspace-b', 'v2.0.0'], 'outputs the new version for only the workspaces prefixed by the tagVersionPrefix' ) - t.matchSnapshot(readFileSync(resolve(testDir, 'package-lock.json'), 'utf8')) + t.matchSnapshot(readFileSync(resolve(prefix, 'package-lock.json'), 'utf8')) }) t.test('with one arg, all workspaces, saves package.json', async t => { - const testDir = t.testdir({ - 'package.json': JSON.stringify( - { - name: 'workspaces-test', - version: '1.0.0', - workspaces: ['workspace-a', 'workspace-b'], - dependencies: { - 'workspace-a': '^1.0.0', - 'workspace-b': '^1.0.0', + const { version, outputs, prefix } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify( + { + name: 'workspaces-test', + version: '1.0.0', + workspaces: ['workspace-a', 'workspace-b'], + dependencies: { + 'workspace-a': '^1.0.0', + 'workspace-b': '^1.0.0', + }, }, + null, + 2 + ), + 'workspace-a': { + 'package.json': JSON.stringify({ + name: 'workspace-a', + version: '1.0.0', + }), + }, + 'workspace-b': { + 'package.json': JSON.stringify({ + name: 'workspace-b', + version: '1.0.0', + }), }, - null, - 2 - ), - 'workspace-a': { - 'package.json': JSON.stringify({ - name: 'workspace-a', - version: '1.0.0', - }), }, - 'workspace-b': { - 'package.json': JSON.stringify({ - name: 'workspace-b', - version: '1.0.0', - }), + config: { + save: true, + workspaces: true, }, }) - const Version = t.mock('../../../lib/commands/version.js', { - '../../../lib/utils/reify-finish.js': noop, - }) - config.save = true - npm.localPrefix = testDir - npm.prefix = testDir - const version = new Version(npm) - await version.execWorkspaces(['major'], []) + await version.exec(['major']) t.same( - result, + outputs.map(o => o[0]).slice(0, 4), ['workspace-a', 'v2.0.0', 'workspace-b', 'v2.0.0'], 'outputs the new version for only the workspaces prefixed by the tagVersionPrefix' ) - t.matchSnapshot(readFileSync(resolve(testDir, 'package-lock.json'), 'utf8')) + t.matchSnapshot(readFileSync(resolve(prefix, 'package-lock.json'), 'utf8')) }) t.test('too many args', async t => { + const { version } = await mockNpm(t, { config: { workspaces: true } }) + await t.rejects( - version.execWorkspaces(['foo', 'bar'], []), + version.exec(['foo', 'bar']), /npm version/, 'should throw usage instructions error' ) }) t.test('no workspaces-update', async t => { - flatOptions.workspacesUpdate = false - - const libNpmVersionArgs = [] - const testDir = t.testdir({ - 'package.json': JSON.stringify( - { - name: 'workspaces-test', - version: '1.0.0', - workspaces: ['workspace-a', 'workspace-b'], + const { version, outputs, prefix } = await mockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify( + { + name: 'workspaces-test', + version: '1.0.0', + workspaces: ['workspace-a', 'workspace-b'], + }, + null, + 2 + ), + 'workspace-a': { + 'package.json': JSON.stringify({ + name: 'workspace-a', + version: '1.0.0', + }), + }, + 'workspace-b': { + 'package.json': JSON.stringify({ + name: 'workspace-b', + version: '1.0.0', + }), }, - null, - 2 - ), - 'workspace-a': { - 'package.json': JSON.stringify({ - name: 'workspace-a', - version: '1.0.0', - }), }, - 'workspace-b': { - 'package.json': JSON.stringify({ - name: 'workspace-b', - version: '1.0.0', - }), + mocks: { + libnpmversion: (arg, opts) => { + return '2.0.0' + }, }, - }) - const Version = t.mock('../../../lib/commands/version.js', { - ...mocks, - libnpmversion: (arg, opts) => { - libNpmVersionArgs.push([arg, opts]) - return '2.0.0' + config: { + workspaces: true, + 'workspaces-update': false, }, }) - npm.localPrefix = testDir - npm.prefix = testDir - const version = new Version(npm) - await version.execWorkspaces(['major'], []) + await version.exec(['major']) t.same( - result, + outputs.map(o => o[0]).slice(0, 4), ['workspace-a', 'v2.0.0', 'workspace-b', 'v2.0.0'], 'outputs the new version for only the workspaces prefixed by the tagVersionPrefix' ) t.throws( - () => statSync(resolve(testDir, 'package-lock.json')), + () => statSync(resolve(prefix, 'package-lock.json')), 'should not have a lockfile since have not reified' ) }) }) - - t.end() }) diff --git a/deps/npm/test/lib/commands/view.js b/deps/npm/test/lib/commands/view.js index d347bc9230ec8a..c6a4bf8fb79f44 100644 --- a/deps/npm/test/lib/commands/view.js +++ b/deps/npm/test/lib/commands/view.js @@ -262,93 +262,88 @@ const packument = (nv, opts) => { } const loadMockNpm = async function (t, opts = {}) { - const consoleLogs = [] const mockNpm = await _loadMockNpm(t, { + command: 'view', mocks: { pacote: { packument, }, }, - globals: { - 'console.log': (...args) => { - consoleLogs.push(args) - }, - }, ...opts, }) - return { ...mockNpm, consoleLogs } + return mockNpm } t.test('package from git', async t => { - const { npm, consoleLogs } = await loadMockNpm(t, { config: { unicode: false } }) - await npm.exec('view', ['https://github.com/npm/green']) - t.matchSnapshot(consoleLogs.join('\n')) + const { view, outputs } = await loadMockNpm(t, { config: { unicode: false } }) + await view.exec(['https://github.com/npm/green']) + t.matchSnapshot(outputs.join('\n')) }) t.test('deprecated package with license, bugs, repository and other fields', async t => { - const { npm, consoleLogs } = await loadMockNpm(t, { config: { unicode: false } }) - await npm.exec('view', ['green@1.0.0']) - t.matchSnapshot(consoleLogs.join('\n')) + const { view, outputs } = await loadMockNpm(t, { config: { unicode: false } }) + await view.exec(['green@1.0.0']) + t.matchSnapshot(outputs.join('\n')) }) t.test('deprecated package with unicode', async t => { - const { npm, consoleLogs } = await loadMockNpm(t, { config: { unicode: true } }) - await npm.exec('view', ['green@1.0.0']) - t.matchSnapshot(consoleLogs.join('\n')) + const { view, outputs } = await loadMockNpm(t, { config: { unicode: true } }) + await view.exec(['green@1.0.0']) + t.matchSnapshot(outputs.join('\n')) }) t.test('package with more than 25 deps', async t => { - const { npm, consoleLogs } = await loadMockNpm(t, { config: { unicode: false } }) - await npm.exec('view', ['black@1.0.0']) - t.matchSnapshot(consoleLogs.join('\n')) + const { view, outputs } = await loadMockNpm(t, { config: { unicode: false } }) + await view.exec(['black@1.0.0']) + t.matchSnapshot(outputs.join('\n')) }) t.test('package with maintainers info as object', async t => { - const { npm, consoleLogs } = await loadMockNpm(t, { config: { unicode: false } }) - await npm.exec('view', ['pink@1.0.0']) - t.matchSnapshot(consoleLogs.join('\n')) + const { view, outputs } = await loadMockNpm(t, { config: { unicode: false } }) + await view.exec(['pink@1.0.0']) + t.matchSnapshot(outputs.join('\n')) }) t.test('package with homepage', async t => { - const { npm, consoleLogs } = await loadMockNpm(t, { config: { unicode: false } }) - await npm.exec('view', ['orange@1.0.0']) - t.matchSnapshot(consoleLogs.join('\n')) + const { view, outputs } = await loadMockNpm(t, { config: { unicode: false } }) + await view.exec(['orange@1.0.0']) + t.matchSnapshot(outputs.join('\n')) }) t.test('package with no versions', async t => { - const { npm, consoleLogs } = await loadMockNpm(t, { config: { unicode: false } }) - await npm.exec('view', ['brown']) - t.equal(consoleLogs.join('\n'), '', 'no info to display') + const { view, outputs } = await loadMockNpm(t, { config: { unicode: false } }) + await view.exec(['brown']) + t.equal(outputs.join('\n'), '', 'no info to display') }) t.test('package with no repo or homepage', async t => { - const { npm, consoleLogs } = await loadMockNpm(t, { config: { unicode: false } }) - await npm.exec('view', ['blue@1.0.0']) - t.matchSnapshot(consoleLogs.join('\n')) + const { view, outputs } = await loadMockNpm(t, { config: { unicode: false } }) + await view.exec(['blue@1.0.0']) + t.matchSnapshot(outputs.join('\n')) }) t.test('package with semver range', async t => { - const { npm, consoleLogs } = await loadMockNpm(t, { config: { unicode: false } }) - await npm.exec('view', ['blue@^1.0.0']) - t.matchSnapshot(consoleLogs.join('\n')) + const { view, outputs } = await loadMockNpm(t, { config: { unicode: false } }) + await view.exec(['blue@^1.0.0']) + t.matchSnapshot(outputs.join('\n')) }) t.test('package with no modified time', async t => { - const { npm, consoleLogs } = await loadMockNpm(t, { config: { unicode: false } }) - await npm.exec('view', ['cyan@1.0.0']) - t.matchSnapshot(consoleLogs.join('\n')) + const { view, outputs } = await loadMockNpm(t, { config: { unicode: false } }) + await view.exec(['cyan@1.0.0']) + t.matchSnapshot(outputs.join('\n')) }) t.test('package with --json and semver range', async t => { - const { npm, consoleLogs } = await loadMockNpm(t, { config: { json: true } }) - await npm.exec('view', ['cyan@^1.0.0']) - t.matchSnapshot(consoleLogs.join('\n')) + const { view, outputs } = await loadMockNpm(t, { config: { json: true } }) + await view.exec(['cyan@^1.0.0']) + t.matchSnapshot(outputs.join('\n')) }) t.test('package with --json and no versions', async t => { - const { npm, consoleLogs } = await loadMockNpm(t, { config: { json: true } }) - await npm.exec('view', ['brown']) - t.equal(consoleLogs.join('\n'), '', 'no info to display') + const { view, outputs } = await loadMockNpm(t, { config: { json: true } }) + await view.exec(['brown']) + t.equal(outputs.join('\n'), '', 'no info to display') }) t.test('package in cwd', async t => { @@ -360,72 +355,71 @@ t.test('package in cwd', async t => { } t.test('specific version', async t => { - const { npm, consoleLogs } = await loadMockNpm(t, { prefixDir }) - await npm.exec('view', ['.@1.0.0']) - t.matchSnapshot(consoleLogs.join('\n')) + const { view, outputs } = await loadMockNpm(t, { prefixDir }) + await view.exec(['.@1.0.0']) + t.matchSnapshot(outputs.join('\n')) }) t.test('non-specific version', async t => { - const { npm, consoleLogs } = await loadMockNpm(t, { prefixDir }) - await npm.exec('view', ['.']) - t.matchSnapshot(consoleLogs.join('\n')) + const { view, outputs } = await loadMockNpm(t, { prefixDir }) + await view.exec(['.']) + t.matchSnapshot(outputs.join('\n')) }) t.test('directory', async t => { - const { npm, consoleLogs } = await loadMockNpm(t, { prefixDir }) - await npm.exec('view', ['./blue']) - t.matchSnapshot(consoleLogs.join('\n')) + const { view, outputs } = await loadMockNpm(t, { prefixDir }) + await view.exec(['./blue']) + t.matchSnapshot(outputs.join('\n')) }) }) t.test('specific field names', async t => { - const { npm, consoleLogs } = await loadMockNpm(t) - t.afterEach(() => { - consoleLogs.length = 0 - }) + const { view, outputs } = await loadMockNpm(t) + t.afterEach(() => outputs.length = 0) + t.test('readme', async t => { - await npm.exec('view', ['yellow@1.0.0', 'readme']) - t.matchSnapshot(consoleLogs.join('\n')) + await view.exec(['yellow@1.0.0', 'readme']) + t.matchSnapshot(outputs.join('\n')) }) t.test('several fields', async t => { - await npm.exec('view', ['yellow@1.0.0', 'name', 'version', 'foo[bar]']) - t.matchSnapshot(consoleLogs.join('\n')) + await view.exec(['yellow@1.0.0', 'name', 'version', 'foo[bar]']) + t.matchSnapshot(outputs.join('\n')) }) t.test('several fields with several versions', async t => { - await npm.exec('view', ['yellow@1.x.x', 'author']) - t.matchSnapshot(consoleLogs.join('\n')) + await view.exec(['yellow@1.x.x', 'author']) + t.matchSnapshot(outputs.join('\n')) }) t.test('nested field with brackets', async t => { - await npm.exec('view', ['orange@1.0.0', 'dist[shasum]']) - t.matchSnapshot(consoleLogs.join('\n')) + await view.exec(['orange@1.0.0', 'dist[shasum]']) + t.matchSnapshot(outputs.join('\n')) }) t.test('maintainers with email', async t => { - await npm.exec('view', ['yellow@1.0.0', 'maintainers', 'name']) - t.matchSnapshot(consoleLogs.join('\n')) + await view.exec(['yellow@1.0.0', 'maintainers', 'name']) + t.matchSnapshot(outputs.join('\n')) }) t.test('maintainers with url', async t => { - await npm.exec('view', ['pink@1.0.0', 'maintainers']) - t.matchSnapshot(consoleLogs.join('\n')) + await view.exec(['pink@1.0.0', 'maintainers']) + t.matchSnapshot(outputs.join('\n')) }) t.test('unknown nested field ', async t => { - await npm.exec('view', ['yellow@1.0.0', 'dist.foobar']) - t.equal(consoleLogs.join('\n'), '', 'no info to display') + await view.exec(['yellow@1.0.0', 'dist.foobar']) + t.equal(outputs.join('\n'), '', 'no info to display') }) t.test('array field - 1 element', async t => { - await npm.exec('view', ['purple@1.0.0', 'maintainers.name']) - t.matchSnapshot(consoleLogs.join('\n')) + await view.exec(['purple@1.0.0', 'maintainers.name']) + t.matchSnapshot(outputs.join('\n')) }) t.test('array field - 2 elements', async t => { - await npm.exec('view', ['yellow@1.x.x', 'maintainers.name']) - t.matchSnapshot(consoleLogs.join('\n')) + await view.exec(['yellow@1.x.x', 'maintainers.name']) + t.matchSnapshot(outputs.join('\n')) }) }) @@ -495,84 +489,84 @@ t.test('workspaces', async t => { } t.test('all workspaces', async t => { - const { npm, consoleLogs } = await loadMockNpm(t, { + const { view, outputs } = await loadMockNpm(t, { prefixDir, config: { unicode: false, workspaces: true }, }) - await npm.exec('view', []) - t.matchSnapshot(consoleLogs.join('\n')) + await view.exec([]) + t.matchSnapshot(outputs.join('\n')) }) t.test('one specific workspace', async t => { - const { npm, consoleLogs } = await loadMockNpm(t, { + const { view, outputs } = await loadMockNpm(t, { prefixDir, config: { unicode: false, workspace: ['green'] }, }) - await npm.exec('view', []) - t.matchSnapshot(consoleLogs.join('\n')) + await view.exec([]) + t.matchSnapshot(outputs.join('\n')) }) t.test('all workspaces --json', async t => { - const { npm, consoleLogs } = await loadMockNpm(t, { + const { view, outputs } = await loadMockNpm(t, { prefixDir, config: { unicode: false, workspaces: true, json: true }, }) - await npm.exec('view', []) - t.matchSnapshot(consoleLogs.join('\n')) + await view.exec([]) + t.matchSnapshot(outputs.join('\n')) }) t.test('all workspaces single field', async t => { - const { npm, consoleLogs } = await loadMockNpm(t, { + const { view, outputs } = await loadMockNpm(t, { prefixDir, config: { unicode: false, workspaces: true }, }) - await npm.exec('view', ['.', 'name']) - t.matchSnapshot(consoleLogs.join('\n')) + await view.exec(['.', 'name']) + t.matchSnapshot(outputs.join('\n')) }) t.test('all workspaces nonexistent field', async t => { - const { npm, consoleLogs } = await loadMockNpm(t, { + const { view, outputs } = await loadMockNpm(t, { prefixDir, config: { unicode: false, workspaces: true }, }) - await npm.exec('view', ['.', 'foo']) - t.matchSnapshot(consoleLogs.join('\n')) + await view.exec(['.', 'foo']) + t.matchSnapshot(outputs.join('\n')) }) t.test('all workspaces nonexistent field --json', async t => { - const { npm, consoleLogs } = await loadMockNpm(t, { + const { view, outputs } = await loadMockNpm(t, { prefixDir, config: { unicode: false, workspaces: true, json: true }, }) - await npm.exec('view', ['.', 'foo']) - t.matchSnapshot(consoleLogs.join('\n')) + await view.exec(['.', 'foo']) + t.matchSnapshot(outputs.join('\n')) }) t.test('all workspaces single field --json', async t => { - const { npm, consoleLogs } = await loadMockNpm(t, { + const { view, outputs } = await loadMockNpm(t, { prefixDir, config: { unicode: false, workspaces: true, json: true }, }) - await npm.exec('view', ['.', 'name']) - t.matchSnapshot(consoleLogs.join('\n')) + await view.exec(['.', 'name']) + t.matchSnapshot(outputs.join('\n')) }) t.test('single workspace --json', async t => { - const { npm, consoleLogs } = await loadMockNpm(t, { + const { view, outputs } = await loadMockNpm(t, { prefixDir, config: { unicode: false, workspace: ['green'], json: true }, }) - await npm.exec('view', []) - t.matchSnapshot(consoleLogs.join('\n')) + await view.exec([]) + t.matchSnapshot(outputs.join('\n')) }) t.test('remote package name', async t => { - const { npm, logs, consoleLogs } = await loadMockNpm(t, { + const { view, logs, outputs } = await loadMockNpm(t, { prefixDir, config: { unicode: false, workspaces: true }, }) - await npm.exec('view', ['pink']) - t.matchSnapshot(consoleLogs.join('\n')) + await view.exec(['pink']) + t.matchSnapshot(outputs.join('\n')) t.matchSnapshot(logs.warn, 'should have warning of ignoring workspaces') }) }) diff --git a/deps/npm/test/lib/docs.js b/deps/npm/test/lib/docs.js index 166651f6020d8a..e8a188b6ad8c48 100644 --- a/deps/npm/test/lib/docs.js +++ b/deps/npm/test/lib/docs.js @@ -41,7 +41,7 @@ t.test('basic usage', async t => { // are generated in the following test const { npm } = await loadMockNpm(t, { mocks: { - '../../lib/utils/cmd-list.js': { commands: [] }, + '{LIB}/utils/cmd-list.js': { commands: [] }, }, }) diff --git a/deps/npm/test/lib/fixtures/mock-globals.js b/deps/npm/test/lib/fixtures/mock-globals.js index 02566e575af5ec..55418dd8e199d7 100644 --- a/deps/npm/test/lib/fixtures/mock-globals.js +++ b/deps/npm/test/lib/fixtures/mock-globals.js @@ -1,6 +1,7 @@ const t = require('tap') const mockGlobals = require('../../fixtures/mock-globals') +/* eslint-disable no-console */ const originals = { platform: process.platform, error: console.error, @@ -28,6 +29,7 @@ t.test('console', async t => { t.equal(console.error, originals.error) }) +/* eslint-enable no-console */ t.test('platform', async (t) => { t.equal(process.platform, originals.platform) @@ -235,6 +237,14 @@ t.test('replace', async (t) => { t.strictSame(process.env, originals.env) }) +t.test('dot key', async t => { + const dotKey = 'this.is.a.single.key' + mockGlobals(t, { + [`process.env."${dotKey}"`]: 'value', + }) + t.strictSame(process.env[dotKey], 'value') +}) + t.test('multiple mocks and resets', async (t) => { const initial = 'a' const platforms = ['b', 'c', 'd', 'e', 'f', 'g'] @@ -299,11 +309,11 @@ t.test('multiple mocks and resets', async (t) => { await t.test('platforms', async (t) => { const resets = platforms.map((p) => { - const { teardown, reset } = mockGlobals(t, { 'process.platform': p }) + const { teardown: nestedTeardown, reset } = mockGlobals(t, { 'process.platform': p }) t.equal(process.platform, p) return [ reset['process.platform'], - teardown, + nestedTeardown, ] }) diff --git a/deps/npm/test/lib/lifecycle-cmd.js b/deps/npm/test/lib/lifecycle-cmd.js index 22011197ead54b..c2701931cac6e8 100644 --- a/deps/npm/test/lib/lifecycle-cmd.js +++ b/deps/npm/test/lib/lifecycle-cmd.js @@ -1,31 +1,32 @@ const t = require('tap') +const mockNpm = require('../fixtures/mock-npm') const LifecycleCmd = require('../../lib/lifecycle-cmd.js') -let runArgs = null -const npm = { - exec: async (cmd, args) => { + +t.test('create a lifecycle command', async t => { + let runArgs = null + const { npm } = await mockNpm(t) + npm.exec = async (cmd, args) => { if (cmd === 'run-script') { runArgs = args return 'called the right thing' } - }, - config: { - validate: () => {}, - }, -} -t.test('create a lifecycle command', async t => { - t.plan(5) + } + class TestStage extends LifecycleCmd { static get name () { return 'test-stage' } } + const cmd = new TestStage(npm) t.match(cmd.usage, /test-stage/) + let result result = await cmd.exec(['some', 'args']) t.same(runArgs, ['test-stage', 'some', 'args']) t.strictSame(result, 'called the right thing') - result = await cmd.execWorkspaces(['some', 'args'], []) + + result = await cmd.execWorkspaces(['some', 'args']) t.same(runArgs, ['test-stage', 'some', 'args']) t.strictSame(result, 'called the right thing') }) diff --git a/deps/npm/test/lib/load-all-commands.js b/deps/npm/test/lib/load-all-commands.js index aaf6a69c27cd6d..dd55560369310e 100644 --- a/deps/npm/test/lib/load-all-commands.js +++ b/deps/npm/test/lib/load-all-commands.js @@ -7,28 +7,41 @@ const util = require('util') const { load: loadMockNpm } = require('../fixtures/mock-npm.js') const { allCommands } = require('../../lib/utils/cmd-list.js') +const isAsyncFn = (v) => typeof v === 'function' && /^\[AsyncFunction:/.test(util.inspect(v)) + t.test('load each command', async t => { for (const cmd of allCommands) { t.test(cmd, async t => { - const { npm, outputs } = await loadMockNpm(t, { + const { npm, outputs, cmd: impl } = await loadMockNpm(t, { + command: cmd, config: { usage: true }, }) - const impl = await npm.cmd(cmd) + const ctor = impl.constructor + if (impl.completion) { t.type(impl.completion, 'function', 'completion, if present, is a function') } - t.type(impl.exec, 'function', 'implementation has an exec function') - t.type(impl.execWorkspaces, 'function', 'implementation has an execWorkspaces function') - t.equal(util.inspect(impl.exec), '[AsyncFunction: exec]', 'exec function is async') - t.equal( - util.inspect(impl.execWorkspaces), - '[AsyncFunction: execWorkspaces]', - 'execWorkspaces function is async' - ) + + // exec fn + t.ok(isAsyncFn(impl.exec), 'exec is async') + t.ok(impl.exec.length <= 1, 'exec fn has 0 or 1 args') + + // workspaces + t.type(ctor.ignoreImplicitWorkspace, 'boolean', 'ctor has ignoreImplictWorkspace boolean') + t.type(ctor.workspaces, 'boolean', 'ctor has workspaces boolean') + if (ctor.workspaces) { + t.ok(isAsyncFn(impl.execWorkspaces), 'execWorkspaces is async') + t.ok(impl.exec.length <= 1, 'execWorkspaces fn has 0 or 1 args') + } else { + t.notOk(impl.execWorkspaces, 'has no execWorkspaces fn') + } + + // name/desc t.ok(impl.description, 'implementation has a description') t.ok(impl.name, 'implementation has a name') t.equal(cmd, impl.name, 'command list and name are the same') - t.ok(impl.ignoreImplicitWorkspace !== undefined, 'implementation has ignoreImplictWorkspace') + + // usage t.match(impl.usage, cmd, 'usage contains the command') await npm.exec(cmd, []) t.match(outputs[0][0], impl.usage, 'usage is what is output') diff --git a/deps/npm/test/lib/npm.js b/deps/npm/test/lib/npm.js index f850ff6aff8a4b..e6936b3e36d5f8 100644 --- a/deps/npm/test/lib/npm.js +++ b/deps/npm/test/lib/npm.js @@ -1,39 +1,10 @@ const t = require('tap') const { resolve, dirname, join } = require('path') const fs = require('fs') - const { load: loadMockNpm } = require('../fixtures/mock-npm.js') const mockGlobals = require('../fixtures/mock-globals') const { commands } = require('../../lib/utils/cmd-list.js') -// delete this so that we don't have configs from the fact that it -// is being run by 'npm test' -const event = process.env.npm_lifecycle_event - -for (const env of Object.keys(process.env).filter(e => /^npm_/.test(e))) { - if (env === 'npm_command') { - // should only be running this in the 'test' or 'run-script' command! - // if the lifecycle event is 'test', then it'll be either 'test' or 'run', - // otherwise it should always be run-script. Of course, it'll be missing - // if this test is just run directly, which is also acceptable. - if (event === 'test') { - t.ok( - ['test', 'run-script'].some(i => i === process.env[env]), - 'should match "npm test" or "npm run test"' - ) - } else { - t.match(process.env[env], /^(run-script|exec)$/) - } - } - delete process.env[env] -} - -t.afterEach(async (t) => { - for (const env of Object.keys(process.env).filter(e => /^npm_/.test(e))) { - delete process.env[env] - } -}) - t.test('not yet loaded', async t => { const { npm, logs } = await loadMockNpm(t, { load: false }) t.match(npm, { @@ -160,8 +131,8 @@ t.test('npm.load', async t => { prefixDir: { bin: t.fixture('symlink', dirname(process.execPath)), }, - globals: ({ prefix }) => ({ - 'process.env.PATH': resolve(prefix, 'bin'), + globals: (dirs) => ({ + 'process.env.PATH': resolve(dirs.prefix, 'bin'), 'process.argv': [ node, process.argv[1], @@ -299,9 +270,6 @@ t.test('npm.load', async t => { }, }) - // verify that calling the command with a short name still sets - // the npm.command property to the full canonical name of the cmd. - npm.command = null await npm.exec('run', []) t.equal(npm.command, 'run-script', 'npm.command set to canonical name') @@ -357,9 +325,7 @@ t.test('npm.load', async t => { ], }, }) - // verify that calling the command with a short name still sets - // the npm.command property to the full canonical name of the cmd. - npm.command = null + await t.rejects( npm.exec('run', []), /Workspaces not supported for global packages/ @@ -441,9 +407,9 @@ t.test('debug log', async t => { t.test('can load with bad dir', async t => { const { npm, testdir } = await loadMockNpm(t, { load: false, - config: { - 'logs-dir': (c) => join(c.testdir, 'my_logs_dir'), - }, + config: (dirs) => ({ + 'logs-dir': join(dirs.testdir, 'my_logs_dir'), + }), }) const logsDir = join(testdir, 'my_logs_dir') @@ -648,15 +614,15 @@ t.test('implicit workspace rejection', async t => { workspaces: ['./packages/a'], }), }, - globals: ({ prefix }) => ({ - 'process.cwd': () => join(prefix, 'packages', 'a'), + chdir: ({ prefix }) => join(prefix, 'packages', 'a'), + globals: { 'process.argv': [ process.execPath, process.argv[1], '--color', 'false', '--workspace', './packages/a', ], - }), + }, }) await t.rejects( mock.npm.exec('team', []), @@ -682,14 +648,14 @@ t.test('implicit workspace accept', async t => { workspaces: ['./packages/a'], }), }, - globals: ({ prefix }) => ({ - 'process.cwd': () => join(prefix, 'packages', 'a'), + chdir: ({ prefix }) => join(prefix, 'packages', 'a'), + globals: { 'process.argv': [ process.execPath, process.argv[1], '--color', 'false', ], - }), + }, }) await t.rejects(mock.npm.exec('org', []), /.*Usage/) }) diff --git a/deps/npm/test/lib/utils/audit-error.js b/deps/npm/test/lib/utils/audit-error.js index bcb7d8c16dd7b6..46a9dbc38cd7d3 100644 --- a/deps/npm/test/lib/utils/audit-error.js +++ b/deps/npm/test/lib/utils/audit-error.js @@ -1,36 +1,44 @@ const t = require('tap') +const mockLogs = require('../../fixtures/mock-logs') +const mockNpm = require('../../fixtures/mock-npm') +const tmock = require('../../fixtures/tmock') -const LOGS = [] -const OUTPUT = [] -const output = (...msg) => OUTPUT.push(msg) -const auditError = t.mock('../../../lib/utils/audit-error.js', { - 'proc-log': { - warn: (...msg) => LOGS.push(msg), - }, -}) +const auditError = async (t, { command, error, ...config } = {}) => { + const { logs, logMocks } = mockLogs() + const mockAuditError = tmock(t, '{LIB}/utils/audit-error', logMocks) + + const mock = await mockNpm(t, { + command, + config, + }) -const npm = { - command: null, - flatOptions: {}, - output, + const res = {} + try { + res.result = mockAuditError(mock.npm, error ? { error } : {}) + } catch (err) { + res.error = err + } + + return { + ...res, + logs: logs.warn.filter((l) => l[0] === 'audit'), + output: mock.joinedOutput(), + } } -t.afterEach(() => { - npm.flatOptions = {} - OUTPUT.length = 0 - LOGS.length = 0 -}) -t.test('no error, not audit command', t => { - npm.command = 'install' - t.equal(auditError(npm, {}), false, 'no error') - t.strictSame(OUTPUT, [], 'no output') - t.strictSame(LOGS, [], 'no warnings') - t.end() +t.test('no error, not audit command', async t => { + const { result, error, logs, output } = await auditError(t, { command: 'install' }) + + t.equal(result, false, 'no error') + t.notOk(error, 'no error') + + t.strictSame(output, '', 'no output') + t.strictSame(logs, [], 'no warnings') }) -t.test('error, not audit command', t => { - npm.command = 'install' - t.equal(auditError(npm, { +t.test('error, not audit command', async t => { + const { result, error, logs, output } = await auditError(t, { + command: 'install', error: { message: 'message', body: Buffer.from('body'), @@ -41,16 +49,17 @@ t.test('error, not audit command', t => { }, statusCode: '420', }, - }), true, 'had error') - t.strictSame(OUTPUT, [], 'no output') - t.strictSame(LOGS, [], 'no warnings') - t.end() + }) + + t.equal(result, true, 'had error') + t.notOk(error, 'no error') + t.strictSame(output, '', 'no output') + t.strictSame(logs, [], 'no warnings') }) -t.test('error, audit command, not json', t => { - npm.command = 'audit' - npm.flatOptions.json = false - t.throws(() => auditError(npm, { +t.test('error, audit command, not json', async t => { + const { result, error, logs, output } = await auditError(t, { + command: 'audit', error: { message: 'message', body: Buffer.from('body'), @@ -61,17 +70,19 @@ t.test('error, audit command, not json', t => { }, statusCode: '420', }, - })) + }) + + t.equal(result, undefined) - t.strictSame(OUTPUT, [['body']], 'some output') - t.strictSame(LOGS, [['audit', 'message']], 'some warnings') - t.end() + t.ok(error, 'throws error') + t.strictSame(output, 'body', 'some output') + t.strictSame(logs, [['audit', 'message']], 'some warnings') }) -t.test('error, audit command, json', t => { - npm.command = 'audit' - npm.flatOptions.json = true - t.throws(() => auditError(npm, { +t.test('error, audit command, json', async t => { + const { result, error, logs, output } = await auditError(t, { + json: true, + command: 'audit', error: { message: 'message', body: { response: 'body' }, @@ -82,26 +93,25 @@ t.test('error, audit command, json', t => { }, statusCode: '420', }, - })) + }) - t.strictSame(OUTPUT, [ - [ - '{\n' + - ' "message": "message",\n' + - ' "method": "POST",\n' + - ' "uri": "https://example.com/not/a/registry",\n' + - ' "headers": {\n' + - ' "head": [\n' + - ' "ers"\n' + - ' ]\n' + - ' },\n' + - ' "statusCode": "420",\n' + - ' "body": {\n' + - ' "response": "body"\n' + - ' }\n' + - '}', - ], - ], 'some output') - t.strictSame(LOGS, [['audit', 'message']], 'some warnings') - t.end() + t.equal(result, undefined) + t.ok(error, 'throws error') + t.strictSame(output, + '{\n' + + ' "message": "message",\n' + + ' "method": "POST",\n' + + ' "uri": "https://example.com/not/a/registry",\n' + + ' "headers": {\n' + + ' "head": [\n' + + ' "ers"\n' + + ' ]\n' + + ' },\n' + + ' "statusCode": "420",\n' + + ' "body": {\n' + + ' "response": "body"\n' + + ' }\n' + + '}' + , 'some output') + t.strictSame(logs, [['audit', 'message']], 'some warnings') }) diff --git a/deps/npm/test/lib/utils/completion/installed-deep.js b/deps/npm/test/lib/utils/completion/installed-deep.js index f0e36faee1fddf..fa39f0f0734b83 100644 --- a/deps/npm/test/lib/utils/completion/installed-deep.js +++ b/deps/npm/test/lib/utils/completion/installed-deep.js @@ -1,5 +1,6 @@ const { resolve } = require('path') const t = require('tap') +const installedDeep = require('../../../../lib/utils/completion/installed-deep.js') let prefix let globalDir = 'MISSING_GLOBAL_DIR' @@ -11,8 +12,6 @@ const _flatOptions = { return prefix }, } -const p = '../../../../lib/utils/completion/installed-deep.js' -const installedDeep = require(p) const npm = { flatOptions: _flatOptions, get prefix () { diff --git a/deps/npm/test/lib/utils/completion/installed-shallow.js b/deps/npm/test/lib/utils/completion/installed-shallow.js index 1445cbf2ffb71a..5a65b6b6bfaef7 100644 --- a/deps/npm/test/lib/utils/completion/installed-shallow.js +++ b/deps/npm/test/lib/utils/completion/installed-shallow.js @@ -1,10 +1,9 @@ -const flatOptions = { global: false } -const npm = { flatOptions } const t = require('tap') const { resolve } = require('path') +const installed = require('../../../../lib/utils/completion/installed-shallow.js') -const p = '../../../../lib/utils/completion/installed-shallow.js' -const installed = require(p) +const flatOptions = { global: false } +const npm = { flatOptions } t.test('global not set, include globals with -g', async t => { const dir = t.testdir({ diff --git a/deps/npm/test/lib/utils/config/definitions.js b/deps/npm/test/lib/utils/config/definitions.js index dca584e1048331..288166039bf6fe 100644 --- a/deps/npm/test/lib/utils/config/definitions.js +++ b/deps/npm/test/lib/utils/config/definitions.js @@ -1,14 +1,15 @@ const t = require('tap') const { resolve } = require('path') const mockGlobals = require('../../../fixtures/mock-globals') +const tmock = require('../../../fixtures/tmock') const pkg = require('../../../../package.json') // have to fake the node version, or else it'll only pass on this one mockGlobals(t, { 'process.version': 'v14.8.0', 'process.env.NODE_ENV': undefined }) -const mockDefs = (mocks = {}) => t.mock('../../../../lib/utils/config/definitions.js', mocks) +const mockDefs = (mocks = {}) => tmock(t, '{LIB}/utils/config/definitions.js', mocks) -const isWin = (isWindows) => ({ '../../../../lib/utils/is-windows.js': { isWindows } }) +const isWin = (isWindows) => ({ '{LIB}/utils/is-windows.js': { isWindows } }) t.test('basic flattening function camelCases from css-case', t => { const flat = {} @@ -930,3 +931,12 @@ t.test('remap global-style', t => { t.strictSame(flat, { installStrategy: 'shallow' }) t.end() }) + +t.test('otp changes auth-type', t => { + const obj = { 'auth-type': 'web', otp: 123456 } + const flat = {} + mockDefs().otp.flatten('otp', obj, flat) + t.strictSame(flat, { authType: 'legacy', otp: 123456 }) + t.strictSame(obj, { 'auth-type': 'legacy', otp: 123456 }) + t.end() +}) diff --git a/deps/npm/test/lib/utils/display.js b/deps/npm/test/lib/utils/display.js index c7332bce8e2492..cfe0181e23e79f 100644 --- a/deps/npm/test/lib/utils/display.js +++ b/deps/npm/test/lib/utils/display.js @@ -2,10 +2,11 @@ const t = require('tap') const log = require('../../../lib/utils/log-shim') const mockLogs = require('../../fixtures/mock-logs') const mockGlobals = require('../../fixtures/mock-globals') +const tmock = require('../../fixtures/tmock') const mockDisplay = (t, mocks) => { const { logs, logMocks } = mockLogs(mocks) - const Display = t.mock('../../../lib/utils/display', { + const Display = tmock(t, '{LIB}/utils/display', { ...mocks, ...logMocks, }) @@ -44,7 +45,7 @@ t.test('can log', async (t) => { error: (...args) => logs.push(['error', ...args]), warn: (...args) => logs.push(['warn', ...args]), }, - '../../../lib/utils/explain-eresolve.js': { + '{LIB}/utils/explain-eresolve.js': { explain: (...args) => { explains.push(args) return 'explanation' @@ -71,7 +72,7 @@ t.test('handles log throwing', async (t) => { throw new Error('verbose') }, }, - '../../../lib/utils/explain-eresolve.js': { + '{LIB}/utils/explain-eresolve.js': { explain: () => { throw new Error('explain') }, diff --git a/deps/npm/test/lib/utils/error-message.js b/deps/npm/test/lib/utils/error-message.js index 29753c3039f365..9d07693989ea84 100644 --- a/deps/npm/test/lib/utils/error-message.js +++ b/deps/npm/test/lib/utils/error-message.js @@ -1,13 +1,18 @@ const t = require('tap') -const path = require('path') +const { resolve } = require('path') +const fs = require('fs/promises') const { load: _loadMockNpm } = require('../../fixtures/mock-npm.js') const mockGlobals = require('../../fixtures/mock-globals.js') +const tmock = require('../../fixtures/tmock') const { cleanCwd, cleanDate } = require('../../fixtures/clean-snapshot.js') t.formatSnapshot = (p) => { if (Array.isArray(p.files) && !p.files.length) { delete p.files } + if (p?.json === undefined) { + delete p.json + } return p } t.cleanSnapshot = p => cleanDate(cleanCwd(p)) @@ -22,35 +27,26 @@ mockGlobals(t, { }, }) -const loadMockNpm = async (t, { load, command, prefixDir, config } = {}) => { - const { npm, ...rest } = await _loadMockNpm(t, { - load, - prefixDir, - config, +const loadMockNpm = async (t, { errorMocks, ...opts } = {}) => { + const mockError = tmock(t, '{LIB}/utils/error-message.js', errorMocks) + const res = await _loadMockNpm(t, { + ...opts, mocks: { - '../../package.json': { + ...opts.mocks, + '{ROOT}/package.json': { version: '123.456.789-npm', }, }, }) - if (command !== undefined) { - npm.command = command - } return { - npm, - ...rest, + ...res, + errorMessage: (er) => mockError(er, res.npm), } } -const errorMessage = (er, { mocks, logMocks, npm } = {}) => - t.mock('../../../lib/utils/error-message.js', { ...mocks, ...logMocks })(er, npm) - t.test('just simple messages', async t => { - const npm = await loadMockNpm(t, { + const { errorMessage } = await loadMockNpm(t, { command: 'audit', - config: { - 'node-version': '99.99.99', - }, }) const codes = [ 'ENOAUDIT', @@ -77,8 +73,7 @@ t.test('just simple messages', async t => { 'E403', 'ERR_SOCKET_TIMEOUT', ] - t.plan(codes.length) - codes.forEach(async code => { + for (const code of codes) { const path = '/some/path' const pkgid = 'some@package' const file = '/some/file' @@ -90,12 +85,12 @@ t.test('just simple messages', async t => { file, stack, }) - t.matchSnapshot(errorMessage(er, npm)) - }) + t.matchSnapshot(errorMessage(er)) + } }) t.test('replace message/stack sensistive info', async t => { - const npm = await loadMockNpm(t, { command: 'audit' }) + const { errorMessage } = await loadMockNpm(t, { command: 'audit' }) const path = '/some/path' const pkgid = 'some@package' const file = '/some/file' @@ -108,11 +103,11 @@ t.test('replace message/stack sensistive info', async t => { file, stack, }) - t.matchSnapshot(errorMessage(er, npm)) + t.matchSnapshot(errorMessage(er)) }) t.test('bad engine without config loaded', async t => { - const npm = await loadMockNpm(t, { load: false }) + const { errorMessage } = await loadMockNpm(t, { load: false }) const path = '/some/path' const pkgid = 'some@package' const file = '/some/file' @@ -124,11 +119,11 @@ t.test('bad engine without config loaded', async t => { file, stack, }) - t.matchSnapshot(errorMessage(er, npm)) + t.matchSnapshot(errorMessage(er)) }) t.test('enoent without a file', async t => { - const npm = await loadMockNpm(t) + const { errorMessage } = await loadMockNpm(t) const path = '/some/path' const pkgid = 'some@package' const stack = 'dummy stack trace' @@ -138,11 +133,11 @@ t.test('enoent without a file', async t => { pkgid, stack, }) - t.matchSnapshot(errorMessage(er, npm)) + t.matchSnapshot(errorMessage(er)) }) t.test('enolock without a command', async t => { - const npm = await loadMockNpm(t, { command: null }) + const { errorMessage } = await loadMockNpm(t, { command: null }) const path = '/some/path' const pkgid = 'some@package' const file = '/some/file' @@ -154,41 +149,43 @@ t.test('enolock without a command', async t => { file, stack, }) - t.matchSnapshot(errorMessage(er, npm)) + t.matchSnapshot(errorMessage(er)) }) t.test('default message', async t => { - const npm = await loadMockNpm(t) - t.matchSnapshot(errorMessage(new Error('error object'), npm)) - t.matchSnapshot(errorMessage('error string', npm)) + const { errorMessage } = await loadMockNpm(t) + t.matchSnapshot(errorMessage(new Error('error object'))) + t.matchSnapshot(errorMessage('error string')) t.matchSnapshot(errorMessage(Object.assign(new Error('cmd err'), { cmd: 'some command', signal: 'SIGYOLO', args: ['a', 'r', 'g', 's'], stdout: 'stdout', stderr: 'stderr', - }), npm)) + }))) }) t.test('args are cleaned', async t => { - const npm = await loadMockNpm(t) + const { errorMessage } = await loadMockNpm(t) t.matchSnapshot(errorMessage(Object.assign(new Error('cmd err'), { cmd: 'some command', signal: 'SIGYOLO', args: ['a', 'r', 'g', 's', 'https://evil:password@npmjs.org'], stdout: 'stdout', stderr: 'stderr', - }), npm)) + }))) }) t.test('eacces/eperm', async t => { const runTest = (windows, loaded, cachePath, cacheDest) => async t => { - if (windows) { - mockGlobals(t, { 'process.platform': 'win32' }) - } - const npm = await loadMockNpm(t, { windows, load: loaded }) - const path = `${cachePath ? npm.cache : '/not/cache/dir'}/path` - const dest = `${cacheDest ? npm.cache : '/not/cache/dir'}/dest` + const { errorMessage, logs, cache } = await loadMockNpm(t, { + windows, + load: loaded, + globals: windows ? { 'process.platform': 'win32' } : [], + }) + + const path = `${cachePath ? cache : '/not/cache/dir'}/path` + const dest = `${cacheDest ? cache : '/not/cache/dir'}/dest` const er = Object.assign(new Error('whoopsie'), { code: 'EACCES', path, @@ -196,8 +193,8 @@ t.test('eacces/eperm', async t => { stack: 'dummy stack trace', }) - t.matchSnapshot(errorMessage(er, npm)) - t.matchSnapshot(npm.logs.verbose) + t.matchSnapshot(errorMessage(er)) + t.matchSnapshot(logs.verbose) } for (const windows of [true, false]) { @@ -217,50 +214,14 @@ t.test('json parse', t => { t.test('merge conflict in package.json', async t => { const prefixDir = { - 'package.json': ` -{ - "array": [ -<<<<<<< HEAD - 100, - { - "foo": "baz" - }, -||||||| merged common ancestors - 1, -======= - 111, - 1, - 2, - 3, - { - "foo": "bar" - }, ->>>>>>> a - 1 - ], - "a": { - "b": { -<<<<<<< HEAD - "c": { - "x": "bbbb" - } -||||||| merged common ancestors - "c": { - "x": "aaaa" - } -======= - "c": "xxxx" ->>>>>>> a + 'package.json': await fs.readFile( + resolve(__dirname, '../../fixtures/merge-conflict.json'), 'utf-8'), } - } -} -`, - } - const npm = await loadMockNpm(t, { prefixDir }) + const { errorMessage, npm } = await loadMockNpm(t, { prefixDir }) t.matchSnapshot(errorMessage(Object.assign(new Error('conflicted'), { code: 'EJSONPARSE', - path: path.resolve(npm.prefix, 'package.json'), - }), npm)) + path: resolve(npm.prefix, 'package.json'), + }))) t.end() }) @@ -268,11 +229,11 @@ t.test('json parse', t => { const prefixDir = { 'package.json': 'not even slightly json', } - const npm = await loadMockNpm(t, { prefixDir }) + const { errorMessage, npm } = await loadMockNpm(t, { prefixDir }) t.matchSnapshot(errorMessage(Object.assign(new Error('not json'), { code: 'EJSONPARSE', - path: path.resolve(npm.prefix, 'package.json'), - }), npm)) + path: resolve(npm.prefix, 'package.json'), + }))) t.end() }) @@ -280,11 +241,11 @@ t.test('json parse', t => { const prefixDir = { 'blerg.json': 'not even slightly json', } - const npm = await loadMockNpm(t, { prefixDir }) + const { npm, errorMessage } = await loadMockNpm(t, { prefixDir }) t.matchSnapshot(errorMessage(Object.assign(new Error('not json'), { code: 'EJSONPARSE', - path: path.resolve(npm.prefix, 'blerg.json'), - }), npm)) + path: resolve(npm.prefix, 'blerg.json'), + }))) t.end() }) @@ -292,26 +253,26 @@ t.test('json parse', t => { }) t.test('eotp/e401', async t => { - const npm = await loadMockNpm(t) + const { errorMessage } = await loadMockNpm(t) t.test('401, no auth headers', t => { t.matchSnapshot(errorMessage(Object.assign(new Error('nope'), { code: 'E401', - }), npm)) + }))) t.end() }) t.test('401, no message', t => { t.matchSnapshot(errorMessage({ code: 'E401', - }, npm)) + })) t.end() }) t.test('one-time pass challenge code', t => { t.matchSnapshot(errorMessage(Object.assign(new Error('nope'), { code: 'EOTP', - }), npm)) + }))) t.end() }) @@ -319,7 +280,7 @@ t.test('eotp/e401', async t => { const message = 'one-time pass' t.matchSnapshot(errorMessage(Object.assign(new Error(message), { code: 'E401', - }), npm)) + }))) t.end() }) @@ -339,7 +300,7 @@ t.test('eotp/e401', async t => { }, code: 'E401', }) - t.matchSnapshot(errorMessage(er, npm)) + t.matchSnapshot(errorMessage(er)) t.end() }) } @@ -347,11 +308,11 @@ t.test('eotp/e401', async t => { }) t.test('404', async t => { - const npm = await loadMockNpm(t) + const { errorMessage } = await loadMockNpm(t) t.test('no package id', t => { const er = Object.assign(new Error('404 not found'), { code: 'E404' }) - t.matchSnapshot(errorMessage(er, npm)) + t.matchSnapshot(errorMessage(er)) t.end() }) t.test('you should publish it', t => { @@ -359,7 +320,7 @@ t.test('404', async t => { pkgid: 'yolo', code: 'E404', }) - t.matchSnapshot(errorMessage(er, npm)) + t.matchSnapshot(errorMessage(er)) t.end() }) t.test('name with warning', t => { @@ -367,7 +328,7 @@ t.test('404', async t => { pkgid: new Array(215).fill('x').join(''), code: 'E404', }) - t.matchSnapshot(errorMessage(er, npm)) + t.matchSnapshot(errorMessage(er)) t.end() }) t.test('name with error', t => { @@ -375,7 +336,7 @@ t.test('404', async t => { pkgid: 'node_modules', code: 'E404', }) - t.matchSnapshot(errorMessage(er, npm)) + t.matchSnapshot(errorMessage(er)) t.end() }) t.test('cleans sensitive info from package id', t => { @@ -383,13 +344,13 @@ t.test('404', async t => { pkgid: 'http://evil:password@npmjs.org/not-found', code: 'E404', }) - t.matchSnapshot(errorMessage(er, npm)) + t.matchSnapshot(errorMessage(er)) t.end() }) }) t.test('bad platform', async t => { - const npm = await loadMockNpm(t) + const { errorMessage } = await loadMockNpm(t) t.test('string os/arch', t => { const er = Object.assign(new Error('a bad plat'), { @@ -404,7 +365,7 @@ t.test('bad platform', async t => { }, code: 'EBADPLATFORM', }) - t.matchSnapshot(errorMessage(er, npm)) + t.matchSnapshot(errorMessage(er)) t.end() }) t.test('array os/arch', t => { @@ -420,30 +381,29 @@ t.test('bad platform', async t => { }, code: 'EBADPLATFORM', }) - t.matchSnapshot(errorMessage(er, npm)) + t.matchSnapshot(errorMessage(er)) t.end() }) }) t.test('explain ERESOLVE errors', async t => { - const { npm, ...rest } = await loadMockNpm(t) const EXPLAIN_CALLED = [] - const er = Object.assign(new Error('could not resolve'), { - code: 'ERESOLVE', - }) - - t.matchSnapshot(errorMessage(er, { - npm, - ...rest, - mocks: { - '../../../lib/utils/explain-eresolve.js': { + const { errorMessage } = await loadMockNpm(t, { + errorMocks: { + '{LIB}/utils/explain-eresolve.js': { report: (...args) => { EXPLAIN_CALLED.push(args) return { explanation: 'explanation', file: 'report' } }, }, }, - })) + }) + + const er = Object.assign(new Error('could not resolve'), { + code: 'ERESOLVE', + }) + + t.matchSnapshot(errorMessage(er)) t.match(EXPLAIN_CALLED, [[er, false]]) }) diff --git a/deps/npm/test/lib/utils/exit-handler.js b/deps/npm/test/lib/utils/exit-handler.js index d22ec4dd141a87..76d5fec4c099a8 100644 --- a/deps/npm/test/lib/utils/exit-handler.js +++ b/deps/npm/test/lib/utils/exit-handler.js @@ -2,12 +2,13 @@ const t = require('tap') const os = require('os') const fs = require('fs') const fsMiniPass = require('fs-minipass') -const { join } = require('path') +const { join, resolve } = require('path') const EventEmitter = require('events') const { format } = require('../../../lib/utils/log-file') const { load: loadMockNpm } = require('../../fixtures/mock-npm') const mockGlobals = require('../../fixtures/mock-globals') const { cleanCwd, cleanDate } = require('../../fixtures/clean-snapshot') +const tmock = require('../../fixtures/tmock') const pick = (obj, ...keys) => keys.reduce((acc, key) => { acc[key] = obj[key] @@ -35,7 +36,8 @@ t.cleanSnapshot = (path) => cleanDate(cleanCwd(path)) // nerf itself, thinking global.process is broken or gone. mockGlobals(t, { process: Object.assign(new EventEmitter(), { - ...pick(process, 'execPath', 'stdout', 'stderr', 'cwd', 'env', 'umask'), + // these are process properties that are needed in the running code and tests + ...pick(process, 'execPath', 'stdout', 'stderr', 'cwd', 'chdir', 'env', 'umask'), argv: ['/node', ...process.argv.slice(1)], version: 'v1.0.0', kill: () => {}, @@ -56,25 +58,32 @@ const mockExitHandler = async (t, { init, load, testdir, config, mocks, files } load, testdir, mocks: { - '../../package.json': { + '{ROOT}/package.json': { version: '1.0.0', }, ...mocks, }, - config: { + config: (dirs) => ({ loglevel: 'notice', - ...config, - }, + ...(typeof config === 'function' ? config(dirs) : config), + }), globals: { 'console.error': (err) => errors.push(err), }, }) - const exitHandler = t.mock('../../../lib/utils/exit-handler.js', { - '../../../lib/utils/error-message.js': (err) => ({ + const exitHandler = tmock(t, '{LIB}/utils/exit-handler.js', { + '{LIB}/utils/error-message.js': (err) => ({ summary: [['ERR SUMMARY', err.message]], detail: [['ERR DETAIL', err.message]], ...(files ? { files } : {}), + json: { + error: { + code: err.code, + summary: err.message, + detail: err.message, + }, + }, }), os: { type: () => 'Foo', @@ -89,7 +98,6 @@ const mockExitHandler = async (t, { init, load, testdir, config, mocks, files } } t.teardown(() => { - delete process.exitCode process.removeAllListeners('exit') }) @@ -101,8 +109,8 @@ const mockExitHandler = async (t, { init, load, testdir, config, mocks, files } // to t.plan() every test to make sure we get process.exit called. Also // introduce a small artificial delay so the logs are consistently finished // by the time the exit handler forces process.exit - exitHandler: (...args) => new Promise(resolve => setTimeout(() => { - process.once('exit', resolve) + exitHandler: (...args) => new Promise(res => setTimeout(() => { + process.once('exit', res) exitHandler(...args) }, 50)), } @@ -338,7 +346,7 @@ t.test('no logs dir', async (t) => { t.test('timers fail to write', async (t) => { // we want the fs.writeFileSync in the Timers class to fail - const mockTimers = t.mock('../../../lib/utils/timers.js', { + const mockTimers = tmock(t, '{LIB}/utils/timers.js', { fs: { ...fs, writeFileSync: (file, ...rest) => { @@ -352,13 +360,13 @@ t.test('timers fail to write', async (t) => { }) const { exitHandler, logs } = await mockExitHandler(t, { - config: { - 'logs-dir': 'LOGS_DIR', + config: (dirs) => ({ + 'logs-dir': resolve(dirs.prefix, 'LOGS_DIR'), timing: true, - }, + }), mocks: { // note, this is relative to test/fixtures/mock-npm.js not this file - '../../lib/utils/timers.js': mockTimers, + '{LIB}/utils/timers.js': mockTimers, }, }) @@ -369,7 +377,7 @@ t.test('timers fail to write', async (t) => { t.test('log files fail to write', async (t) => { // we want the fsMiniPass.WriteStreamSync in the LogFile class to fail - const mockLogFile = t.mock('../../../lib/utils/log-file.js', { + const mockLogFile = tmock(t, '{LIB}/utils/log-file.js', { 'fs-minipass': { ...fsMiniPass, WriteStreamSync: (file, ...rest) => { @@ -381,12 +389,12 @@ t.test('log files fail to write', async (t) => { }) const { exitHandler, logs } = await mockExitHandler(t, { - config: { - 'logs-dir': 'LOGS_DIR', - }, + config: (dirs) => ({ + 'logs-dir': resolve(dirs.prefix, 'LOGS_DIR'), + }), mocks: { // note, this is relative to test/fixtures/mock-npm.js not this file - '../../lib/utils/log-file.js': mockLogFile, + '{LIB}/utils/log-file.js': mockLogFile, }, }) @@ -417,9 +425,9 @@ t.test('files from error message', async (t) => { t.test('files from error message with error', async (t) => { const { exitHandler, logs } = await mockExitHandler(t, { - config: { - 'logs-dir': 'LOGS_DIR', - }, + config: (dirs) => ({ + 'logs-dir': resolve(dirs.prefix, 'LOGS_DIR'), + }), files: [ ['error-file.txt', '# error file content'], ], @@ -587,10 +595,7 @@ t.test('exits uncleanly when only emitting exit event', async (t) => { t.test('do no fancy handling for shellouts', async t => { const { exitHandler, npm, logs } = await mockExitHandler(t) - const exec = await npm.cmd('exec') - - npm.command = 'exec' - npm.commandInstance = exec + await npm.cmd('exec') const loudNoises = () => logs.filter(([level]) => ['warn', 'error'].includes(level)) diff --git a/deps/npm/test/lib/utils/explain-dep.js b/deps/npm/test/lib/utils/explain-dep.js index ed006c01d78fb3..514f28d125a0d7 100644 --- a/deps/npm/test/lib/utils/explain-dep.js +++ b/deps/npm/test/lib/utils/explain-dep.js @@ -1,16 +1,11 @@ const { resolve } = require('path') const t = require('tap') const { explainNode, printNode } = require('../../../lib/utils/explain-dep.js') +const { cleanCwd } = require('../../fixtures/clean-snapshot') + const testdir = t.testdirName -const redactCwd = (path) => { - const normalizePath = p => p - .replace(/\\+/g, '/') - .replace(/\r\n/g, '\n') - return normalizePath(path) - .replace(new RegExp(normalizePath(process.cwd()), 'g'), '{CWD}') -} -t.cleanSnapshot = (str) => redactCwd(str) +t.cleanSnapshot = (str) => cleanCwd(str) const cases = { prodDep: { diff --git a/deps/npm/test/lib/utils/log-file.js b/deps/npm/test/lib/utils/log-file.js index 4be5231c1c4fa0..e134fe8790bd53 100644 --- a/deps/npm/test/lib/utils/log-file.js +++ b/deps/npm/test/lib/utils/log-file.js @@ -4,11 +4,11 @@ const fs = _fs.promises const path = require('path') const os = require('os') const fsMiniPass = require('fs-minipass') -const rimraf = require('rimraf') +const tmock = require('../../fixtures/tmock') const LogFile = require('../../../lib/utils/log-file.js') const { cleanCwd, cleanDate } = require('../../fixtures/clean-snapshot') -t.cleanSnapshot = (path) => cleanDate(cleanCwd(path)) +t.cleanSnapshot = (s) => cleanDate(cleanCwd(s)) const getId = (d = new Date()) => d.toISOString().replace(/[.:]/g, '_') const last = arr => arr[arr.length - 1] @@ -43,7 +43,7 @@ const cleanErr = (message) => { const loadLogFile = async (t, { buffer = [], mocks, testdir = {}, ...options } = {}) => { const root = t.testdir(testdir) - const MockLogFile = t.mock('../../../lib/utils/log-file.js', mocks) + const MockLogFile = tmock(t, '{LIB}/utils/log-file.js', mocks) const logFile = new MockLogFile(Object.keys(options).length ? options : undefined) buffer.forEach((b) => logFile.log(...b)) @@ -275,12 +275,14 @@ t.test('rimraf error', async t => { logsMax, testdir: makeOldLogs(oldLogs), mocks: { - rimraf: (...args) => { - if (count >= 3) { - throw new Error('bad rimraf') - } - count++ - return rimraf(...args) + 'fs/promises': { + rm: async (...args) => { + if (count >= 3) { + throw new Error('bad rimraf') + } + count++ + return fs.rm(...args) + }, }, }, }) diff --git a/deps/npm/test/lib/utils/log-shim.js b/deps/npm/test/lib/utils/log-shim.js index dee4efbaa4552d..7c8fb7ce3c9569 100644 --- a/deps/npm/test/lib/utils/log-shim.js +++ b/deps/npm/test/lib/utils/log-shim.js @@ -1,6 +1,7 @@ const t = require('tap') +const tmock = require('../../fixtures/tmock') -const makeShim = (mocks) => t.mock('../../../lib/utils/log-shim.js', mocks) +const makeShim = (mocks) => tmock(t, '{LIB}/utils/log-shim.js', mocks) const loggers = [ 'notice', diff --git a/deps/npm/test/lib/utils/open-url-prompt.js b/deps/npm/test/lib/utils/open-url-prompt.js index a18fe85f687517..faf2ab32587af1 100644 --- a/deps/npm/test/lib/utils/open-url-prompt.js +++ b/deps/npm/test/lib/utils/open-url-prompt.js @@ -1,6 +1,7 @@ const t = require('tap') const mockGlobals = require('../../fixtures/mock-globals.js') const EventEmitter = require('events') +const tmock = require('../../fixtures/tmock') const OUTPUT = [] const output = (...args) => OUTPUT.push(args) @@ -22,14 +23,6 @@ let openerUrl = null let openerOpts = null let openerResult = null -const open = async (url, options) => { - openerUrl = url - openerOpts = options - if (openerResult) { - throw openerResult - } -} - let questionShouldResolve = true let openUrlPromptInterrupted = false @@ -49,9 +42,15 @@ const readline = { }), } -const openUrlPrompt = t.mock('../../../lib/utils/open-url-prompt.js', { +const openUrlPrompt = tmock(t, '{LIB}/utils/open-url-prompt.js', { '@npmcli/promise-spawn': { - open, + open: async (url, options) => { + openerUrl = url + openerOpts = options + if (openerResult) { + throw openerResult + } + }, }, readline, }) diff --git a/deps/npm/test/lib/utils/open-url.js b/deps/npm/test/lib/utils/open-url.js index 70afd550333f74..28a11b3609c674 100644 --- a/deps/npm/test/lib/utils/open-url.js +++ b/deps/npm/test/lib/utils/open-url.js @@ -1,4 +1,5 @@ const t = require('tap') +const tmock = require('../../fixtures/tmock') const OUTPUT = [] const output = (...args) => OUTPUT.push(args) @@ -28,7 +29,7 @@ const open = async (url, options) => { } } -const openUrl = t.mock('../../../lib/utils/open-url.js', { +const openUrl = tmock(t, '{LIB}/utils/open-url.js', { '@npmcli/promise-spawn': { open, }, diff --git a/deps/npm/test/lib/utils/otplease.js b/deps/npm/test/lib/utils/otplease.js index 79eaa798e60539..d788c39da842c5 100644 --- a/deps/npm/test/lib/utils/otplease.js +++ b/deps/npm/test/lib/utils/otplease.js @@ -1,74 +1,74 @@ const t = require('tap') +const setupMockNpm = require('../../fixtures/mock-npm') +const tmock = require('../../fixtures/tmock') -const { fake: mockNpm } = require('../../fixtures/mock-npm') -const mockGlobals = require('../../fixtures/mock-globals') +const setupOtplease = async (t, { otp = {}, ...rest }, fn) => { + const readUserInfo = { + otp: async () => '1234', + } -const readUserInfo = { - otp: async () => '1234', -} -const webAuth = async (opener) => { - opener() - return '1234' -} + const webAuth = async (opener) => { + opener() + return '1234' + } -const otplease = t.mock('../../../lib/utils/otplease.js', { - '../../../lib/utils/read-user-info.js': readUserInfo, - '../../../lib/utils/open-url-prompt.js': () => {}, - '../../../lib/utils/web-auth': webAuth, -}) + const otplease = tmock(t, '{LIB}/utils/otplease.js', { + '{LIB}/utils/read-user-info.js': readUserInfo, + '{LIB}/utils/open-url-prompt.js': () => {}, + '{LIB}/utils/web-auth': webAuth, + }) + + const { npm } = await setupMockNpm(t, rest) + + return await otplease(npm, otp, fn) +} t.test('returns function results on success', async (t) => { - const fn = () => 'test string' - const result = await otplease(null, {}, fn) + const result = await setupOtplease(t, {}, () => 'test string') t.equal('test string', result) }) t.test('returns function results on otp success', async (t) => { - mockGlobals(t, { - 'process.stdin': { isTTY: true }, - 'process.stdout': { isTTY: true }, - }) const fn = ({ otp }) => { if (otp) { return 'success' } throw Object.assign(new Error('nope'), { code: 'EOTP' }) } - const result = await otplease(null, {}, fn) + + const result = await setupOtplease(t, { + globals: { + 'process.stdin': { isTTY: true }, + 'process.stdout': { isTTY: true }, + }, + }, fn) + t.equal('success', result) }) t.test('prompts for otp for EOTP', async (t) => { - const stdinTTY = process.stdin.isTTY - const stdoutTTY = process.stdout.isTTY - process.stdin.isTTY = true - process.stdout.isTTY = true - t.teardown(() => { - process.stdin.isTTY = stdinTTY - process.stdout.isTTY = stdoutTTY - }) + let called = false - let runs = 0 const fn = async (opts) => { - if (++runs === 1) { + if (!called) { + called = true throw Object.assign(new Error('nope'), { code: 'EOTP' }) } - - t.equal(opts.some, 'prop', 'carried original options') - t.equal(opts.otp, '1234', 'received the otp') - t.end() + return opts } - await otplease(null, { some: 'prop' }, fn) + const result = await setupOtplease(t, { + otp: { some: 'prop' }, + globals: { + 'process.stdin': { isTTY: true }, + 'process.stdout': { isTTY: true }, + }, + }, fn) + + t.strictSame(result, { some: 'prop', otp: '1234' }) }) t.test('returns function results on webauth success', async (t) => { - mockGlobals(t, { - 'process.stdin': { isTTY: true }, - 'process.stdout': { isTTY: true }, - }) - - const npm = mockNpm({ config: { browser: 'firefox' } }) const fn = ({ otp }) => { if (otp) { return 'success' @@ -82,75 +82,64 @@ t.test('returns function results on webauth success', async (t) => { }) } - const result = await otplease(npm, {}, fn) + const result = await setupOtplease(t, { + config: { browser: 'firefox' }, + globals: { + 'process.stdin': { isTTY: true }, + 'process.stdout': { isTTY: true }, + }, + }, fn) + t.equal('success', result) }) t.test('prompts for otp for 401', async (t) => { - const stdinTTY = process.stdin.isTTY - const stdoutTTY = process.stdout.isTTY - process.stdin.isTTY = true - process.stdout.isTTY = true - t.teardown(() => { - process.stdin.isTTY = stdinTTY - process.stdout.isTTY = stdoutTTY - }) + let called = false - let runs = 0 const fn = async (opts) => { - if (++runs === 1) { + if (!called) { + called = true throw Object.assign(new Error('nope'), { code: 'E401', body: 'one-time pass required', }) } - t.equal(opts.some, 'prop', 'carried original options') - t.equal(opts.otp, '1234', 'received the otp') - t.end() + return opts } - await otplease(null, { some: 'prop' }, fn) + const result = await setupOtplease(t, { + globals: { + 'process.stdin': { isTTY: true }, + 'process.stdout': { isTTY: true }, + }, + }, fn) + + t.strictSame(result, { otp: '1234' }) }) t.test('does not prompt for non-otp errors', async (t) => { - const stdinTTY = process.stdin.isTTY - const stdoutTTY = process.stdout.isTTY - process.stdin.isTTY = true - process.stdout.isTTY = true - t.teardown(() => { - process.stdin.isTTY = stdinTTY - process.stdout.isTTY = stdoutTTY - }) - const fn = async (opts) => { throw new Error('nope') } - t.rejects( - otplease(null, { some: 'prop' }, fn), - { message: 'nope' }, - 'rejects with the original error' - ) + await t.rejects(setupOtplease(t, { + globals: { + 'process.stdin': { isTTY: true }, + 'process.stdout': { isTTY: true }, + }, + }, fn), { message: 'nope' }, 'rejects with the original error') }) t.test('does not prompt if stdin or stdout is not a tty', async (t) => { - const stdinTTY = process.stdin.isTTY - const stdoutTTY = process.stdout.isTTY - process.stdin.isTTY = false - process.stdout.isTTY = false - t.teardown(() => { - process.stdin.isTTY = stdinTTY - process.stdout.isTTY = stdoutTTY - }) - const fn = async (opts) => { throw Object.assign(new Error('nope'), { code: 'EOTP' }) } - t.rejects( - otplease(null, { some: 'prop' }, fn), - { message: 'nope' }, - 'rejects with the original error' - ) + await t.rejects(setupOtplease(t, { + globals: { + 'process.stdin': { isTTY: false }, + 'process.stdout': { isTTY: false }, + }, + }, fn), { message: 'nope' }, 'rejects with the original error') }) diff --git a/deps/npm/test/lib/utils/pulse-till-done.js b/deps/npm/test/lib/utils/pulse-till-done.js index 9f7a94614d3bb5..3b3f4b2f2253ef 100644 --- a/deps/npm/test/lib/utils/pulse-till-done.js +++ b/deps/npm/test/lib/utils/pulse-till-done.js @@ -1,8 +1,9 @@ const t = require('tap') +const tmock = require('../../fixtures/tmock') let pulseStarted = null -const pulseTillDone = t.mock('../../../lib/utils/pulse-till-done.js', { +const pulseTillDone = tmock(t, '{LIB}/utils/pulse-till-done.js', { npmlog: { gauge: { pulse: () => { diff --git a/deps/npm/test/lib/utils/read-user-info.js b/deps/npm/test/lib/utils/read-user-info.js index be805a2a87c6a0..dfd17a8e37cbe8 100644 --- a/deps/npm/test/lib/utils/read-user-info.js +++ b/deps/npm/test/lib/utils/read-user-info.js @@ -1,4 +1,5 @@ const t = require('tap') +const tmock = require('../../fixtures/tmock') let readOpts = null let readResult = null @@ -25,7 +26,7 @@ const npmUserValidate = { } let logMsg = null -const readUserInfo = t.mock('../../../lib/utils/read-user-info.js', { +const readUserInfo = tmock(t, '{LIB}/utils/read-user-info.js', { read, npmlog: { clearProgress: () => {}, diff --git a/deps/npm/test/lib/utils/reify-finish.js b/deps/npm/test/lib/utils/reify-finish.js index b565034058adb7..ee112203a24bc8 100644 --- a/deps/npm/test/lib/utils/reify-finish.js +++ b/deps/npm/test/lib/utils/reify-finish.js @@ -1,4 +1,6 @@ const t = require('tap') +const { cleanNewlines } = require('../../fixtures/clean-snapshot') +const tmock = require('../../fixtures/tmock') const npm = { config: { @@ -30,9 +32,9 @@ const fs = { }, } -const reifyFinish = t.mock('../../../lib/utils/reify-finish.js', { +const reifyFinish = tmock(t, '{LIB}/utils/reify-finish.js', { fs, - '../../../lib/utils/reify-output.js': reifyOutput, + '{LIB}/utils/reify-output.js': reifyOutput, }) t.test('should not write if not global', async t => { @@ -74,6 +76,6 @@ t.test('should write if everything above passes', async t => { }, }) // windowwwwwwssss!!!!! - const data = fs.readFileSync(`${path}/npmrc`, 'utf8').replace(/\r\n/g, '\n') + const data = cleanNewlines(fs.readFileSync(`${path}/npmrc`, 'utf8')) 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 b38a14de339098..5d1d5be47efa30 100644 --- a/deps/npm/test/lib/utils/reify-output.js +++ b/deps/npm/test/lib/utils/reify-output.js @@ -1,25 +1,22 @@ const t = require('tap') +const mockNpm = require('../../fixtures/mock-npm') +const reifyOutput = require('../../../lib/utils/reify-output.js') t.cleanSnapshot = str => str.replace(/in [0-9]+m?s/g, 'in {TIME}') -const settings = { - fund: true, -} -const npm = { - started: Date.now(), - flatOptions: settings, - silent: false, +const mockReify = async (t, reify, { command, ...config } = {}) => { + const mock = await mockNpm(t, { + command, + config, + }) + + reifyOutput(mock.npm, reify) + + return mock.joinedOutput() } -const reifyOutput = require('../../../lib/utils/reify-output.js') -t.test('missing info', (t) => { - t.plan(1) - npm.output = out => t.notMatch( - out, - 'looking for funding', - 'should not print fund message if missing info' - ) - reifyOutput(npm, { +t.test('missing info', async t => { + const out = await mockReify(t, { actualTree: { children: [], }, @@ -27,36 +24,30 @@ t.test('missing info', (t) => { children: [], }, }) -}) -t.test('even more missing info', t => { - t.plan(1) - npm.output = out => t.notMatch( + t.notMatch( out, 'looking for funding', 'should not print fund message if missing info' ) +}) - reifyOutput(npm, { +t.test('even more missing info', async t => { + const out = await mockReify(t, { actualTree: { children: [], }, }) -}) -t.test('single package', (t) => { - t.plan(1) - npm.output = out => { - if (out.endsWith('looking for funding')) { - t.match( - out, - '1 package is looking for funding', - 'should print single package message' - ) - } - } + t.notMatch( + out, + 'looking for funding', + 'should not print fund message if missing info' + ) +}) - reifyOutput(npm, { +t.test('single package', async t => { + const out = await mockReify(t, { // a report with an error is the same as no report at all, if // the command is not 'audit' auditReport: { @@ -87,20 +78,16 @@ t.test('single package', (t) => { children: [], }, }) -}) -t.test('no message when funding config is false', (t) => { - t.teardown(() => { - settings.fund = true - }) - settings.fund = false - npm.output = out => { - if (out.endsWith('looking for funding')) { - t.fail('should not print funding info', { actual: out }) - } - } + t.match( + out, + '1 package is looking for funding', + 'should print single package message' + ) +}) - reifyOutput(npm, { +t.test('no message when funding config is false', async t => { + const out = await mockReify(t, { actualTree: { name: 'foo', package: { @@ -123,24 +110,13 @@ t.test('no message when funding config is false', (t) => { diff: { children: [], }, - }) + }, { fund: false }) - t.end() + t.notMatch(out, 'looking for funding', 'should not print funding info') }) -t.test('print appropriate message for many packages', (t) => { - t.plan(1) - npm.output = out => { - if (out.endsWith('looking for funding')) { - t.match( - out, - '3 packages are looking for funding', - 'should print single package message' - ) - } - } - - reifyOutput(npm, { +t.test('print appropriate message for many packages', async t => { + const out = await mockReify(t, { actualTree: { name: 'foo', package: { @@ -184,6 +160,12 @@ t.test('print appropriate message for many packages', (t) => { children: [], }, }) + + t.match( + out, + '3 packages are looking for funding', + 'should print single package message' + ) }) t.test('showing and not showing audit report', async t => { @@ -231,15 +213,8 @@ t.test('showing and not showing audit report', async t => { }, } - t.test('no output when silent', t => { - t.teardown(() => { - delete npm.silent - }) - npm.silent = true - npm.output = out => { - t.fail('should not get output when silent', { actual: out }) - } - reifyOutput(npm, { + t.test('no output when silent', async t => { + const out = await mockReify(t, { actualTree: { inventory: { size: 999 }, children: [] }, auditReport, diff: { @@ -247,16 +222,12 @@ t.test('showing and not showing audit report', async t => { { action: 'ADD', ideal: { location: 'loc' } }, ], }, - }) - t.end() + }, { silent: true }) + t.equal(out, '', 'should not get output when silent') }) - t.test('output when not silent', t => { - const OUT = [] - npm.output = out => { - OUT.push(out) - } - reifyOutput(npm, { + t.test('output when not silent', async t => { + const out = await mockReify(t, { actualTree: { inventory: new Map(), children: [] }, auditReport, diff: { @@ -265,33 +236,14 @@ t.test('showing and not showing audit report', async t => { ], }, }) - t.match(OUT.join('\n'), /Run `npm audit` for details\.$/, 'got audit report') - t.end() + + t.match(out, /Run `npm audit` for details\.$/, 'got audit report') }) for (const json of [true, false]) { - t.test(`json=${json}`, t => { - t.teardown(() => { - delete npm.flatOptions.json - }) - npm.flatOptions.json = json - t.test('set exit code when cmd is audit', t => { - npm.output = () => {} - const { exitCode } = process - const { command } = npm - npm.flatOptions.auditLevel = 'low' - t.teardown(() => { - delete npm.flatOptions.auditLevel - npm.command = command - // only set exitCode back if we're passing tests - if (t.passing()) { - process.exitCode = exitCode - } - }) - - process.exitCode = 0 - npm.command = 'audit' - reifyOutput(npm, { + t.test(`json=${json}`, async t => { + t.test('set exit code when cmd is audit', async t => { + await mockReify(t, { actualTree: { inventory: new Map(), children: [] }, auditReport, diff: { @@ -299,29 +251,13 @@ t.test('showing and not showing audit report', async t => { { action: 'ADD', ideal: { location: 'loc' } }, ], }, - }) + }, { command: 'audit', 'audit-level': 'low' }) t.equal(process.exitCode, 1, 'set exit code') - t.end() }) - t.test('do not set exit code when cmd is install', t => { - npm.output = () => {} - const { exitCode } = process - const { command } = npm - npm.flatOptions.auditLevel = 'low' - t.teardown(() => { - delete npm.flatOptions.auditLevel - npm.command = command - // only set exitCode back if we're passing tests - if (t.passing()) { - process.exitCode = exitCode - } - }) - - process.exitCode = 0 - npm.command = 'install' - reifyOutput(npm, { + t.test('do not set exit code when cmd is install', async t => { + await mockReify(t, { actualTree: { inventory: new Map(), children: [] }, auditReport, diff: { @@ -329,28 +265,17 @@ t.test('showing and not showing audit report', async t => { { action: 'ADD', ideal: { location: 'loc' } }, ], }, - }) + }, { command: 'install', 'audit-level': 'low' }) - t.equal(process.exitCode, 0, 'did not set exit code') - t.end() + t.notOk(process.exitCode, 'did not set exit code') }) - t.end() }) } - - t.end() }) -t.test('packages changed message', t => { - const output = [] - npm.output = out => { - output.push(out) - } - +t.test('packages changed message', async t => { // return a test function that builds up the mock and snapshots output - const testCase = (t, added, removed, changed, audited, json, command) => { - settings.json = json - npm.command = command + const testCase = async (t, added, removed, changed, audited, json, command) => { const mock = { actualTree: { inventory: { size: audited, has: () => true }, @@ -384,9 +309,9 @@ t.test('packages changed message', t => { const ideal = { location: 'loc' } mock.diff.children.push({ action: 'CHANGE', actual, ideal }) } - output.length = 0 - reifyOutput(npm, mock) - t.matchSnapshot(output.join('\n'), JSON.stringify({ + + const out = await mockReify(t, mock, { json, command }) + t.matchSnapshot(out, JSON.stringify({ added, removed, changed, @@ -412,20 +337,14 @@ t.test('packages changed message', t => { cases.push([0, 0, 0, 2, true, 'audit']) cases.push([0, 0, 0, 2, false, 'audit']) - t.plan(cases.length) - for (const [added, removed, changed, audited, json, command] of cases) { - testCase(t, added, removed, changed, audited, json, command) + for (const c of cases) { + await t.test('', t => testCase(t, ...c)) } - - t.end() }) -t.test('added packages should be looked up within returned tree', t => { - t.test('has added pkg in inventory', t => { - t.plan(1) - npm.output = out => t.matchSnapshot(out) - - reifyOutput(npm, { +t.test('added packages should be looked up within returned tree', async t => { + t.test('has added pkg in inventory', async t => { + const out = await mockReify(t, { actualTree: { name: 'foo', inventory: { @@ -438,13 +357,12 @@ t.test('added packages should be looked up within returned tree', t => { ], }, }) - }) - t.test('missing added pkg in inventory', t => { - t.plan(1) - npm.output = out => t.matchSnapshot(out) + t.matchSnapshot(out) + }) - reifyOutput(npm, { + t.test('missing added pkg in inventory', async t => { + const out = await mockReify(t, { actualTree: { name: 'foo', inventory: { @@ -457,6 +375,7 @@ t.test('added packages should be looked up within returned tree', t => { ], }, }) + + t.matchSnapshot(out) }) - t.end() }) diff --git a/deps/npm/test/lib/utils/tar.js b/deps/npm/test/lib/utils/tar.js index f72b1432c89d6f..78c01f3f57ae40 100644 --- a/deps/npm/test/lib/utils/tar.js +++ b/deps/npm/test/lib/utils/tar.js @@ -1,10 +1,11 @@ const t = require('tap') const pack = require('libnpmpack') const ssri = require('ssri') +const tmock = require('../../fixtures/tmock') const { getContents } = require('../../../lib/utils/tar.js') -const mockTar = ({ notice }) => t.mock('../../../lib/utils/tar.js', { +const mockTar = ({ notice }) => tmock(t, '{LIB}/utils/tar.js', { 'proc-log': { notice, }, diff --git a/deps/npm/test/lib/utils/timers.js b/deps/npm/test/lib/utils/timers.js index 23d8eb6e2cafef..74df6c28cd361c 100644 --- a/deps/npm/test/lib/utils/timers.js +++ b/deps/npm/test/lib/utils/timers.js @@ -2,10 +2,11 @@ const t = require('tap') const { resolve, join } = require('path') const fs = require('graceful-fs') const mockLogs = require('../../fixtures/mock-logs') +const tmock = require('../../fixtures/tmock') const mockTimers = (t, options) => { const { logs, logMocks } = mockLogs() - const Timers = t.mock('../../../lib/utils/timers', { + const Timers = tmock(t, '{LIB}/utils/timers', { ...logMocks, }) const timers = new Timers(options) diff --git a/deps/npm/test/lib/utils/update-notifier.js b/deps/npm/test/lib/utils/update-notifier.js index fa4a04bad9839c..e7830e6d9d66e0 100644 --- a/deps/npm/test/lib/utils/update-notifier.js +++ b/deps/npm/test/lib/utils/update-notifier.js @@ -1,4 +1,6 @@ const t = require('tap') +const tmock = require('../../fixtures/tmock') + let ciMock = {} const flatOptions = { global: false, cache: t.testdir() + '/_cacache' } @@ -17,7 +19,6 @@ let PACOTE_ERROR = null const pacote = { manifest: async (spec, opts) => { if (!spec.match(/^npm@/)) { - console.error(new Error('should only fetch manifest for npm')) process.exit(1) } MANIFEST_REQUEST.push(spec) @@ -53,22 +54,15 @@ const fs = { ...require('fs'), stat: (path, cb) => { if (basename(path) !== '_update-notifier-last-checked') { - console.error( - new Error('should only write to notifier last checked file') - ) process.exit(1) } process.nextTick(() => cb(STAT_ERROR, { mtime: new Date(STAT_MTIME) })) }, writeFile: (path, content, cb) => { if (content !== '') { - console.error(new Error('should not be writing content')) process.exit(1) } if (basename(path) !== '_update-notifier-last-checked') { - console.error( - new Error('should only write to notifier last checked file') - ) process.exit(1) } process.nextTick(() => cb(WRITE_ERROR)) @@ -85,7 +79,7 @@ t.afterEach(() => { const runUpdateNotifier = async ({ color = true, ...npmOptions } = {}) => { const _npm = { ...defaultNpm, ...npmOptions, logColor: color } - return t.mock('../../../lib/utils/update-notifier.js', { + return tmock(t, '{LIB}/utils/update-notifier.js', { 'ci-info': ciMock, pacote, fs, diff --git a/deps/npm/test/lib/utils/web-auth.js b/deps/npm/test/lib/utils/web-auth.js index ee8a17ecbc09d4..a4e8f4bbc755dc 100644 --- a/deps/npm/test/lib/utils/web-auth.js +++ b/deps/npm/test/lib/utils/web-auth.js @@ -1,10 +1,11 @@ const t = require('tap') +const tmock = require('../../fixtures/tmock') const webAuthCheckLogin = async () => { return { token: 'otp-token' } } -const webauth = t.mock('../../../lib/utils/web-auth.js', { +const webauth = tmock(t, '{LIB}/utils/web-auth.js', { 'npm-profile': { webAuthCheckLogin }, })