1const PackageJson = require('@npmcli/package-json') 2const BaseCommand = require('../base-command.js') 3const Queryable = require('../utils/queryable.js') 4 5class Pkg extends BaseCommand { 6 static description = 'Manages your package.json' 7 static name = 'pkg' 8 static usage = [ 9 'set <key>=<value> [<key>=<value> ...]', 10 'get [<key> [<key> ...]]', 11 'delete <key> [<key> ...]', 12 'set [<array>[<index>].<key>=<value> ...]', 13 'set [<array>[].<key>=<value> ...]', 14 'fix', 15 ] 16 17 static params = [ 18 'force', 19 'json', 20 'workspace', 21 'workspaces', 22 ] 23 24 static workspaces = true 25 static ignoreImplicitWorkspace = false 26 27 async exec (args, { prefix } = {}) { 28 if (!prefix) { 29 this.prefix = this.npm.localPrefix 30 } else { 31 this.prefix = prefix 32 } 33 34 if (this.npm.global) { 35 throw Object.assign( 36 new Error(`There's no package.json file to manage on global mode`), 37 { code: 'EPKGGLOBAL' } 38 ) 39 } 40 41 const [cmd, ..._args] = args 42 switch (cmd) { 43 case 'get': 44 return this.get(_args) 45 case 'set': 46 return this.set(_args) 47 case 'delete': 48 return this.delete(_args) 49 case 'fix': 50 return this.fix(_args) 51 default: 52 throw this.usageError() 53 } 54 } 55 56 async execWorkspaces (args) { 57 await this.setWorkspaces() 58 const result = {} 59 for (const [workspaceName, workspacePath] of this.workspaces.entries()) { 60 this.prefix = workspacePath 61 result[workspaceName] = await this.exec(args, { prefix: workspacePath }) 62 } 63 // when running in workspaces names, make sure to key by workspace 64 // name the results of each value retrieved in each ws 65 this.npm.output(JSON.stringify(result, null, 2)) 66 } 67 68 async get (args) { 69 const pkgJson = await PackageJson.load(this.prefix) 70 71 const { content } = pkgJson 72 let result = !args.length && content 73 74 if (!result) { 75 const q = new Queryable(content) 76 result = q.query(args) 77 78 // in case there's only a single result from the query 79 // just prints that one element to stdout 80 if (Object.keys(result).length === 1) { 81 result = result[args] 82 } 83 } 84 85 // only outputs if not running with workspaces config, 86 // in case you're retrieving info for workspaces the pkgWorkspaces 87 // will handle the output to make sure it get keyed by ws name 88 if (!this.npm.config.get('workspaces')) { 89 this.npm.output(JSON.stringify(result, null, 2)) 90 } 91 92 return result 93 } 94 95 async set (args) { 96 const setError = () => 97 this.usageError('npm pkg set expects a key=value pair of args.') 98 99 if (!args.length) { 100 throw setError() 101 } 102 103 const force = this.npm.config.get('force') 104 const json = this.npm.config.get('json') 105 const pkgJson = await PackageJson.load(this.prefix) 106 const q = new Queryable(pkgJson.content) 107 for (const arg of args) { 108 const [key, ...rest] = arg.split('=') 109 const value = rest.join('=') 110 if (!key || !value) { 111 throw setError() 112 } 113 114 q.set(key, json ? JSON.parse(value) : value, { force }) 115 } 116 117 pkgJson.update(q.toJSON()) 118 await pkgJson.save() 119 } 120 121 async delete (args) { 122 const setError = () => 123 this.usageError('npm pkg delete expects key args.') 124 125 if (!args.length) { 126 throw setError() 127 } 128 129 const pkgJson = await PackageJson.load(this.prefix) 130 const q = new Queryable(pkgJson.content) 131 for (const key of args) { 132 if (!key) { 133 throw setError() 134 } 135 136 q.delete(key) 137 } 138 139 pkgJson.update(q.toJSON()) 140 await pkgJson.save() 141 } 142 143 async fix () { 144 const pkgJson = await PackageJson.fix(this.prefix) 145 await pkgJson.save() 146 } 147} 148 149module.exports = Pkg 150