From 4a22850d7f2845ca6c543295514a9610cf28996c Mon Sep 17 00:00:00 2001 From: Ruy Adorno Date: Thu, 13 May 2021 16:18:53 -0400 Subject: [PATCH] deps: upgrade npm to 7.13.0 PR-URL: https://github.com/nodejs/node/pull/38682 Reviewed-By: Rich Trott Reviewed-By: Danielle Adams Reviewed-By: Trivikram Kamat Reviewed-By: Luigi Pinca Reviewed-By: Colin Ihrig --- deps/npm/CHANGELOG.md | 18 +++ deps/npm/docs/content/commands/npm-fund.md | 56 ++++++++ deps/npm/docs/content/commands/npm-publish.md | 7 + deps/npm/docs/output/commands/npm-fund.html | 45 ++++++ deps/npm/docs/output/commands/npm-ls.html | 2 +- .../npm/docs/output/commands/npm-publish.html | 9 ++ deps/npm/docs/output/commands/npm.html | 2 +- deps/npm/lib/fund.js | 16 ++- deps/npm/lib/publish.js | 76 ++++++---- deps/npm/lib/workspaces/arborist-cmd.js | 24 ++++ deps/npm/man/man1/npm-fund.1 | 67 +++++++++ deps/npm/man/man1/npm-ls.1 | 2 +- deps/npm/man/man1/npm-publish.1 | 7 + deps/npm/man/man1/npm.1 | 2 +- .../@npmcli/arborist/lib/arborist/index.js | 23 +++ .../arborist/lib/get-workspace-nodes.js | 33 +++++ .../@npmcli/arborist/package.json | 2 +- deps/npm/node_modules/libnpmfund/CHANGELOG.md | 6 - deps/npm/node_modules/libnpmfund/README.md | 5 +- deps/npm/node_modules/libnpmfund/index.js | 63 +++++---- deps/npm/node_modules/libnpmfund/package.json | 19 ++- deps/npm/package.json | 8 +- .../tap-snapshots/test/lib/fund.js.test.cjs | 20 +++ .../test/lib/publish.js.test.cjs | 103 ++++++++++++++ .../test/lib/utils/npm-usage.js.test.cjs | 3 + deps/npm/test/lib/fund.js | 86 ++++++++++++ deps/npm/test/lib/publish.js | 132 +++++++++++++++--- deps/npm/test/lib/workspaces/arborist-cmd.js | 109 +++++++++++++++ 28 files changed, 846 insertions(+), 99 deletions(-) create mode 100644 deps/npm/lib/workspaces/arborist-cmd.js create mode 100644 deps/npm/node_modules/@npmcli/arborist/lib/get-workspace-nodes.js delete mode 100644 deps/npm/node_modules/libnpmfund/CHANGELOG.md create mode 100644 deps/npm/test/lib/workspaces/arborist-cmd.js diff --git a/deps/npm/CHANGELOG.md b/deps/npm/CHANGELOG.md index bed0f87c2b80c9..1c36c70875f722 100644 --- a/deps/npm/CHANGELOG.md +++ b/deps/npm/CHANGELOG.md @@ -1,3 +1,21 @@ +## v7.13.0 (2021-05-13) + +* [`076420c14`](https://github.com/npm/cli/commit/076420c149d097056f687e44e21744b743b86e4e) + [#3231](https://github.com/npm/cli/issues/3231) + feat(publish): add workspace support + ([@wraithgar](https://github.com/wraithgar)) +* [`370b36a36`](https://github.com/npm/cli/commit/370b36a36ca226840761e4214cbccaf2a1a90e3c) + [#3241](https://github.com/npm/cli/issues/3241) + feat(fund): add workspaces support + ([@ruyadorno](https://github.com/ruyadorno)) + +### DEPENDENCIES + +* [`0c18e4f77`](https://github.com/npm/cli/commit/0c18e4f774562fa054fedf323bea25805ebf39b3) + `@npmcli/arborist@2.5.0` +* [`b551c6811`](https://github.com/npm/cli/commit/b551c6811251dbc901f47fea3c137f93e205a9e4) + `libnpmfund@1.1.0` + ## v7.12.1 (2021-05-10) ### BUG FIXES diff --git a/deps/npm/docs/content/commands/npm-fund.md b/deps/npm/docs/content/commands/npm-fund.md index aa1b26b9a8971b..45c5dfaac2afc2 100644 --- a/deps/npm/docs/content/commands/npm-fund.md +++ b/deps/npm/docs/content/commands/npm-fund.md @@ -8,6 +8,7 @@ description: Retrieve funding information ```bash npm fund [] +npm fund [-w ] ``` ### Description @@ -24,6 +25,43 @@ The list will avoid duplicated entries and will stack all packages that share the same url as a single entry. Thus, the list does not have the same shape of the output from `npm ls`. +#### Example + +### Workspaces support + +It's possible to filter the results to only include a single workspace and its +dependencies using the `workspace` config option. + +#### Example: + +Here's an example running `npm fund` in a project with a configured +workspace `a`: + +```bash +$ npm fund +test-workspaces-fund@1.0.0 ++-- https://example.com/a +| | `-- a@1.0.0 +| `-- https://example.com/maintainer +| `-- foo@1.0.0 ++-- https://example.com/npmcli-funding +| `-- @npmcli/test-funding +`-- https://example.com/org + `-- bar@2.0.0 +``` + +And here is an example of the expected result when filtering only by +a specific workspace `a` in the same project: + +```bash +$ npm fund -w a +test-workspaces-fund@1.0.0 +`-- https://example.com/a + | `-- a@1.0.0 + `-- https://example.com/maintainer + `-- foo@2.0.0 +``` + ### Configuration #### browser @@ -48,6 +86,23 @@ Show information in JSON format. Whether to represent the tree structure using unicode characters. Set it to `false` in order to use all-ansi output. +#### `workspace` + +* Default: +* Type: String (can be set multiple times) + +Enable running a command in the context of the configured workspaces of the +current project while filtering by running only the workspaces defined by +this configuration option. + +Valid values for the `workspace` config are either: +* Workspace names +* Path to a workspace directory +* Path to a parent workspace directory (will result to selecting all of the +nested workspaces) + +This value is not exported to the environment for child processes. + #### which * Type: Number @@ -61,3 +116,4 @@ If there are multiple funding sources, which 1-indexed source URL to open. * [npm docs](/commands/npm-docs) * [npm ls](/commands/npm-ls) * [npm config](/commands/npm-config) +* [npm workspaces](/using-npm/workspaces) diff --git a/deps/npm/docs/content/commands/npm-publish.md b/deps/npm/docs/content/commands/npm-publish.md index fc13e672223589..10e65f895ec5bc 100644 --- a/deps/npm/docs/content/commands/npm-publish.md +++ b/deps/npm/docs/content/commands/npm-publish.md @@ -47,6 +47,13 @@ by specifying a different default registry or using a actually publishing to the registry. Reports the details of what would have been published. +* `[--workspaces]`: Enables workspace context while publishing. All + workspace packages will be published. + +* `[--workspace]`: Enables workspaces context and limits results to only + those specified by this config item. Only the packages in the + workspaces given will be published. + The publish will fail if the package name and version combination already exists in the specified registry. diff --git a/deps/npm/docs/output/commands/npm-fund.html b/deps/npm/docs/output/commands/npm-fund.html index bd9118fe326559..16539cfd998685 100644 --- a/deps/npm/docs/output/commands/npm-fund.html +++ b/deps/npm/docs/output/commands/npm-fund.html @@ -146,6 +146,7 @@

