summaryrefslogtreecommitdiff
path: root/deps/npm/lib/explore.js
diff options
context:
space:
mode:
Diffstat (limited to 'deps/npm/lib/explore.js')
-rw-r--r--deps/npm/lib/explore.js76
1 files changed, 41 insertions, 35 deletions
diff --git a/deps/npm/lib/explore.js b/deps/npm/lib/explore.js
index 96221cb497..e9b09707ec 100644
--- a/deps/npm/lib/explore.js
+++ b/deps/npm/lib/explore.js
@@ -4,59 +4,65 @@
const usageUtil = require('./utils/usage.js')
const completion = require('./utils/completion/installed-shallow.js')
const usage = usageUtil('explore', 'npm explore <pkg> [ -- <command>]')
+const rpj = require('read-package-json-fast')
const cmd = (args, cb) => explore(args).then(() => cb()).catch(cb)
const output = require('./utils/output.js')
const npm = require('./npm.js')
-const isWindows = require('./utils/is-windows.js')
-const escapeArg = require('./utils/escape-arg.js')
-const escapeExecPath = require('./utils/escape-exec-path.js')
-const log = require('npmlog')
-const spawn = require('@npmcli/promise-spawn')
-
-const { resolve } = require('path')
-const { promisify } = require('util')
-const stat = promisify(require('fs').stat)
+const runScript = require('@npmcli/run-script')
+const { join, resolve, relative } = require('path')
const explore = async args => {
if (args.length < 1 || !args[0])
throw usage
- const pkg = args.shift()
- const cwd = resolve(npm.dir, pkg)
- const opts = { cwd, stdio: 'inherit', stdioString: true }
-
- const shellArgs = []
- if (args.length) {
- if (isWindows) {
- const execCmd = escapeExecPath(args.shift())
- opts.windowsVerbatimArguments = true
- shellArgs.push('/d', '/s', '/c', execCmd, ...args.map(escapeArg))
- } else
- shellArgs.push('-c', args.map(escapeArg).join(' ').trim())
- }
+ const pkgname = args.shift()
- await stat(cwd).catch(er => {
- throw new Error(`It doesn't look like ${pkg} is installed.`)
- })
+ // detect and prevent any .. shenanigans
+ const path = join(npm.dir, join('/', pkgname))
+ if (relative(path, npm.dir) === '')
+ throw usage
- const sh = npm.flatOptions.shell
- log.disableProgress()
+ // 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.
- if (!shellArgs.length)
- output(`\nExploring ${cwd}\nType 'exit' or ^D when finished\n`)
+ const pkg = await rpj(resolve(path, 'package.json')).catch(er => {
+ npm.log.error('explore', `It doesn't look like ${pkgname} is installed.`)
+ throw er
+ })
- log.silly('explore', { sh, shellArgs, opts })
+ const { shell } = npm.flatOptions
+ pkg.scripts = {
+ ...(pkg.scripts || {}),
+ _explore: args.join(' ').trim() || shell,
+ }
- // only noisily fail if non-interactive, but still keep exit code intact
- const proc = spawn(sh, shellArgs, opts)
+ if (!args.length)
+ output(`\nExploring ${path}\nType 'exit' or ^D when finished\n`)
+ npm.log.disableProgress()
try {
- const res = await (shellArgs.length ? proc : proc.catch(er => er))
- process.exitCode = res.code
+ return await runScript({
+ ...npm.flatOptions,
+ pkg,
+ banner: false,
+ path,
+ stdioString: true,
+ event: '_explore',
+ stdio: 'inherit',
+ }).catch(er => {
+ process.exitCode = typeof er.code === 'number' && er.code !== 0 ? er.code
+ : 1
+ // if it's not an exit error, or non-interactive, throw it
+ const isProcExit = er.message === 'command failed' &&
+ (typeof er.code === 'number' || /^SIG/.test(er.signal || ''))
+ if (args.length || !isProcExit)
+ throw er
+ })
} finally {
- log.enableProgress()
+ npm.log.enableProgress()
}
}