130 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			130 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
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
 |