-
Notifications
You must be signed in to change notification settings - Fork 3.4k
/
Copy pathpkg.js
129 lines (108 loc) · 3.6 KB
/
pkg.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
const { output } = require('proc-log')
const PackageJson = require('@npmcli/package-json')
const BaseCommand = require('../base-cmd.js')
const Queryable = require('../utils/queryable.js')
class Pkg extends BaseCommand {
static description = 'Manages your package.json'
static name = 'pkg'
static usage = [
'set <key>=<value> [<key>=<value> ...]',
'get [<key> [<key> ...]]',
'delete <key> [<key> ...]',
'set [<array>[<index>].<key>=<value> ...]',
'set [<array>[].<key>=<value> ...]',
'fix',
]
static params = [
'force',
'json',
'workspace',
'workspaces',
]
static workspaces = true
static ignoreImplicitWorkspace = false
async exec (args, { path = this.npm.localPrefix, workspace } = {}) {
if (this.npm.global) {
throw Object.assign(
new Error(`There's no package.json file to manage on global mode`),
{ code: 'EPKGGLOBAL' }
)
}
const [cmd, ..._args] = args
switch (cmd) {
case 'get':
return this.get(_args, { path, workspace })
case 'set':
return this.set(_args, { path, workspace }).then(p => p.save())
case 'delete':
return this.delete(_args, { path, workspace }).then(p => p.save())
case 'fix':
return PackageJson.fix(path).then(p => p.save())
default:
throw this.usageError()
}
}
async execWorkspaces (args) {
await this.setWorkspaces()
for (const [workspace, path] of this.workspaces.entries()) {
await this.exec(args, { path, workspace })
}
}
async get (args, { path, workspace }) {
this.npm.config.set('json', true)
const pkgJson = await PackageJson.load(path)
let result = pkgJson.content
if (args.length) {
result = new Queryable(result).query(args)
// in case there's only a single argument and a single result from the query
// just prints that one element to stdout.
// TODO(BREAKING_CHANGE): much like other places where we unwrap single
// item arrays this should go away. it makes the behavior unknown for users
// who don't already know the shape of the data.
if (Object.keys(result).length === 1 && args.length === 1) {
result = result[args]
}
}
// The display layer is responsible for calling JSON.stringify on the result
// TODO: https://github.com/npm/cli/issues/5508 a raw mode has been requested similar
// to jq -r. If that was added then this method should no longer set `json:true` all the time
output.buffer(workspace ? { [workspace]: result } : result)
}
async set (args, { path }) {
const setError = () =>
this.usageError('npm pkg set expects a key=value pair of args.')
if (!args.length) {
throw setError()
}
const force = this.npm.config.get('force')
const json = this.npm.config.get('json')
const pkgJson = await PackageJson.load(path)
const q = new Queryable(pkgJson.content)
for (const arg of args) {
const [key, ...rest] = arg.split('=')
const value = rest.join('=')
if (!key || !value) {
throw setError()
}
q.set(key, json ? JSON.parse(value) : value, { force })
}
return pkgJson.update(q.toJSON())
}
async delete (args, { path }) {
const setError = () =>
this.usageError('npm pkg delete expects key args.')
if (!args.length) {
throw setError()
}
const pkgJson = await PackageJson.load(path)
const q = new Queryable(pkgJson.content)
for (const key of args) {
if (!key) {
throw setError()
}
q.delete(key)
}
return pkgJson.update(q.toJSON())
}
}
module.exports = Pkg