diff --git a/lib/audit.js b/lib/audit.js index 9df2698589278..2e081d1865e84 100644 --- a/lib/audit.js +++ b/lib/audit.js @@ -2,9 +2,9 @@ const Arborist = require('@npmcli/arborist') const auditReport = require('npm-audit-report') const reifyFinish = require('./utils/reify-finish.js') const auditError = require('./utils/audit-error.js') -const BaseCommand = require('./base-command.js') +const ReifyCmd = require('./utils/reify-cmd.js') -class Audit extends BaseCommand { +class Audit extends ReifyCmd { /* istanbul ignore next - see test/lib/load-all-commands.js */ static get description () { return 'Run a security audit' @@ -57,7 +57,9 @@ class Audit extends BaseCommand { audit: true, path: this.npm.prefix, reporter, + workspaces: this.workspaces, } + const arb = new Arborist(opts) const fix = args[0] === 'fix' await arb.audit({ fix }) diff --git a/lib/base-command.js b/lib/base-command.js index 322fd8963a203..e1efcff5832b3 100644 --- a/lib/base-command.js +++ b/lib/base-command.js @@ -6,6 +6,7 @@ class BaseCommand { constructor (npm) { this.wrapWidth = 80 this.npm = npm + this.workspaces = null } get name () { diff --git a/lib/ci.js b/lib/ci.js index 9ae31950ef102..8d8945fe7c091 100644 --- a/lib/ci.js +++ b/lib/ci.js @@ -17,9 +17,9 @@ const removeNodeModules = async where => { await Promise.all(entries.map(f => rimraf(`${path}/${f}`, rimrafOpts))) process.emit('timeEnd', 'npm-ci:rm') } -const BaseCommand = require('./base-command.js') +const ReifyCmd = require('./utils/reify-cmd.js') -class CI extends BaseCommand { +class CI extends ReifyCmd { /* istanbul ignore next - see test/lib/load-all-commands.js */ static get description () { return 'Install a project with a clean slate' @@ -47,6 +47,7 @@ class CI extends BaseCommand { path: where, log: this.npm.log, save: false, // npm ci should never modify the lockfile or package.json + workspaces: this.workspaces, } const arb = new Arborist(opts) diff --git a/lib/dedupe.js b/lib/dedupe.js index 9649025739c60..1b1fd5dfef931 100644 --- a/lib/dedupe.js +++ b/lib/dedupe.js @@ -2,9 +2,9 @@ const Arborist = require('@npmcli/arborist') const reifyFinish = require('./utils/reify-finish.js') -const BaseCommand = require('./base-command.js') +const ReifyCmd = require('./utils/reify-cmd.js') -class Dedupe extends BaseCommand { +class Dedupe extends ReifyCmd { /* istanbul ignore next - see test/lib/load-all-commands.js */ static get description () { return 'Reduce duplication in the package tree' @@ -33,6 +33,7 @@ class Dedupe extends BaseCommand { log: this.npm.log, path: where, dryRun, + workspaces: this.workspaces, } const arb = new Arborist(opts) await arb.dedupe(opts) diff --git a/lib/install.js b/lib/install.js index a023015ed823a..1e590dd9a185d 100644 --- a/lib/install.js +++ b/lib/install.js @@ -9,8 +9,8 @@ const { resolve, join } = require('path') const Arborist = require('@npmcli/arborist') const runScript = require('@npmcli/run-script') -const BaseCommand = require('./base-command.js') -class Install extends BaseCommand { +const ReifyCmd = require('./utils/reify-cmd.js') +class Install extends ReifyCmd { /* istanbul ignore next - see test/lib/load-all-commands.js */ static get description () { return 'Install a package' @@ -132,6 +132,7 @@ class Install extends BaseCommand { auditLevel: null, path: where, add: args, + workspaces: this.workspaces, } const arb = new Arborist(opts) await arb.reify(opts) diff --git a/lib/prune.js b/lib/prune.js index 5c4a549d4d7ad..1d58c4ba98a5e 100644 --- a/lib/prune.js +++ b/lib/prune.js @@ -2,8 +2,8 @@ const Arborist = require('@npmcli/arborist') const reifyFinish = require('./utils/reify-finish.js') -const BaseCommand = require('./base-command.js') -class Prune extends BaseCommand { +const ReifyCmd = require('./utils/reify-cmd.js') +class Prune extends ReifyCmd { /* istanbul ignore next - see test/lib/load-all-commands.js */ static get description () { return 'Remove extraneous packages' @@ -34,6 +34,7 @@ class Prune extends BaseCommand { ...this.npm.flatOptions, path: where, log: this.npm.log, + workspaces: this.workspaces, } const arb = new Arborist(opts) await arb.prune(opts) diff --git a/lib/rebuild.js b/lib/rebuild.js index 5910ab3d172dc..db5a23fa5f13d 100644 --- a/lib/rebuild.js +++ b/lib/rebuild.js @@ -4,6 +4,8 @@ const npa = require('npm-package-arg') const semver = require('semver') const completion = require('./utils/completion/installed-deep.js') +// TODO: make Arborist.rebuild() understand the workspaces option +// and then extend ReifyCmd instead const BaseCommand = require('./base-command.js') class Rebuild extends BaseCommand { /* istanbul ignore next - see test/lib/load-all-commands.js */ @@ -36,6 +38,8 @@ class Rebuild extends BaseCommand { const arb = new Arborist({ ...this.npm.flatOptions, path: where, + // TODO when extending ReifyCmd + // workspaces: this.workspaces, }) if (args.length) { diff --git a/lib/uninstall.js b/lib/uninstall.js index 79a4420d89f39..7418e667708c4 100644 --- a/lib/uninstall.js +++ b/lib/uninstall.js @@ -5,8 +5,8 @@ const rpj = require('read-package-json-fast') const reifyFinish = require('./utils/reify-finish.js') const completion = require('./utils/completion/installed-shallow.js') -const BaseCommand = require('./base-command.js') -class Uninstall extends BaseCommand { +const ReifyCmd = require('./utils/reify-cmd.js') +class Uninstall extends ReifyCmd { static get description () { return 'Remove a package' } @@ -66,7 +66,7 @@ class Uninstall extends BaseCommand { path, log: this.npm.log, rm: args, - + workspaces: this.workspaces, } const arb = new Arborist(opts) await arb.reify(opts) diff --git a/lib/update.js b/lib/update.js index f8cb12d267d8a..557815a54b74d 100644 --- a/lib/update.js +++ b/lib/update.js @@ -6,8 +6,8 @@ const log = require('npmlog') const reifyFinish = require('./utils/reify-finish.js') const completion = require('./utils/completion/installed-deep.js') -const BaseCommand = require('./base-command.js') -class Update extends BaseCommand { +const ReifyCmd = require('./utils/reify-cmd.js') +class Update extends ReifyCmd { /* istanbul ignore next - see test/lib/load-all-commands.js */ static get description () { return 'Update packages' @@ -53,6 +53,7 @@ class Update extends BaseCommand { ...this.npm.flatOptions, log: this.npm.log, path: where, + workspaces: this.workspaces, }) await arb.reify({ update }) diff --git a/lib/utils/reify-cmd.js b/lib/utils/reify-cmd.js new file mode 100644 index 0000000000000..43768d4a34332 --- /dev/null +++ b/lib/utils/reify-cmd.js @@ -0,0 +1,17 @@ +// 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 ReifyCmd extends BaseCommand { + execWorkspaces (args, filters, cb) { + getWorkspaces(filters, { path: this.npm.localPrefix }) + .then(workspaces => { + this.workspaces = workspaces.map(([name]) => name) + this.exec(args, cb) + }) + } +} + +module.exports = ReifyCmd diff --git a/test/lib/audit.js b/test/lib/audit.js index bb6f06debc51f..80c34ccb9e511 100644 --- a/test/lib/audit.js +++ b/test/lib/audit.js @@ -191,3 +191,5 @@ t.test('completion', t => { t.end() }) + +t.test('workspaces') diff --git a/test/lib/ci.js b/test/lib/ci.js index b60375c289842..e7cc09fd4bfc6 100644 --- a/test/lib/ci.js +++ b/test/lib/ci.js @@ -242,3 +242,5 @@ t.test('should remove existing node_modules before installing', (t) => { throw er }) }) + +t.test('workspaces') diff --git a/test/lib/dedupe.js b/test/lib/dedupe.js index 801e3c96de3cf..14bbb404c88e4 100644 --- a/test/lib/dedupe.js +++ b/test/lib/dedupe.js @@ -62,3 +62,5 @@ t.test('should remove dupes using Arborist - no arguments', (t) => { t.end() }) }) + +t.test('workspaces') diff --git a/test/lib/install.js b/test/lib/install.js index b7929bddafdba..df22cdbe68868 100644 --- a/test/lib/install.js +++ b/test/lib/install.js @@ -218,3 +218,5 @@ t.test('completion', async t => { t.notOk(res) t.end() }) + +t.test('workspaces') diff --git a/test/lib/prune.js b/test/lib/prune.js index 87bb1370f3a19..01bfaece2a95c 100644 --- a/test/lib/prune.js +++ b/test/lib/prune.js @@ -26,3 +26,5 @@ t.test('should prune using Arborist', (t) => { t.end() }) }) + +t.test('workspaces') diff --git a/test/lib/rebuild.js b/test/lib/rebuild.js index e686b6a32ce53..4a932b5877acd 100644 --- a/test/lib/rebuild.js +++ b/test/lib/rebuild.js @@ -256,3 +256,5 @@ t.test('global prefix', t => { t.end() }) }) + +t.test('workspaces') diff --git a/test/lib/uninstall.js b/test/lib/uninstall.js index 8cf35bd428d3b..65865d24b106a 100644 --- a/test/lib/uninstall.js +++ b/test/lib/uninstall.js @@ -249,3 +249,5 @@ t.test('unknown error reading from localPrefix package.json', t => { t.end() }) }) + +t.test('workspaces') diff --git a/test/lib/update.js b/test/lib/update.js index 5396397d520cf..ad2250956c0ae 100644 --- a/test/lib/update.js +++ b/test/lib/update.js @@ -37,7 +37,12 @@ t.test('no args', t => { constructor (args) { t.same( args, - { ...npm.flatOptions, path: npm.prefix, log: noop }, + { + ...npm.flatOptions, + path: npm.prefix, + log: noop, + workspaces: null, + }, 'should call arborist contructor with expected args' ) } @@ -71,7 +76,12 @@ t.test('with args', t => { constructor (args) { t.same( args, - { ...npm.flatOptions, path: npm.prefix, log: noop }, + { + ...npm.flatOptions, + path: npm.prefix, + log: noop, + workspaces: null, + }, 'should call arborist contructor with expected args' ) } @@ -139,7 +149,7 @@ t.test('update --global', t => { const { path, ...opts } = args t.same( opts, - { ...npm.flatOptions, log: noop }, + { ...npm.flatOptions, log: noop, workspaces: undefined }, 'should call arborist contructor with expected options' ) @@ -164,3 +174,5 @@ t.test('update --global', t => { throw err }) }) + +t.test('workspaces') diff --git a/test/lib/utils/reify-cmd.js b/test/lib/utils/reify-cmd.js new file mode 100644 index 0000000000000..b8537d38099ab --- /dev/null +++ b/test/lib/utils/reify-cmd.js @@ -0,0 +1,7 @@ +const t = require('tap') +const ReifyCmd = require('../../../lib/utils/reify-cmd.js') +// Just a dummy thing here so eslint will stop yelling, but it'll still +// log a todo. +t.todo('ReifyCmd basic tests', { todo: true }, async t => { + console.log(ReifyCmd) +})