diff options
Diffstat (limited to 'deps/npm/lib/run-script.js')
-rw-r--r-- | deps/npm/lib/run-script.js | 272 |
1 files changed, 117 insertions, 155 deletions
diff --git a/deps/npm/lib/run-script.js b/deps/npm/lib/run-script.js index 476591c051..90f11270c6 100644 --- a/deps/npm/lib/run-script.js +++ b/deps/npm/lib/run-script.js @@ -1,72 +1,92 @@ -module.exports = runScript - -var lifecycle = require('./utils/lifecycle.js') -var npm = require('./npm.js') -var path = require('path') -var readJson = require('read-package-json') -var log = require('npmlog') -var chain = require('slide').chain -var usage = require('./utils/usage') -var output = require('./utils/output.js') -var didYouMean = require('./utils/did-you-mean') -var isWindowsShell = require('./utils/is-windows-shell.js') - -runScript.usage = usage( +const run = require('@npmcli/run-script') +const npm = require('./npm.js') +const readJson = require('read-package-json-fast') +const { resolve } = require('path') +const output = require('./utils/output.js') +const log = require('npmlog') +const usageUtil = require('./utils/usage') +const didYouMean = require('./utils/did-you-mean') +const isWindowsShell = require('./utils/is-windows-shell.js') + +const usage = usageUtil( 'run-script', - 'npm run-script <command> [-- <args>...]' + 'npm run-script <command> [-- <args>]' ) -runScript.completion = function (opts, cb) { - // see if there's already a package specified. - var argv = opts.conf.argv.remain - - if (argv.length >= 4) return cb() - - if (argv.length === 3) { - // either specified a script locally, in which case, done, - // or a package, in which case, complete against its scripts - var json = path.join(npm.localPrefix, 'package.json') - return readJson(json, function (er, d) { - if (er && er.code !== 'ENOENT' && er.code !== 'ENOTDIR') return cb(er) - if (er) d = {} - var scripts = Object.keys(d.scripts || {}) - console.error('local scripts', scripts) - if (scripts.indexOf(argv[2]) !== -1) return cb() - // ok, try to find out which package it was, then - var pref = npm.config.get('global') ? npm.config.get('prefix') - : npm.localPrefix - var pkgDir = path.resolve(pref, 'node_modules', argv[2], 'package.json') - readJson(pkgDir, function (er, d) { - if (er && er.code !== 'ENOENT' && er.code !== 'ENOTDIR') return cb(er) - if (er) d = {} - var scripts = Object.keys(d.scripts || {}) - return cb(null, scripts) - }) - }) +const completion = async (opts, cb) => { + const argv = opts.conf.argv.remain + if (argv.length === 2) { + // find the script name + const json = resolve(npm.localPrefix, 'package.json') + const { scripts = {} } = await readJson(json).catch(er => ({})) + return cb(null, Object.keys(scripts)) } + // otherwise nothing to do, just let the system handle it + return cb() +} - readJson(path.join(npm.localPrefix, 'package.json'), function (er, d) { - if (er && er.code !== 'ENOENT' && er.code !== 'ENOTDIR') return cb(er) - d = d || {} - cb(null, Object.keys(d.scripts || {})) - }) +const cmd = (args, cb) => { + const fn = args.length ? runScript : list + return fn(args).then(() => cb()).catch(cb) } -function runScript (args, cb) { - if (!args.length) return list(cb) +const runScript = async (args) => { + const path = npm.localPrefix + const event = args.shift() + const { scriptShell } = npm.flatOptions + + const pkg = await readJson(`${path}/package.json`) + const { scripts = {} } = pkg + + if (event === 'restart' && !scripts.restart) { + scripts.restart = 'npm stop --if-present && npm start' + } else if (event === 'env') { + scripts.env = isWindowsShell ? 'SET' : 'env' + } + pkg.scripts = scripts + + if (!scripts[event]) { + if (npm.config.get('if-present')) { + return + } + const suggestions = didYouMean(event, Object.keys(scripts)) + throw new Error(`missing script: ${event}${ + suggestions ? `\n${suggestions}` : ''}`) + } + + // positional args only added to the main event, not pre/post + const events = [[event, args]] + if (!npm.flatOptions.ignoreScripts) { + if (scripts[`pre${event}`]) { + events.unshift([`pre${event}`, []]) + } + if (scripts[`post${event}`]) { + events.push([`post${event}`, []]) + } + } - var pkgdir = npm.localPrefix - var cmd = args.shift() + const opts = { + path, + args, + scriptShell, + stdio: log.level === 'silent' ? 'pipe' : 'inherit', + stdioString: true, + pkg + } - readJson(path.resolve(pkgdir, 'package.json'), function (er, d) { - if (er) return cb(er) - run(d, pkgdir, cmd, args, cb) - }) + for (const [event, args] of events) { + await run({ + ...opts, + event, + args + }) + } } -function list (cb) { - var json = path.join(npm.localPrefix, 'package.json') - var cmdList = [ +const list = async () => { + const path = npm.localPrefix + const { scripts, name } = await readJson(`${path}/package.json`) + const cmdList = [ 'publish', 'install', 'uninstall', @@ -75,111 +95,53 @@ function list (cb) { 'start', 'restart', 'version' - ].reduce(function (l, p) { - return l.concat(['pre' + p, p, 'post' + p]) - }, []) - return readJson(json, function (er, d) { - if (er && er.code !== 'ENOENT' && er.code !== 'ENOTDIR') return cb(er) - if (er) d = {} - var allScripts = Object.keys(d.scripts || {}) - var scripts = [] - var runScripts = [] - allScripts.forEach(function (script) { - if (cmdList.indexOf(script) !== -1) scripts.push(script) - else runScripts.push(script) - }) - - if (log.level === 'silent') { - return cb(null, allScripts) - } + ].reduce((l, p) => l.concat(['pre' + p, p, 'post' + p]), []) - if (npm.config.get('json')) { - output(JSON.stringify(d.scripts || {}, null, 2)) - return cb(null, allScripts) - } + if (!scripts) { + return [] + } - if (npm.config.get('parseable')) { - allScripts.forEach(function (script) { - output(script + ':' + d.scripts[script]) - }) - return cb(null, allScripts) - } + const allScripts = Object.keys(scripts) + if (log.level === 'silent') { + return allScripts + } - var s = '\n ' - var prefix = ' ' - if (scripts.length) { - output('Lifecycle scripts included in %s:', d.name) - } - scripts.forEach(function (script) { - output(prefix + script + s + d.scripts[script]) - }) - if (!scripts.length && runScripts.length) { - output('Scripts available in %s via `npm run-script`:', d.name) - } else if (runScripts.length) { - output('\navailable via `npm run-script`:') - } - runScripts.forEach(function (script) { - output(prefix + script + s + d.scripts[script]) - }) - return cb(null, allScripts) - }) -} + if (npm.flatOptions.json) { + output(JSON.stringify(scripts, null, 2)) + return allScripts + } -function run (pkg, wd, cmd, args, cb) { - if (!pkg.scripts) pkg.scripts = {} - - var cmds - if (cmd === 'restart' && !pkg.scripts.restart) { - cmds = [ - 'prestop', 'stop', 'poststop', - 'restart', - 'prestart', 'start', 'poststart' - ] - } else { - if (pkg.scripts[cmd] == null) { - if (cmd === 'test') { - pkg.scripts.test = 'echo \'Error: no test specified\'' - } else if (cmd === 'env') { - if (isWindowsShell) { - log.verbose('run-script using default platform env: SET (Windows)') - pkg.scripts[cmd] = 'SET' - } else { - log.verbose('run-script using default platform env: env (Unix)') - pkg.scripts[cmd] = 'env' - } - } else if (npm.config.get('if-present')) { - return cb(null) - } else { - let suggestions = didYouMean(cmd, Object.keys(pkg.scripts)) - suggestions = suggestions ? '\n' + suggestions : '' - return cb(new Error('missing script: ' + cmd + suggestions)) - } + if (npm.flatOptions.parseable) { + for (const [script, cmd] of Object.entries(scripts)) { + output(`${script}:${cmd}`) } - cmds = [cmd] + return allScripts } - if (!cmd.match(/^(pre|post)/)) { - cmds = ['pre' + cmd].concat(cmds).concat('post' + cmd) + const indent = '\n ' + const prefix = ' ' + const cmds = [] + const runScripts = [] + for (const script of allScripts) { + const list = cmdList.includes(script) ? cmds : runScripts + list.push(script) } - log.verbose('run-script', cmds) - chain(cmds.map(function (c) { - // pass cli arguments after -- to script. - if (pkg.scripts[c] && c === cmd) { - pkg.scripts[c] = pkg.scripts[c] + joinArgs(args) - } - - // when running scripts explicitly, assume that they're trusted. - return [lifecycle, pkg, c, wd, { unsafePerm: true }] - }), cb) + if (cmds.length) { + output(`Lifecycle scripts included in ${name}:`) + } + for (const script of cmds) { + output(prefix + script + indent + scripts[script]) + } + if (!cmds.length && runScripts.length) { + output(`Scripts available in ${name} via \`npm run-script\`:`) + } else if (runScripts.length) { + output('\navailable via `npm run-script`:') + } + for (const script of runScripts) { + output(prefix + script + indent + scripts[script]) + } + return allScripts } -// join arguments after '--' and pass them to script, -// handle special characters such as ', ", ' '. -function joinArgs (args) { - var joinedArgs = '' - args.forEach(function (arg) { - joinedArgs += ' "' + arg.replace(/"/g, '\\"') + '"' - }) - return joinedArgs -} +module.exports = Object.assign(cmd, { completion, usage }) |