2023-06-08 05:24:49 -07:00
|
|
|
const pkgJson = require('@npmcli/package-json')
|
2020-12-04 15:51:55 -05:00
|
|
|
const runScript = require('@npmcli/run-script')
|
2024-05-30 04:21:05 -07:00
|
|
|
const { join, relative } = require('node:path')
|
2024-04-30 23:53:22 -07:00
|
|
|
const { log, output } = require('proc-log')
|
|
|
|
const completion = require('../utils/installed-shallow.js')
|
|
|
|
const BaseCommand = require('../base-cmd.js')
|
2020-10-02 17:52:19 -04:00
|
|
|
|
2024-04-30 23:53:22 -07:00
|
|
|
// npm explore <pkg>[@<version>]
|
|
|
|
// open a subshell to the package folder.
|
2021-03-11 17:54:23 -05:00
|
|
|
class Explore extends BaseCommand {
|
2021-11-18 20:58:02 +00:00
|
|
|
static description = 'Browse an installed package'
|
|
|
|
static name = 'explore'
|
|
|
|
static usage = ['<pkg> [ -- <command>]']
|
|
|
|
static params = ['shell']
|
2022-03-03 21:38:08 +00:00
|
|
|
static ignoreImplicitWorkspace = false
|
2016-05-27 14:07:59 -07:00
|
|
|
|
2021-11-18 20:58:02 +00:00
|
|
|
// TODO
|
|
|
|
/* istanbul ignore next */
|
2023-06-08 05:24:49 -07:00
|
|
|
static async completion (opts, npm) {
|
|
|
|
return completion(npm, opts)
|
2021-03-04 17:40:28 -05:00
|
|
|
}
|
2013-05-14 14:37:59 -07:00
|
|
|
|
2021-11-04 20:42:47 +00:00
|
|
|
async exec (args) {
|
2021-11-18 20:58:02 +00:00
|
|
|
if (args.length < 1 || !args[0]) {
|
2021-11-04 20:42:47 +00:00
|
|
|
throw this.usageError()
|
2021-11-18 20:58:02 +00:00
|
|
|
}
|
2020-10-02 17:52:19 -04:00
|
|
|
|
2021-03-04 17:40:28 -05:00
|
|
|
const pkgname = args.shift()
|
|
|
|
|
|
|
|
// detect and prevent any .. shenanigans
|
|
|
|
const path = join(this.npm.dir, join('/', pkgname))
|
2021-11-18 20:58:02 +00:00
|
|
|
if (relative(path, this.npm.dir) === '') {
|
2021-11-04 20:42:47 +00:00
|
|
|
throw this.usageError()
|
2021-11-18 20:58:02 +00:00
|
|
|
}
|
2020-10-02 17:52:19 -04:00
|
|
|
|
2021-03-04 17:40:28 -05:00
|
|
|
// run as if running a script named '_explore', which we set to either
|
|
|
|
// the set of arguments, or the shell config, and let @npmcli/run-script
|
|
|
|
// handle all the escaping and PATH setup stuff.
|
|
|
|
|
2023-06-08 05:24:49 -07:00
|
|
|
const { content: pkg } = await pkgJson.normalize(path).catch(er => {
|
2021-12-02 22:04:46 +00:00
|
|
|
log.error('explore', `It doesn't look like ${pkgname} is installed.`)
|
2021-03-04 17:40:28 -05:00
|
|
|
throw er
|
2020-12-04 15:51:55 -05:00
|
|
|
})
|
2021-03-04 17:40:28 -05:00
|
|
|
|
|
|
|
const { shell } = this.npm.flatOptions
|
|
|
|
pkg.scripts = {
|
|
|
|
...(pkg.scripts || {}),
|
|
|
|
_explore: args.join(' ').trim() || shell,
|
|
|
|
}
|
|
|
|
|
2021-11-18 20:58:02 +00:00
|
|
|
if (!args.length) {
|
2024-04-30 23:53:22 -07:00
|
|
|
output.standard(`\nExploring ${path}\nType 'exit' or ^D when finished\n`)
|
2021-11-18 20:58:02 +00:00
|
|
|
}
|
2024-04-30 23:53:22 -07:00
|
|
|
|
|
|
|
return runScript({
|
|
|
|
...this.npm.flatOptions,
|
|
|
|
pkg,
|
|
|
|
path,
|
|
|
|
event: '_explore',
|
|
|
|
stdio: 'inherit',
|
|
|
|
}).catch(er => {
|
|
|
|
process.exitCode = typeof er.code === 'number' && er.code !== 0 ? er.code
|
|
|
|
: 1
|
2021-03-04 17:40:28 -05:00
|
|
|
// if it's not an exit error, or non-interactive, throw it
|
2024-04-30 23:53:22 -07:00
|
|
|
const isProcExit = er.message === 'command failed' &&
|
2021-03-04 17:40:28 -05:00
|
|
|
(typeof er.code === 'number' || /^SIG/.test(er.signal || ''))
|
2024-04-30 23:53:22 -07:00
|
|
|
if (args.length || !isProcExit) {
|
|
|
|
throw er
|
|
|
|
}
|
|
|
|
})
|
2020-10-02 17:52:19 -04:00
|
|
|
}
|
2011-11-21 09:48:45 -08:00
|
|
|
}
|
2024-04-30 23:53:22 -07:00
|
|
|
|
2021-03-04 17:40:28 -05:00
|
|
|
module.exports = Explore
|