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 // execWorkspaces will handle the output otherwise 87 if (!this.workspaces) { 88 this.npm.output(JSON.stringify(result, null, 2)) 89 } 90 91 return result 92 } 93 94 async set (args) { 95 const setError = () => 96 this.usageError('npm pkg set expects a key=value pair of args.') 97 98 if (!args.length) { 99 throw setError() 100 } 101 102 const force = this.npm.config.get('force') 103 const json = this.npm.config.get('json') 104 const pkgJson = await PackageJson.load(this.prefix) 105 const q = new Queryable(pkgJson.content) 106 for (const arg of args) { 107 const [key, ...rest] = arg.split('=') 108 const value = rest.join('=') 109 if (!key || !value) { 110 throw setError() 111 } 112 113 q.set(key, json ? JSON.parse(value) : value, { force }) 114 } 115 116 pkgJson.update(q.toJSON()) 117 await pkgJson.save() 118 } 119 120 async delete (args) { 121 const setError = () => 122 this.usageError('npm pkg delete expects key args.') 123 124 if (!args.length) { 125 throw setError() 126 } 127 128 const pkgJson = await PackageJson.load(this.prefix) 129 const q = new Queryable(pkgJson.content) 130 for (const key of args) { 131 if (!key) { 132 throw setError() 133 } 134 135 q.delete(key) 136 } 137 138 pkgJson.update(q.toJSON()) 139 await pkgJson.save() 140 } 141 142 async fix () { 143 const pkgJson = await PackageJson.fix(this.prefix) 144 await pkgJson.save() 145 } 146} 147 148module.exports = Pkg 149