11cb0ef41Sopenharmony_ci// npm explore <pkg>[@<version>]
21cb0ef41Sopenharmony_ci// open a subshell to the package folder.
31cb0ef41Sopenharmony_ci
41cb0ef41Sopenharmony_ciconst pkgJson = require('@npmcli/package-json')
51cb0ef41Sopenharmony_ciconst runScript = require('@npmcli/run-script')
61cb0ef41Sopenharmony_ciconst { join, relative } = require('path')
71cb0ef41Sopenharmony_ciconst log = require('../utils/log-shim.js')
81cb0ef41Sopenharmony_ciconst completion = require('../utils/completion/installed-shallow.js')
91cb0ef41Sopenharmony_ciconst BaseCommand = require('../base-command.js')
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_ciclass Explore extends BaseCommand {
121cb0ef41Sopenharmony_ci  static description = 'Browse an installed package'
131cb0ef41Sopenharmony_ci  static name = 'explore'
141cb0ef41Sopenharmony_ci  static usage = ['<pkg> [ -- <command>]']
151cb0ef41Sopenharmony_ci  static params = ['shell']
161cb0ef41Sopenharmony_ci  static ignoreImplicitWorkspace = false
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_ci  // TODO
191cb0ef41Sopenharmony_ci  /* istanbul ignore next */
201cb0ef41Sopenharmony_ci  static async completion (opts, npm) {
211cb0ef41Sopenharmony_ci    return completion(npm, opts)
221cb0ef41Sopenharmony_ci  }
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_ci  async exec (args) {
251cb0ef41Sopenharmony_ci    if (args.length < 1 || !args[0]) {
261cb0ef41Sopenharmony_ci      throw this.usageError()
271cb0ef41Sopenharmony_ci    }
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ci    const pkgname = args.shift()
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ci    // detect and prevent any .. shenanigans
321cb0ef41Sopenharmony_ci    const path = join(this.npm.dir, join('/', pkgname))
331cb0ef41Sopenharmony_ci    if (relative(path, this.npm.dir) === '') {
341cb0ef41Sopenharmony_ci      throw this.usageError()
351cb0ef41Sopenharmony_ci    }
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ci    // run as if running a script named '_explore', which we set to either
381cb0ef41Sopenharmony_ci    // the set of arguments, or the shell config, and let @npmcli/run-script
391cb0ef41Sopenharmony_ci    // handle all the escaping and PATH setup stuff.
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_ci    const { content: pkg } = await pkgJson.normalize(path).catch(er => {
421cb0ef41Sopenharmony_ci      log.error('explore', `It doesn't look like ${pkgname} is installed.`)
431cb0ef41Sopenharmony_ci      throw er
441cb0ef41Sopenharmony_ci    })
451cb0ef41Sopenharmony_ci
461cb0ef41Sopenharmony_ci    const { shell } = this.npm.flatOptions
471cb0ef41Sopenharmony_ci    pkg.scripts = {
481cb0ef41Sopenharmony_ci      ...(pkg.scripts || {}),
491cb0ef41Sopenharmony_ci      _explore: args.join(' ').trim() || shell,
501cb0ef41Sopenharmony_ci    }
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ci    if (!args.length) {
531cb0ef41Sopenharmony_ci      this.npm.output(`\nExploring ${path}\nType 'exit' or ^D when finished\n`)
541cb0ef41Sopenharmony_ci    }
551cb0ef41Sopenharmony_ci    log.disableProgress()
561cb0ef41Sopenharmony_ci    try {
571cb0ef41Sopenharmony_ci      return await runScript({
581cb0ef41Sopenharmony_ci        ...this.npm.flatOptions,
591cb0ef41Sopenharmony_ci        pkg,
601cb0ef41Sopenharmony_ci        banner: false,
611cb0ef41Sopenharmony_ci        path,
621cb0ef41Sopenharmony_ci        event: '_explore',
631cb0ef41Sopenharmony_ci        stdio: 'inherit',
641cb0ef41Sopenharmony_ci      }).catch(er => {
651cb0ef41Sopenharmony_ci        process.exitCode = typeof er.code === 'number' && er.code !== 0 ? er.code
661cb0ef41Sopenharmony_ci          : 1
671cb0ef41Sopenharmony_ci        // if it's not an exit error, or non-interactive, throw it
681cb0ef41Sopenharmony_ci        const isProcExit = er.message === 'command failed' &&
691cb0ef41Sopenharmony_ci          (typeof er.code === 'number' || /^SIG/.test(er.signal || ''))
701cb0ef41Sopenharmony_ci        if (args.length || !isProcExit) {
711cb0ef41Sopenharmony_ci          throw er
721cb0ef41Sopenharmony_ci        }
731cb0ef41Sopenharmony_ci      })
741cb0ef41Sopenharmony_ci    } finally {
751cb0ef41Sopenharmony_ci      log.enableProgress()
761cb0ef41Sopenharmony_ci    }
771cb0ef41Sopenharmony_ci  }
781cb0ef41Sopenharmony_ci}
791cb0ef41Sopenharmony_cimodule.exports = Explore
80