Skip to content

Commit 8ded0bb

Browse files
committed
feat(workspaces): add repo and docs
This adds workspaces support to `npm repo` and `npm docs`. It also updates the usage output to support the -w and -ws parameters output, and cleans up some unneccessary functions in `run-script` and `exec`.
1 parent 2b3d1f9 commit 8ded0bb

13 files changed

+454
-181
lines changed

lib/base-command.js

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class BaseCommand {
2727
usage = `${usage}${this.constructor.usage.map(u => `npm ${this.constructor.name} ${u}`).join('\n')}`
2828

2929
if (this.constructor.params)
30+
// TODO word wrap this along params boundaries
3031
usage = `${usage}\n\nOptions:\n[${this.constructor.params.map(p => ConfigDefinitions[p].usage).join('] [')}]`
3132

3233
// Mostly this just appends aliases, this could be more clear

lib/docs.js

+16
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const log = require('npmlog')
22
const pacote = require('pacote')
33
const openUrl = require('./utils/open-url.js')
44
const hostedFromMani = require('./utils/hosted-git-info-from-manifest.js')
5+
const getWorkspaces = require('./workspaces/get-workspaces.js')
56

67
const BaseCommand = require('./base-command.js')
78
class Docs extends BaseCommand {
@@ -15,6 +16,11 @@ class Docs extends BaseCommand {
1516
return 'docs'
1617
}
1718

19+
/* istanbul ignore next - see test/lib/load-all-commands.js */
20+
static get params () {
21+
return ['browser', 'workspace', 'workspaces']
22+
}
23+
1824
/* istanbul ignore next - see test/lib/load-all-commands.js */
1925
static get usage () {
2026
return ['[<pkgname> [<pkgname> ...]]']
@@ -24,13 +30,23 @@ class Docs extends BaseCommand {
2430
this.docs(args).then(() => cb()).catch(cb)
2531
}
2632

33+
execWorkspaces (args, filters, cb) {
34+
this.docsWorkspaces(args, filters).then(() => cb()).catch(cb)
35+
}
36+
2737
async docs (args) {
2838
if (!args || !args.length)
2939
args = ['.']
3040

3141
await Promise.all(args.map(pkg => this.getDocs(pkg)))
3242
}
3343

44+
async docsWorkspaces (args, filters) {
45+
const workspaces =
46+
await getWorkspaces(filters, { path: this.npm.localPrefix })
47+
return this.docs([...workspaces.values()])
48+
}
49+
3450
async getDocs (pkg) {
3551
const opts = { ...this.npm.flatOptions, fullMetadata: true }
3652
const mani = await pacote.manifest(pkg, opts)

lib/exec.js

+7-5
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ class Exec extends BaseCommand {
5353
return 'Run a command from a local or remote npm package'
5454
}
5555

56+
/* istanbul ignore next - see test/lib/load-all-commands.js */
57+
static get params () {
58+
return ['workspace', 'workspaces']
59+
}
60+
5661
/* istanbul ignore next - see test/lib/load-all-commands.js */
5762
static get name () {
5863
return 'exec'
@@ -339,12 +344,9 @@ class Exec extends BaseCommand {
339344
.slice(0, 16)
340345
}
341346

342-
async workspaces (filters) {
343-
return getWorkspaces(filters, { path: this.npm.localPrefix })
344-
}
345-
346347
async _execWorkspaces (args, filters) {
347-
const workspaces = await this.workspaces(filters)
348+
const workspaces =
349+
await getWorkspaces(filters, { path: this.npm.localPrefix })
348350
const getLocationMsg = async path => {
349351
const color = this.npm.config.get('color')
350352
const colorize = color ? chalk : nocolor

lib/repo.js

+16
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const log = require('npmlog')
22
const pacote = require('pacote')
3+
const getWorkspaces = require('./workspaces/get-workspaces.js')
34
const { URL } = require('url')
45

56
const hostedFromMani = require('./utils/hosted-git-info-from-manifest.js')
@@ -17,6 +18,11 @@ class Repo extends BaseCommand {
1718
return 'repo'
1819
}
1920

21+
/* istanbul ignore next - see test/lib/load-all-commands.js */
22+
static get params () {
23+
return ['browser', 'workspace', 'workspaces']
24+
}
25+
2026
/* istanbul ignore next - see test/lib/load-all-commands.js */
2127
static get usage () {
2228
return ['[<pkgname> [<pkgname> ...]]']
@@ -26,13 +32,23 @@ class Repo extends BaseCommand {
2632
this.repo(args).then(() => cb()).catch(cb)
2733
}
2834

35+
execWorkspaces (args, filters, cb) {
36+
this.repoWorkspaces(args, filters).then(() => cb()).catch(cb)
37+
}
38+
2939
async repo (args) {
3040
if (!args || !args.length)
3141
args = ['.']
3242

3343
await Promise.all(args.map(pkg => this.get(pkg)))
3444
}
3545

46+
async repoWorkspaces (args, filters) {
47+
const workspaces =
48+
await getWorkspaces(filters, { path: this.npm.localPrefix })
49+
return this.repo([...workspaces.values()])
50+
}
51+
3652
async get (pkg) {
3753
const opts = { ...this.npm.flatOptions, fullMetadata: true }
3854
const mani = await pacote.manifest(pkg, opts)

lib/run-script.js

+9-6
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ class RunScript extends BaseCommand {
3434
return 'Run arbitrary package scripts'
3535
}
3636

37+
/* istanbul ignore next - see test/lib/load-all-commands.js */
38+
static get params () {
39+
return ['workspace', 'workspaces']
40+
}
41+
3742
/* istanbul ignore next - see test/lib/load-all-commands.js */
3843
static get name () {
3944
return 'run-script'
@@ -182,13 +187,10 @@ class RunScript extends BaseCommand {
182187
return allScripts
183188
}
184189

185-
async workspaces (filters) {
186-
return getWorkspaces(filters, { path: this.npm.localPrefix })
187-
}
188-
189190
async runWorkspaces (args, filters) {
190191
const res = []
191-
const workspaces = await this.workspaces(filters)
192+
const workspaces =
193+
await getWorkspaces(filters, { path: this.npm.localPrefix })
192194

193195
for (const workspacePath of workspaces.values()) {
194196
const pkg = await rpj(`${workspacePath}/package.json`)
@@ -219,7 +221,8 @@ class RunScript extends BaseCommand {
219221
}
220222

221223
async listWorkspaces (args, filters) {
222-
const workspaces = await this.workspaces(filters)
224+
const workspaces =
225+
await getWorkspaces(filters, { path: this.npm.localPrefix })
223226

224227
if (log.level === 'silent')
225228
return

lib/utils/config/definition.js

+33-15
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class Definition {
4545
this.defaultDescription = describeValue(this.default)
4646
if (!this.typeDescription)
4747
this.typeDescription = describeType(this.type)
48+
// hint is only used for non-boolean values
4849
if (!this.hint)
4950
this.hint = `<${this.key}>`
5051
if (!this.usage)
@@ -79,26 +80,43 @@ ${description}
7980
}
8081
}
8182

82-
// Usage for a single param, abstracted because we have arrays of types in
83-
// config definition
84-
const paramUsage = (type, def) => {
83+
const describeUsage = (def) => {
8584
let key = `--${def.key}`
8685
if (def.short && typeof def.short === 'string')
8786
key = `-${def.short}|${key}`
88-
if (type === Boolean)
89-
return `${key}`
90-
else
91-
return `${key} ${def.hint}`
92-
}
9387

94-
const describeUsage = (def) => {
95-
if (Array.isArray(def.type)) {
96-
if (!def.type.some(d => d !== null && typeof d !== 'string'))
97-
return `--${def.key} <${def.type.filter(d => d).join('|')}>`
98-
else
99-
return def.type.filter(d => d).map((t) => paramUsage(t, def)).join('|')
88+
// Single type
89+
if (!Array.isArray(def.type))
90+
return `${key}${def.type === Boolean ? '' : ' ' + def.hint}`
91+
92+
// Multiple types
93+
let types = def.type
94+
const multiple = types.includes(Array)
95+
const bool = types.includes(Boolean)
96+
97+
// null type means optional and doesn't currently affect usage output since
98+
// all non-optional params have defaults so we render everything as optional
99+
types = types.filter(t => t !== null && t !== Array && t !== Boolean)
100+
101+
if (!types.length)
102+
return key
103+
104+
let description
105+
if (!types.some(t => typeof t !== 'string'))
106+
// Specific values, use specifics given
107+
description = `<${types.filter(d => d).join('|')}>`
108+
else {
109+
// Generic values, use hint
110+
description = def.hint
100111
}
101-
return paramUsage(def.type, def)
112+
113+
if (multiple)
114+
description = `${description} [${description} ...]`
115+
116+
if (bool)
117+
key = `${key}|${key}`
118+
119+
return `${key} ${description}`
102120
}
103121

104122
const describeType = type => {

lib/utils/config/definitions.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ define('audit', {
223223

224224
define('audit-level', {
225225
default: null,
226-
type: ['info', 'low', 'moderate', 'high', 'critical', 'none', null],
226+
type: [null, 'info', 'low', 'moderate', 'high', 'critical', 'none'],
227227
description: `
228228
The minimum level of vulnerability for \`npm audit\` to exit with
229229
a non-zero exit code.
@@ -2033,6 +2033,7 @@ define('which', {
20332033
define('workspace', {
20342034
default: [],
20352035
type: [String, Array],
2036+
hint: '<workspace-name>',
20362037
short: 'w',
20372038
description: `
20382039
Enable running a command in the context of the configured workspaces of the

tap-snapshots/test-lib-utils-config-describe-all.js-TAP.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ registry and all registries configured for scopes. See the documentation for
6464
#### \`audit-level\`
6565
6666
* Default: null
67-
* Type: "info", "low", "moderate", "high", "critical", "none", or null
67+
* Type: null, "info", "low", "moderate", "high", "critical", or "none"
6868
6969
The minimum level of vulnerability for \`npm audit\` to exit with a non-zero
7070
exit code.

tap-snapshots/test-lib-utils-npm-usage.js-TAP.test.js

+12
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,9 @@ All commands:
334334
Usage:
335335
npm docs [<pkgname> [<pkgname> ...]]
336336
337+
Options:
338+
[--browser|--browser <browser>] [-w|--workspace <workspace-name> [<workspace-name> ...]] [-ws|--workspaces]
339+
337340
alias: home
338341
339342
Run "npm help docs" for more info
@@ -366,6 +369,9 @@ All commands:
366369
npm exec -c '<cmd> [args...]'
367370
npm exec --package=foo -c '<cmd> [args...]'
368371
372+
Options:
373+
[-w|--workspace <workspace-name> [<workspace-name> ...]] [-ws|--workspaces]
374+
369375
alias: x
370376
371377
Run "npm help exec" for more info
@@ -695,6 +701,9 @@ All commands:
695701
Usage:
696702
npm repo [<pkgname> [<pkgname> ...]]
697703
704+
Options:
705+
[--browser|--browser <browser>] [-w|--workspace <workspace-name> [<workspace-name> ...]] [-ws|--workspaces]
706+
698707
Run "npm help repo" for more info
699708
700709
restart npm restart
@@ -725,6 +734,9 @@ All commands:
725734
Usage:
726735
npm run-script <command> [-- <args>]
727736
737+
Options:
738+
[-w|--workspace <workspace-name> [<workspace-name> ...]] [-ws|--workspaces]
739+
728740
aliases: run, rum, urn
729741
730742
Run "npm help run-script" for more info

0 commit comments

Comments
 (0)