11cb0ef41Sopenharmony_ci// npm edit <pkg>
21cb0ef41Sopenharmony_ci// open the package folder in the $EDITOR
31cb0ef41Sopenharmony_ci
41cb0ef41Sopenharmony_ciconst { resolve } = require('path')
51cb0ef41Sopenharmony_ciconst fs = require('graceful-fs')
61cb0ef41Sopenharmony_ciconst cp = require('child_process')
71cb0ef41Sopenharmony_ciconst completion = require('../utils/completion/installed-shallow.js')
81cb0ef41Sopenharmony_ciconst BaseCommand = require('../base-command.js')
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ciconst splitPackageNames = (path) => {
111cb0ef41Sopenharmony_ci  return path.split('/')
121cb0ef41Sopenharmony_ci    // combine scoped parts
131cb0ef41Sopenharmony_ci    .reduce((parts, part) => {
141cb0ef41Sopenharmony_ci      if (parts.length === 0) {
151cb0ef41Sopenharmony_ci        return [part]
161cb0ef41Sopenharmony_ci      }
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_ci      const lastPart = parts[parts.length - 1]
191cb0ef41Sopenharmony_ci      // check if previous part is the first part of a scoped package
201cb0ef41Sopenharmony_ci      if (lastPart[0] === '@' && !lastPart.includes('/')) {
211cb0ef41Sopenharmony_ci        parts[parts.length - 1] += '/' + part
221cb0ef41Sopenharmony_ci      } else {
231cb0ef41Sopenharmony_ci        parts.push(part)
241cb0ef41Sopenharmony_ci      }
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_ci      return parts
271cb0ef41Sopenharmony_ci    }, [])
281cb0ef41Sopenharmony_ci    .join('/node_modules/')
291cb0ef41Sopenharmony_ci    .replace(/(\/node_modules)+/, '/node_modules')
301cb0ef41Sopenharmony_ci}
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_ciclass Edit extends BaseCommand {
331cb0ef41Sopenharmony_ci  static description = 'Edit an installed package'
341cb0ef41Sopenharmony_ci  static name = 'edit'
351cb0ef41Sopenharmony_ci  static usage = ['<pkg>[/<subpkg>...]']
361cb0ef41Sopenharmony_ci  static params = ['editor']
371cb0ef41Sopenharmony_ci  static ignoreImplicitWorkspace = false
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ci  // TODO
401cb0ef41Sopenharmony_ci  /* istanbul ignore next */
411cb0ef41Sopenharmony_ci  static async completion (opts, npm) {
421cb0ef41Sopenharmony_ci    return completion(npm, opts)
431cb0ef41Sopenharmony_ci  }
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_ci  async exec (args) {
461cb0ef41Sopenharmony_ci    if (args.length !== 1) {
471cb0ef41Sopenharmony_ci      throw this.usageError()
481cb0ef41Sopenharmony_ci    }
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ci    const path = splitPackageNames(args[0])
511cb0ef41Sopenharmony_ci    const dir = resolve(this.npm.dir, path)
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_ci    // graceful-fs does not promisify
541cb0ef41Sopenharmony_ci    await new Promise((res, rej) => {
551cb0ef41Sopenharmony_ci      fs.lstat(dir, (err) => {
561cb0ef41Sopenharmony_ci        if (err) {
571cb0ef41Sopenharmony_ci          return rej(err)
581cb0ef41Sopenharmony_ci        }
591cb0ef41Sopenharmony_ci        const [bin, ...spawnArgs] = this.npm.config.get('editor').split(/\s+/)
601cb0ef41Sopenharmony_ci        const editor = cp.spawn(bin, [...spawnArgs, dir], { stdio: 'inherit' })
611cb0ef41Sopenharmony_ci        editor.on('exit', async (code) => {
621cb0ef41Sopenharmony_ci          if (code) {
631cb0ef41Sopenharmony_ci            return rej(new Error(`editor process exited with code: ${code}`))
641cb0ef41Sopenharmony_ci          }
651cb0ef41Sopenharmony_ci          try {
661cb0ef41Sopenharmony_ci            await this.npm.exec('rebuild', [dir])
671cb0ef41Sopenharmony_ci          } catch (execErr) {
681cb0ef41Sopenharmony_ci            rej(execErr)
691cb0ef41Sopenharmony_ci          }
701cb0ef41Sopenharmony_ci          res()
711cb0ef41Sopenharmony_ci        })
721cb0ef41Sopenharmony_ci      })
731cb0ef41Sopenharmony_ci    })
741cb0ef41Sopenharmony_ci  }
751cb0ef41Sopenharmony_ci}
761cb0ef41Sopenharmony_cimodule.exports = Edit
77