Table of contents

Synopsis

npm fund [<pkg>]
+npm fund [-w <workspace-name>]
 

Description

This command retrieves information on how to fund the dependencies of a @@ -158,6 +159,33 @@

Description

The list will avoid duplicated entries and will stack all packages that share the same url as a single entry. Thus, the list does not have the same shape of the output from npm ls.

+

Example

+

Workspaces support

+

It’s possible to filter the results to only include a single workspace and its +dependencies using the workspace config option.

+

Example:

+

Here’s an example running npm fund in a project with a configured +workspace a:

+
$ npm fund
+test-workspaces-fund@1.0.0
++-- https://example.com/a
+| | `-- a@1.0.0
+| `-- https://example.com/maintainer
+|     `-- foo@1.0.0
++-- https://example.com/npmcli-funding
+|   `-- @npmcli/test-funding
+`-- https://example.com/org
+    `-- bar@2.0.0
+
+

And here is an example of the expected result when filtering only by +a specific workspace a in the same project:

+
$ npm fund -w a
+test-workspaces-fund@1.0.0
+`-- https://example.com/a
+  | `-- a@1.0.0
+  `-- https://example.com/maintainer
+      `-- foo@2.0.0
+

Configuration

browser

    @@ -178,6 +206,22 @@

    unicode

Whether to represent the tree structure using unicode characters. Set it to false in order to use all-ansi output.

+

workspace

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

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

+

Valid values for the workspace config are either:

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

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

which

diff --git a/deps/npm/docs/output/commands/npm-ls.html b/deps/npm/docs/output/commands/npm-ls.html index 3d60f2baecd2b2..be1f7cd94a62a4 100644 --- a/deps/npm/docs/output/commands/npm-ls.html +++ b/deps/npm/docs/output/commands/npm-ls.html @@ -159,7 +159,7 @@

Description

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

-
npm@7.12.1 /path/to/npm
+
npm@7.13.0 /path/to/npm
 └─┬ init-package-json@0.0.4
   └── promzard@0.1.5
 
diff --git a/deps/npm/docs/output/commands/npm-publish.html b/deps/npm/docs/output/commands/npm-publish.html index fc9136d356b481..159566e09a0706 100644 --- a/deps/npm/docs/output/commands/npm-publish.html +++ b/deps/npm/docs/output/commands/npm-publish.html @@ -188,6 +188,15 @@

Description

actually publishing to the registry. Reports the details of what would have been published.

+
  • +

    [--workspaces]: Enables workspace context while publishing. All +workspace packages will be published.

    +
  • +
  • +

    [--workspace]: Enables workspaces context and limits results to only +those specified by this config item. Only the packages in the +workspaces given will be published.

    +
  • The publish will fail if the package name and version combination already exists in the specified registry.

    diff --git a/deps/npm/docs/output/commands/npm.html b/deps/npm/docs/output/commands/npm.html index 445abd0d5ce3e0..1adcb07e046c33 100644 --- a/deps/npm/docs/output/commands/npm.html +++ b/deps/npm/docs/output/commands/npm.html @@ -148,7 +148,7 @@

    Table of contents

    npm <command> [args]
     

    Version

    -

    7.12.1

    +

    7.13.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 diff --git a/deps/npm/lib/fund.js b/deps/npm/lib/fund.js index 25d3462f638693..55d2f65dc4b55c 100644 --- a/deps/npm/lib/fund.js +++ b/deps/npm/lib/fund.js @@ -13,15 +13,14 @@ const { const completion = require('./utils/completion/installed-deep.js') const openUrl = require('./utils/open-url.js') +const ArboristWorkspaceCmd = require('./workspaces/arborist-cmd.js') const getPrintableName = ({ name, version }) => { const printableVersion = version ? `@${version}` : '' return `${name}${printableVersion}` } -const BaseCommand = require('./base-command.js') - -class Fund extends BaseCommand { +class Fund extends ArboristWorkspaceCmd { /* istanbul ignore next - see test/lib/load-all-commands.js */ static get description () { return 'Retrieve funding information' @@ -38,6 +37,7 @@ class Fund extends BaseCommand { 'json', 'browser', 'unicode', + 'workspace', 'which', ] } @@ -92,10 +92,16 @@ class Fund extends BaseCommand { return } + const fundingInfo = getFundingInfo(tree, { + ...this.flatOptions, + log: this.npm.log, + workspaces: this.workspaces, + }) + if (this.npm.config.get('json')) - this.npm.output(this.printJSON(getFundingInfo(tree))) + this.npm.output(this.printJSON(fundingInfo)) else - this.npm.output(this.printHuman(getFundingInfo(tree))) + this.npm.output(this.printHuman(fundingInfo)) } printJSON (fundingInfo) { diff --git a/deps/npm/lib/publish.js b/deps/npm/lib/publish.js index b121cb3d36773a..b33839903a266d 100644 --- a/deps/npm/lib/publish.js +++ b/deps/npm/lib/publish.js @@ -8,13 +8,19 @@ const pacote = require('pacote') const npa = require('npm-package-arg') const npmFetch = require('npm-registry-fetch') -const flatten = require('./utils/config/flatten.js') const otplease = require('./utils/otplease.js') const { getContents, logTar } = require('./utils/tar.js') +const getWorkspaces = require('./workspaces/get-workspaces.js') + +// for historical reasons, publishConfig in package.json can contain ANY config +// keys that npm supports in .npmrc files and elsewhere. We *may* want to +// revisit this at some point, and have a minimal set that's a SemVer-major +// change that ought to get a RFC written on it. +const flatten = require('./utils/config/flatten.js') -// this is the only case in the CLI where we use the old full slow -// 'read-package-json' module, because we want to pull in all the -// defaults and metadata, like git sha's and default scripts and all that. +// this is the only case in the CLI where we want to use the old full slow +// 'read-package-json' module, because we want to pull in all the defaults and +// metadata, like git sha's and default scripts and all that. const readJson = util.promisify(require('read-package-json')) const BaseCommand = require('./base-command.js') @@ -30,7 +36,7 @@ class Publish extends BaseCommand { /* istanbul ignore next - see test/lib/load-all-commands.js */ static get params () { - return ['tag', 'access', 'dry-run'] + return ['tag', 'access', 'dry-run', 'workspace', 'workspaces'] } /* istanbul ignore next - see test/lib/load-all-commands.js */ @@ -44,6 +50,10 @@ class Publish extends BaseCommand { this.publish(args).then(() => cb()).catch(cb) } + execWorkspaces (args, filters, cb) { + this.publishWorkspaces(args, filters).then(() => cb()).catch(cb) + } + async publish (args) { if (args.length === 0) args = ['.'] @@ -56,6 +66,7 @@ class Publish extends BaseCommand { const dryRun = this.npm.config.get('dry-run') const json = this.npm.config.get('json') const defaultTag = this.npm.config.get('tag') + const silent = log.level === 'silent' if (semver.validRange(defaultTag)) throw new Error('Tag name must not be a valid SemVer range: ' + defaultTag.trim()) @@ -68,7 +79,7 @@ class Publish extends BaseCommand { let manifest = await this.getManifest(spec, opts) if (manifest.publishConfig) - Object.assign(opts, this.publishConfigToOpts(manifest.publishConfig)) + flatten(manifest.publishConfig, opts) // only run scripts for directory type publishes if (spec.type === 'directory') { @@ -77,7 +88,7 @@ class Publish extends BaseCommand { path: spec.fetchSpec, stdio: 'inherit', pkg: manifest, - banner: log.level !== 'silent', + banner: !silent, }) } @@ -89,7 +100,7 @@ class Publish extends BaseCommand { // note that publishConfig might have changed as well! manifest = await this.getManifest(spec, opts) if (manifest.publishConfig) - Object.assign(opts, this.publishConfigToOpts(manifest.publishConfig)) + flatten(manifest.publishConfig, opts) // note that logTar calls npmlog.notice(), so if we ARE in silent mode, // this will do nothing, but we still want it in the debuglog if it fails. @@ -114,7 +125,7 @@ class Publish extends BaseCommand { path: spec.fetchSpec, stdio: 'inherit', pkg: manifest, - banner: log.level !== 'silent', + banner: !silent, }) await runScript({ @@ -122,19 +133,43 @@ class Publish extends BaseCommand { path: spec.fetchSpec, stdio: 'inherit', pkg: manifest, - banner: log.level !== 'silent', + banner: !silent, }) } - const silent = log.level === 'silent' - if (!silent && json) - this.npm.output(JSON.stringify(pkgContents, null, 2)) - else if (!silent) - this.npm.output(`+ ${pkgContents.id}`) + if (!this.workspaces) { + if (!silent && json) + this.npm.output(JSON.stringify(pkgContents, null, 2)) + else if (!silent) + this.npm.output(`+ ${pkgContents.id}`) + } return pkgContents } + async publishWorkspaces (args, filters) { + // Suppresses JSON output in publish() so we can handle it here + this.workspaces = true + + const results = {} + const json = this.npm.config.get('json') + const silent = log.level === 'silent' + const workspaces = + await getWorkspaces(filters, { path: this.npm.localPrefix }) + for (const [name, workspace] of workspaces.entries()) { + const pkgContents = await this.publish([workspace]) + // This needs to be in-line w/ the rest of the output that non-JSON + // publish generates + if (!silent && !json) + this.npm.output(`+ ${pkgContents.id}`) + else + results[name] = pkgContents + } + + if (!silent && json) + this.npm.output(JSON.stringify(results, null, 2)) + } + // if it's a directory, read it from the file system // otherwise, get the full metadata from whatever it is getManifest (spec, opts) { @@ -142,16 +177,5 @@ class Publish extends BaseCommand { return readJson(`${spec.fetchSpec}/package.json`) return pacote.manifest(spec, { ...opts, fullMetadata: true }) } - - // for historical reasons, publishConfig in package.json can contain - // ANY config keys that npm supports in .npmrc files and elsewhere. - // We *may* want to revisit this at some point, and have a minimal set - // that's a SemVer-major change that ought to get a RFC written on it. - publishConfigToOpts (publishConfig) { - // create a new object that inherits from the config stack - // then squash the css-case into camelCase opts, like we do - // this is Object.assign()'ed onto the base npm.flatOptions - return flatten(publishConfig, {}) - } } module.exports = Publish diff --git a/deps/npm/lib/workspaces/arborist-cmd.js b/deps/npm/lib/workspaces/arborist-cmd.js new file mode 100644 index 00000000000000..f08843bd9ea5a8 --- /dev/null +++ b/deps/npm/lib/workspaces/arborist-cmd.js @@ -0,0 +1,24 @@ +// This is the base for all commands whose execWorkspaces just gets +// a list of workspace names and passes it on to new Arborist() to +// be able to run a filtered Arborist.reify() at some point. + +const BaseCommand = require('../base-command.js') +const getWorkspaces = require('../workspaces/get-workspaces.js') +class ArboristCmd extends BaseCommand { + /* istanbul ignore next - see test/lib/load-all-commands.js */ + static get params () { + return [ + 'workspace', + ] + } + + execWorkspaces (args, filters, cb) { + getWorkspaces(filters, { path: this.npm.localPrefix }) + .then(workspaces => { + this.workspaces = [...workspaces.keys()] + this.exec(args, cb) + }) + } +} + +module.exports = ArboristCmd diff --git a/deps/npm/man/man1/npm-fund.1 b/deps/npm/man/man1/npm-fund.1 index 81a277bb0087c2..aa21dad231882a 100644 --- a/deps/npm/man/man1/npm-fund.1 +++ b/deps/npm/man/man1/npm-fund.1 @@ -6,6 +6,7 @@ .RS 2 .nf npm fund [] +npm fund [\-w ] .fi .RE .SS Description @@ -21,6 +22,44 @@ to pass the \fB\-\-which\fP option to disambiguate\. The list will avoid duplicated entries and will stack all packages that share the same url as a single entry\. Thus, the list does not have the same shape of the output from \fBnpm ls\fP\|\. +.SS Example +.SS Workspaces support +.P +It's possible to filter the results to only include a single workspace and its +dependencies using the \fBworkspace\fP config option\. +.SS Example: +.P +Here's an example running \fBnpm fund\fP in a project with a configured +workspace \fBa\fP: +.P +.RS 2 +.nf +$ npm fund +test\-workspaces\-fund@1\.0\.0 ++\-\- https://example\.com/a +| | `\-\- a@1\.0\.0 +| `\-\- https://example\.com/maintainer +| `\-\- foo@1\.0\.0 ++\-\- https://example\.com/npmcli\-funding +| `\-\- @npmcli/test\-funding +`\-\- https://example\.com/org + `\-\- bar@2\.0\.0 +.fi +.RE +.P +And here is an example of the expected result when filtering only by +a specific workspace \fBa\fP in the same project: +.P +.RS 2 +.nf +$ npm fund \-w a +test\-workspaces\-fund@1\.0\.0 +`\-\- https://example\.com/a + | `\-\- a@1\.0\.0 + `\-\- https://example\.com/maintainer + `\-\- foo@2\.0\.0 +.fi +.RE .SS Configuration .SS browser .RS 0 @@ -53,6 +92,32 @@ Default: true .P Whether to represent the tree structure using unicode characters\. Set it to \fBfalse\fP in order to use all\-ansi output\. +.SS \fBworkspace\fP +.RS 0 +.IP \(bu 2 +Default: +.IP \(bu 2 +Type: String (can be set multiple times) + +.RE +.P +Enable running a command in the context of the configured workspaces of the +current project while filtering by running only the workspaces defined by +this configuration option\. +.P +Valid values for the \fBworkspace\fP config are either: +.RS 0 +.IP \(bu 2 +Workspace names +.IP \(bu 2 +Path to a workspace directory +.IP \(bu 2 +Path to a parent workspace directory (will result to selecting all of the +nested workspaces) + +.RE +.P +This value is not exported to the environment for child processes\. .SS which .RS 0 .IP \(bu 2 @@ -73,5 +138,7 @@ npm help docs npm help ls .IP \(bu 2 npm help config +.IP \(bu 2 +npm help workspaces .RE diff --git a/deps/npm/man/man1/npm-ls.1 b/deps/npm/man/man1/npm-ls.1 index c47da91875482f..d7013b296440c0 100644 --- a/deps/npm/man/man1/npm-ls.1 +++ b/deps/npm/man/man1/npm-ls.1 @@ -26,7 +26,7 @@ example, running \fBnpm ls promzard\fP in npm's source tree will show: .P .RS 2 .nf -npm@7\.12\.1 /path/to/npm +npm@7\.13\.0 /path/to/npm └─┬ init\-package\-json@0\.0\.4 └── promzard@0\.1\.5 .fi diff --git a/deps/npm/man/man1/npm-publish.1 b/deps/npm/man/man1/npm-publish.1 index c405f64f27e361..906c5a36e194fe 100644 --- a/deps/npm/man/man1/npm-publish.1 +++ b/deps/npm/man/man1/npm-publish.1 @@ -45,6 +45,13 @@ from a TTY then you'll be prompted\. \fB[\-\-dry\-run]\fP: As of \fBnpm@6\fP, does everything publish would do except actually publishing to the registry\. Reports the details of what would have been published\. +.IP \(bu 2 +\fB[\-\-workspaces]\fP: Enables workspace context while publishing\. All +workspace packages will be published\. +.IP \(bu 2 +\fB[\-\-workspace]\fP: Enables workspaces context and limits results to only +those specified by this config item\. Only the packages in the +workspaces given will be published\. .RE .P diff --git a/deps/npm/man/man1/npm.1 b/deps/npm/man/man1/npm.1 index 4562527e1b5ade..4921bcc656a555 100644 --- a/deps/npm/man/man1/npm.1 +++ b/deps/npm/man/man1/npm.1 @@ -10,7 +10,7 @@ npm [args] .RE .SS Version .P -7\.12\.1 +7\.13\.0 .SS Description .P npm is the package manager for the Node JavaScript platform\. It puts diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/arborist/index.js b/deps/npm/node_modules/@npmcli/arborist/lib/arborist/index.js index 3578d50389ea64..cd39df01af6c6f 100644 --- a/deps/npm/node_modules/@npmcli/arborist/lib/arborist/index.js +++ b/deps/npm/node_modules/@npmcli/arborist/lib/arborist/index.js @@ -45,6 +45,7 @@ const mixins = [ ] const Base = mixins.reduce((a, b) => b(a), require('events')) +const getWorkspaceNodes = require('../get-workspace-nodes.js') class Arborist extends Base { constructor (options = {}) { @@ -64,6 +65,28 @@ class Arborist extends Base { this.path = resolve(this.options.path) process.emit('timeEnd', 'arborist:ctor') } + + // returns an array of the actual nodes for all the workspaces + workspaceNodes (tree, workspaces) { + return getWorkspaceNodes(tree, workspaces, this.log) + } + + // returns a set of workspace nodes and all their deps + workspaceDependencySet (tree, workspaces) { + const wsNodes = this.workspaceNodes(tree, workspaces) + const set = new Set(wsNodes) + for (const node of set) { + for (const edge of node.edgesOut.values()) { + const dep = edge.to + if (dep) { + set.add(dep) + if (dep.target) + set.add(dep.target) + } + } + } + return set + } } module.exports = Arborist diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/get-workspace-nodes.js b/deps/npm/node_modules/@npmcli/arborist/lib/get-workspace-nodes.js new file mode 100644 index 00000000000000..6db489f69c5185 --- /dev/null +++ b/deps/npm/node_modules/@npmcli/arborist/lib/get-workspace-nodes.js @@ -0,0 +1,33 @@ +// Get the actual nodes corresponding to a root node's child workspaces, +// given a list of workspace names. +const relpath = require('./relpath.js') +const getWorkspaceNodes = (tree, workspaces, log) => { + const wsMap = tree.workspaces + if (!wsMap) { + log.warn('workspaces', 'filter set, but no workspaces present') + return [] + } + + const nodes = [] + for (const name of workspaces) { + const path = wsMap.get(name) + if (!path) { + log.warn('workspaces', `${name} in filter set, but not in workspaces`) + continue + } + + const loc = relpath(tree.realpath, path) + const node = tree.inventory.get(loc) + + if (!node) { + log.warn('workspaces', `${name} in filter set, but no workspace folder present`) + continue + } + + nodes.push(node) + } + + return nodes +} + +module.exports = getWorkspaceNodes diff --git a/deps/npm/node_modules/@npmcli/arborist/package.json b/deps/npm/node_modules/@npmcli/arborist/package.json index bbe87d8bf97ad2..fd579cbf27fdc8 100644 --- a/deps/npm/node_modules/@npmcli/arborist/package.json +++ b/deps/npm/node_modules/@npmcli/arborist/package.json @@ -1,6 +1,6 @@ { "name": "@npmcli/arborist", - "version": "2.4.4", + "version": "2.5.0", "description": "Manage node_modules trees", "dependencies": { "@npmcli/installed-package-contents": "^1.0.7", diff --git a/deps/npm/node_modules/libnpmfund/CHANGELOG.md b/deps/npm/node_modules/libnpmfund/CHANGELOG.md deleted file mode 100644 index b890b58e1405ae..00000000000000 --- a/deps/npm/node_modules/libnpmfund/CHANGELOG.md +++ /dev/null @@ -1,6 +0,0 @@ -# Changelog - -## 0.0.0-pre.0 - -- Initial pre-release. - diff --git a/deps/npm/node_modules/libnpmfund/README.md b/deps/npm/node_modules/libnpmfund/README.md index c373a9ceb7dd57..8ab663f634d6fb 100644 --- a/deps/npm/node_modules/libnpmfund/README.md +++ b/deps/npm/node_modules/libnpmfund/README.md @@ -73,7 +73,10 @@ Options: - `countOnly`: Uses the tree-traversal logic from **npm fund** but skips over any obj definition and just returns an obj containing `{ length }` - useful for things such as printing a `6 packages are looking for funding` msg. -- `path`: Location to current working directory +- `workspaces`: `Array` List of workspaces names to filter for, +the result will only include a subset of the resulting tree that includes +only the nodes that are children of the listed workspaces names. +- `path`, `registry` and more [Arborist](https://github.com/npm/arborist/) options. ##### `> fund.readTree(tree, [opts]) -> Promise` diff --git a/deps/npm/node_modules/libnpmfund/index.js b/deps/npm/node_modules/libnpmfund/index.js index 58aba028e36221..37bc1dd0b79165 100644 --- a/deps/npm/node_modules/libnpmfund/index.js +++ b/deps/npm/node_modules/libnpmfund/index.js @@ -15,11 +15,11 @@ function normalizeFunding (funding) { // Is the value of a `funding` property of a `package.json` // a valid type+url for `npm fund` to display? function isValidFunding (funding) { - if (!funding) return false + if (!funding) + return false - if (Array.isArray(funding)) { + if (Array.isArray(funding)) return funding.every(f => !Array.isArray(f) && isValidFunding(f)) - } try { var parsed = new URL(funding.url || funding) @@ -30,7 +30,8 @@ function isValidFunding (funding) { if ( parsed.protocol !== 'https:' && parsed.protocol !== 'http:' - ) return false + ) + return false return Boolean(parsed.host) } @@ -43,11 +44,18 @@ function readTree (tree, opts) { const { countOnly } = opts || {} const _trailingDependencies = Symbol('trailingDependencies') + let filterSet + + if (opts && opts.workspaces && opts.workspaces.length) { + const arb = new Arborist(opts) + filterSet = arb.workspaceDependencySet(tree, opts.workspaces) + } + function tracked (name, version) { const key = String(name) + String(version) - if (seen.has(key)) { + if (seen.has(key)) return true - } + seen.add(key) } @@ -81,30 +89,36 @@ function readTree (tree, opts) { function getFundingDependencies (tree) { const edges = tree && tree.edgesOut && tree.edgesOut.values() - if (!edges) return empty() + if (!edges) + return empty() const directDepsWithFunding = Array.from(edges).map(edge => { - if (!edge || !edge.to) return empty() + if (!edge || !edge.to) + return empty() const node = edge.to.target || edge.to - if (!node.package) return empty() + if (!node.package) + return empty() + + if (filterSet && filterSet.size > 0 && !filterSet.has(node)) + return empty() const { name, funding, version } = node.package // avoids duplicated items within the funding tree - if (tracked(name, version)) return empty() + if (tracked(name, version)) + return empty() const fundingItem = {} - if (version) { + if (version) fundingItem.version = version - } attachFundingInfo(fundingItem, funding) return { node, - fundingItem + fundingItem, } }) @@ -112,7 +126,8 @@ function readTree (tree, opts) { (res, { node, fundingItem }, i) => { if (!fundingItem || fundingItem.length === 0 || - !node) return res + !node) + return res // recurse const transitiveDependencies = node.edgesOut && @@ -121,16 +136,17 @@ function readTree (tree, opts) { // if we're only counting items there's no need // to add all the data to the resulting object - if (countOnly) return null + if (countOnly) + return null if (hasDependencies(transitiveDependencies)) { fundingItem.dependencies = retrieveDependencies(transitiveDependencies) } - if (isValidFunding(fundingItem.funding)) { + if (isValidFunding(fundingItem.funding)) res[node.package.name] = fundingItem - } else if (hasDependencies(fundingItem.dependencies)) { + else if (hasDependencies(fundingItem.dependencies)) { res[_trailingDependencies] = Object.assign( empty(), @@ -145,7 +161,7 @@ function readTree (tree, opts) { const treeDependencies = getFundingDependencies(tree) const result = { - length: packageWithFundingCount + length: packageWithFundingCount, } if (!countOnly) { @@ -154,13 +170,11 @@ function readTree (tree, opts) { (tree && tree.name) result.name = name || (tree && tree.path) - if (tree && tree.package && tree.package.version) { + if (tree && tree.package && tree.package.version) result.version = tree.package.version - } - if (tree && tree.package && tree.package.funding) { + if (tree && tree.package && tree.package.funding) result.funding = normalizeFunding(tree.package.funding) - } result.dependencies = retrieveDependencies(treeDependencies) } @@ -170,8 +184,7 @@ function readTree (tree, opts) { async function read (opts) { const arb = new Arborist(opts) - const tree = await arb.loadActual() - + const tree = await arb.loadActual(opts) return readTree(tree, opts) } @@ -179,5 +192,5 @@ module.exports = { read, readTree, normalizeFunding, - isValidFunding + isValidFunding, } diff --git a/deps/npm/node_modules/libnpmfund/package.json b/deps/npm/node_modules/libnpmfund/package.json index b25d3aa6b520eb..7f4acad383bb80 100644 --- a/deps/npm/node_modules/libnpmfund/package.json +++ b/deps/npm/node_modules/libnpmfund/package.json @@ -1,6 +1,6 @@ { "name": "libnpmfund", - "version": "1.0.2", + "version": "1.1.0", "files": [ "index.js" ], @@ -25,8 +25,10 @@ ], "license": "ISC", "scripts": { - "lint": "standard", - "pretest": "npm run lint", + "eslint": "eslint", + "lint": "npm run eslint -- index.js test.js", + "lintfix": "npm run lint -- --fix", + "posttest": "npm run lint", "test": "tap", "snap": "tap", "preversion": "npm test", @@ -42,11 +44,14 @@ ] }, "devDependencies": { - "require-inject": "^1.4.4", - "standard": "^14.3.4", - "tap": "^14.10.7" + "eslint": "^7.26.0", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^5.1.0", + "eslint-plugin-standard": "^5.0.0", + "tap": "^15.0.9" }, "dependencies": { - "@npmcli/arborist": "^2.0.0" + "@npmcli/arborist": "^2.5.0" } } diff --git a/deps/npm/package.json b/deps/npm/package.json index 70f94838882b74..f939dacadf23f9 100644 --- a/deps/npm/package.json +++ b/deps/npm/package.json @@ -1,5 +1,5 @@ { - "version": "7.12.1", + "version": "7.13.0", "name": "npm", "description": "a package manager for JavaScript", "keywords": [ @@ -42,7 +42,7 @@ "./package.json": "./package.json" }, "dependencies": { - "@npmcli/arborist": "^2.4.4", + "@npmcli/arborist": "^2.5.0", "@npmcli/ci-detect": "^1.2.0", "@npmcli/config": "^2.2.0", "@npmcli/run-script": "^1.8.5", @@ -68,7 +68,7 @@ "libnpmaccess": "^4.0.2", "libnpmdiff": "^2.0.4", "libnpmexec": "^1.1.1", - "libnpmfund": "^1.0.2", + "libnpmfund": "^1.1.0", "libnpmhook": "^6.0.2", "libnpmorg": "^2.0.2", "libnpmpack": "^2.0.1", @@ -205,7 +205,7 @@ "sudotest:nocleanup": "sudo NO_TEST_CLEANUP=1 npm run test --", "posttest": "npm run lint", "eslint": "eslint", - "lint": "npm run eslint -- test/lib test/bin \"lib/**/*.js\"", + "lint": "npm run eslint -- test/lib test/bin lib", "lintfix": "npm run lint -- --fix", "prelint": "rimraf test/npm_cache*", "resetdeps": "bash scripts/resetdeps.sh", diff --git a/deps/npm/tap-snapshots/test/lib/fund.js.test.cjs b/deps/npm/tap-snapshots/test/lib/fund.js.test.cjs index 7ad86ebeea7e93..c078beb7d98665 100644 --- a/deps/npm/tap-snapshots/test/lib/fund.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/fund.js.test.cjs @@ -92,3 +92,23 @@ test-multiple-funding-sources@1.0.0 ` + +exports[`test/lib/fund.js TAP workspaces filter funding info by a specific workspace > 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/fund.js TAP workspaces filter funding info by a specific workspace > should display only filtered workspace path 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/publish.js.test.cjs b/deps/npm/tap-snapshots/test/lib/publish.js.test.cjs index 172ed5b29f478e..0d652e289a822d 100644 --- a/deps/npm/tap-snapshots/test/lib/publish.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/publish.js.test.cjs @@ -15,6 +15,109 @@ npm publish [] Options: [--tag ] [--access ] [--dry-run] +[-w|--workspace [-w|--workspace ...]] +[-ws|--workspaces] Run "npm help publish" for more info ` + +exports[`test/lib/publish.js TAP workspaces all workspaces > should output all publishes 1`] = ` +Array [ + "+ workspace-a@1.2.3-a", + "+ workspace-b@1.2.3-n", +] +` + +exports[`test/lib/publish.js TAP workspaces all workspaces > should publish all workspaces 1`] = ` +Array [ + Object { + "_id": "workspace-a@1.2.3-a", + "name": "workspace-a", + "readme": "ERROR: No README data found!", + "repository": Object { + "type": "git", + "url": "http://repo.workspace-a/", + }, + "version": "1.2.3-a", + }, + Object { + "_id": "workspace-b@1.2.3-n", + "bugs": Object { + "url": "https://github.com/npm/workspace-b/issues", + }, + "homepage": "https://github.com/npm/workspace-b#readme", + "name": "workspace-b", + "readme": "ERROR: No README data found!", + "repository": Object { + "type": "git", + "url": "git+https://github.com/npm/workspace-b.git", + }, + "version": "1.2.3-n", + }, +] +` + +exports[`test/lib/publish.js TAP workspaces json > should output all publishes as json 1`] = ` +Array [ + String( + { + "workspace-a": { + "id": "workspace-a@1.2.3-a" + }, + "workspace-b": { + "id": "workspace-b@1.2.3-n" + } + } + ), +] +` + +exports[`test/lib/publish.js TAP workspaces json > should publish all workspaces 1`] = ` +Array [ + Object { + "_id": "workspace-a@1.2.3-a", + "name": "workspace-a", + "readme": "ERROR: No README data found!", + "repository": Object { + "type": "git", + "url": "http://repo.workspace-a/", + }, + "version": "1.2.3-a", + }, + Object { + "_id": "workspace-b@1.2.3-n", + "bugs": Object { + "url": "https://github.com/npm/workspace-b/issues", + }, + "homepage": "https://github.com/npm/workspace-b#readme", + "name": "workspace-b", + "readme": "ERROR: No README data found!", + "repository": Object { + "type": "git", + "url": "git+https://github.com/npm/workspace-b.git", + }, + "version": "1.2.3-n", + }, +] +` + +exports[`test/lib/publish.js TAP workspaces one workspace > should output one publish 1`] = ` +Array [ + "+ workspace-a@1.2.3-a", +] +` + +exports[`test/lib/publish.js TAP workspaces one workspace > should publish given workspace 1`] = ` +Array [ + Object { + "_id": "workspace-a@1.2.3-a", + "name": "workspace-a", + "readme": "ERROR: No README data found!", + "repository": Object { + "type": "git", + "url": "http://repo.workspace-a/", + }, + "version": "1.2.3-a", + }, +] +` diff --git a/deps/npm/tap-snapshots/test/lib/utils/npm-usage.js.test.cjs b/deps/npm/tap-snapshots/test/lib/utils/npm-usage.js.test.cjs index c0cb3241d93c68..3b007a83c95d0d 100644 --- a/deps/npm/tap-snapshots/test/lib/utils/npm-usage.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/utils/npm-usage.js.test.cjs @@ -422,6 +422,7 @@ All commands: Options: [--json] [--browser|--browser ] [--unicode] + [-w|--workspace [-w|--workspace ...]] [--which ] Run "npm help fund" for more info @@ -697,6 +698,8 @@ All commands: Options: [--tag ] [--access ] [--dry-run] + [-w|--workspace [-w|--workspace ...]] + [-ws|--workspaces] Run "npm help publish" for more info diff --git a/deps/npm/test/lib/fund.js b/deps/npm/test/lib/fund.js index 41754d51f35894..65778fca50bd71 100644 --- a/deps/npm/test/lib/fund.js +++ b/deps/npm/test/lib/fund.js @@ -839,3 +839,89 @@ t.test('sub dep with fund info and a parent with no funding info', t => { t.end() }) }) + +t.test('workspaces', t => { + t.test('filter funding info by a specific workspace', async t => { + npm.localPrefix = npm.prefix = t.testdir({ + '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', + }, + }), + }, + }, + }) + + await new Promise((res, rej) => { + fund.execWorkspaces([], ['a'], (err) => { + if (err) + rej(err) + + t.matchSnapshot(result, + 'should display only filtered workspace name and its deps') + + result = '' + res() + }) + }) + + await new Promise((res, rej) => { + fund.execWorkspaces([], ['./packages/a'], (err) => { + if (err) + rej(err) + + t.matchSnapshot(result, + 'should display only filtered workspace path and its deps') + + result = '' + res() + }) + }) + }) + + t.end() +}) diff --git a/deps/npm/test/lib/publish.js b/deps/npm/test/lib/publish.js index 57574b22a56eaf..7aff7b08c1971c 100644 --- a/deps/npm/test/lib/publish.js +++ b/deps/npm/test/lib/publish.js @@ -9,15 +9,12 @@ const fs = require('fs') const log = require('npmlog') log.level = 'silent' -// mock config const {definitions} = require('../../lib/utils/config') const defaults = Object.entries(definitions).reduce((defaults, [key, def]) => { defaults[key] = def.default return defaults }, {}) -const config = defaults - t.afterEach(() => log.level = 'silent') t.test('should publish with libnpmpublish, passing through flatOptions and respecting publishConfig.registry', (t) => { @@ -54,7 +51,6 @@ t.test('should publish with libnpmpublish, passing through flatOptions and respe }, }) const npm = mockNpm({ - config, flatOptions: { customValue: true, }, @@ -102,7 +98,7 @@ t.test('re-loads publishConfig.registry if added during script process', (t) => }, }, }) - const npm = mockNpm({ config }) + const npm = mockNpm() npm.config.getCredentialsByURI = (uri) => { t.same(uri, registry, 'gets credentials for expected registry') return { token: 'some.registry.token' } @@ -144,13 +140,13 @@ t.test('if loglevel=info and json, should not output package contents', (t) => { }, }) const npm = mockNpm({ - config: { ...config, json: true }, + config: { json: true }, output: () => { t.pass('output is called') }, }) npm.config.getCredentialsByURI = (uri) => { - t.same(uri, defaults.registry, 'gets credentials for expected registry') + t.same(uri, npm.config.get('registry'), 'gets credentials for expected registry') return { token: 'some.registry.token' } } const publish = new Publish(npm) @@ -190,7 +186,7 @@ t.test('if loglevel=silent and dry-run, should not output package contents or pu }, }) const npm = mockNpm({ - config: { ...config, 'dry-run': true }, + config: { 'dry-run': true }, output: () => { throw new Error('should not output in dry run mode') }, @@ -236,7 +232,7 @@ t.test('if loglevel=info and dry-run, should not publish, should log package con }, }) const npm = mockNpm({ - config: { ...config, 'dry-run': true }, + config: { 'dry-run': true }, output: () => { t.pass('output fn is called') }, @@ -270,7 +266,7 @@ t.test('throws when invalid tag', (t) => { const Publish = t.mock('../../lib/publish.js') const npm = mockNpm({ - config: { ...config, tag: '0.0.13' }, + config: { tag: '0.0.13' }, }) const publish = new Publish(npm) @@ -313,9 +309,9 @@ t.test('can publish a tarball', t => { }, }, }) - const npm = mockNpm({ config }) + const npm = mockNpm() npm.config.getCredentialsByURI = (uri) => { - t.same(uri, defaults.registry, 'gets credentials for expected registry') + t.same(uri, npm.config.get('registry'), 'gets credentials for expected registry') return { token: 'some.registry.token' } } const publish = new Publish(npm) @@ -331,9 +327,9 @@ t.test('can publish a tarball', t => { t.test('should check auth for default registry', t => { t.plan(2) const Publish = t.mock('../../lib/publish.js') - const npm = mockNpm({ config }) + const npm = mockNpm() npm.config.getCredentialsByURI = (uri) => { - t.same(uri, defaults.registry, 'gets credentials for expected registry') + t.same(uri, npm.config.get('registry'), 'gets credentials for expected registry') return {} } const publish = new Publish(npm) @@ -352,7 +348,6 @@ t.test('should check auth for configured registry', t => { const registry = 'https://some.registry' const Publish = t.mock('../../lib/publish.js') const npm = mockNpm({ - config, flatOptions: { registry }, }) npm.config.getCredentialsByURI = (uri) => { @@ -382,7 +377,6 @@ t.test('should check auth for scope specific registry', t => { const Publish = t.mock('../../lib/publish.js') const npm = mockNpm({ - config, flatOptions: { '@npm:registry': registry }, }) npm.config.getCredentialsByURI = (uri) => { @@ -419,7 +413,6 @@ t.test('should use auth for scope specific registry', t => { }, }) const npm = mockNpm({ - config, flatOptions: { '@npm:registry': registry }, }) npm.config.getCredentialsByURI = (uri) => { @@ -457,9 +450,7 @@ t.test('read registry only from publishConfig', t => { }, }, }) - const npm = mockNpm({ - config, - }) + const npm = mockNpm() npm.config.getCredentialsByURI = (uri) => { t.same(uri, registry, 'gets credentials for expected registry') return { token: 'some.registry.token' } @@ -525,3 +516,104 @@ t.test('able to publish after if encountered multiple configs', t => { t.end() }) }) + +t.test('workspaces', (t) => { + const testDir = t.testdir({ + 'package.json': JSON.stringify({ + name: 'my-cool-pkg', + version: '1.0.0', + workspaces: ['workspace-a', 'workspace-b', 'workspace-c'], + }, null, 2), + 'workspace-a': { + 'package.json': JSON.stringify({ + name: 'workspace-a', + version: '1.2.3-a', + repository: 'http://repo.workspace-a/', + }), + }, + 'workspace-b': { + 'package.json': JSON.stringify({ + name: 'workspace-b', + version: '1.2.3-n', + repository: 'https://github.com/npm/workspace-b', + }), + }, + 'workspace-c': JSON.stringify({ + 'package.json': { + name: 'workspace-n', + version: '1.2.3-n', + }, + }), + }) + + const publishes = [] + const outputs = [] + t.beforeEach(() => { + npm.config.set('json', false) + outputs.length = 0 + publishes.length = 0 + }) + const Publish = t.mock('../../lib/publish.js', { + '../../lib/utils/tar.js': { + getContents: (manifest) => ({ + id: manifest._id, + }), + logTar: () => {}, + }, + libnpmpublish: { + publish: (manifest, tarballData, opts) => { + publishes.push(manifest) + }, + }, + }) + const npm = mockNpm({ + output: (o) => { + outputs.push(o) + }, + }) + npm.localPrefix = testDir + npm.config.getCredentialsByURI = (uri) => { + return { token: 'some.registry.token' } + } + const publish = new Publish(npm) + + t.test('all workspaces', (t) => { + log.level = 'info' + publish.execWorkspaces([], [], (err) => { + t.notOk(err) + t.matchSnapshot(publishes, 'should publish all workspaces') + t.matchSnapshot(outputs, 'should output all publishes') + t.end() + }) + }) + + t.test('one workspace', t => { + log.level = 'info' + publish.execWorkspaces([], ['workspace-a'], (err) => { + t.notOk(err) + t.matchSnapshot(publishes, 'should publish given workspace') + t.matchSnapshot(outputs, 'should output one publish') + t.end() + }) + }) + + t.test('invalid workspace', t => { + publish.execWorkspaces([], ['workspace-x'], (err) => { + t.match(err, /No workspaces found/) + t.match(err, /workspace-x/) + t.end() + }) + }) + + t.test('json', t => { + log.level = 'info' + npm.config.set('json', true) + publish.execWorkspaces([], [], (err) => { + t.notOk(err) + t.matchSnapshot(publishes, 'should publish all workspaces') + t.matchSnapshot(outputs, 'should output all publishes as json') + t.end() + }) + }) + t.end() +}) diff --git a/deps/npm/test/lib/workspaces/arborist-cmd.js b/deps/npm/test/lib/workspaces/arborist-cmd.js new file mode 100644 index 00000000000000..cceeb68dbd42ae --- /dev/null +++ b/deps/npm/test/lib/workspaces/arborist-cmd.js @@ -0,0 +1,109 @@ +const { resolve } = require('path') +const t = require('tap') +const ArboristCmd = require('../../../lib/workspaces/arborist-cmd.js') + +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' }), + }, + 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', + }, + }), + }, + d: { + 'package.json': JSON.stringify({ name: 'd', version: '1.0.0' }), + }, + }, + }) + + class TestCmd extends ArboristCmd {} + + const cmd = new TestCmd() + cmd.npm = { localPrefix: path } + + // check filtering for a single workspace name + cmd.exec = function (args, cb) { + t.same(this.workspaces, ['a'], 'should set array with single ws name') + t.same(args, ['foo'], 'should get received args') + cb() + } + await new Promise(res => { + cmd.execWorkspaces(['foo'], ['a'], res) + }) + + // check filtering single workspace by path + cmd.exec = function (args, cb) { + t.same(this.workspaces, ['a'], + 'should set array with single ws name from path') + cb() + } + await new Promise(res => { + cmd.execWorkspaces([], ['./a'], res) + }) + + // check filtering single workspace by full path + cmd.exec = function (args, cb) { + t.same(this.workspaces, ['a'], + 'should set array with single ws name from full path') + cb() + } + await new Promise(res => { + cmd.execWorkspaces([], [resolve(path, './a')], res) + }) + + // filtering multiple workspaces by name + cmd.exec = function (args, cb) { + t.same(this.workspaces, ['a', 'c'], + 'should set array with multiple listed ws names') + cb() + } + await new Promise(res => { + cmd.execWorkspaces([], ['a', 'c'], res) + }) + + // filtering multiple workspaces by path names + cmd.exec = function (args, cb) { + t.same(this.workspaces, ['a', 'c'], + 'should set array with multiple ws names from paths') + cb() + } + await new Promise(res => { + cmd.execWorkspaces([], ['./a', 'group/c'], res) + }) + + // filtering multiple workspaces by parent path name + cmd.exec = function (args, cb) { + t.same(this.workspaces, ['c', 'd'], + 'should set array with multiple ws names from a parent folder name') + cb() + } + await new Promise(res => { + cmd.execWorkspaces([], ['./group'], res) + }) +})