module.exports = runScript var lifecycle = require("./utils/lifecycle.js") , npm = require("./npm.js") , path = require("path") , readJson = require("read-package-json") , log = require("npmlog") , chain = require("slide").chain runScript.usage = "npm run-script [-- ]" runScript.completion = function (opts, cb) { // see if there's already a package specified. var argv = opts.conf.argv.remain , installedShallow = require("./utils/completion/installed-shallow.js") 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) }) }) } // complete against the installed-shallow, and the pwd's scripts. // but only packages that have scripts var installed , scripts installedShallow(opts, function (d) { return d.scripts }, function (er, inst) { installed = inst next() }) if (npm.config.get("global")) { scripts = [] next() } else readJson(path.join(npm.localPrefix, "package.json"), function (er, d) { if (er && er.code !== "ENOENT" && er.code !== "ENOTDIR") return cb(er) d = d || {} scripts = Object.keys(d.scripts || {}) next() }) function next () { if (!installed || !scripts) return cb(null, scripts.concat(installed)) } } function runScript (args, cb) { if (!args.length) return list(cb) var pkgdir = npm.localPrefix , cmd = args.shift() readJson(path.resolve(pkgdir, "package.json"), function (er, d) { if (er) return cb(er) run(d, pkgdir, cmd, args, cb) }) } function list(cb) { var json = path.join(npm.localPrefix, "package.json") var cmdList = [ "publish", "install", "uninstall" , "test", "stop", "start", "restart" ].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) } if (npm.config.get("json")) { console.log(JSON.stringify(d.scripts || {}, null, 2)) return cb(null, allScripts) } if (npm.config.get("parseable")) { allScripts.forEach(function(script) { console.log(script + ":" + d.scripts[script]) }) return cb(null, allScripts) } var s = "\n " var prefix = " " if (scripts.length) { console.log("Lifecycle scripts included in %s:", d.name) } scripts.forEach(function(script) { console.log(prefix + script + s + d.scripts[script]) }) if (!scripts.length && runScripts.length) { console.log("Scripts available in %s via `npm run-script`:", d.name) } else if (runScripts.length) { console.log("\navailable via `npm run-script`:") } runScripts.forEach(function(script) { console.log(prefix + script + s + d.scripts[script]) }) return cb(null, 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]) { if (cmd === "test") { pkg.scripts.test = "echo \"Error: no test specified\"" } else if (cmd === "env") { if (process.platform === "win32") { 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 { return cb(new Error("missing script: " + cmd)) } } cmds = [cmd] } if (!cmd.match(/^(pre|post)/)) { cmds = ["pre"+cmd].concat(cmds).concat("post"+cmd) } 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, true] }), cb) } // join arguments after '--' and pass them to script, // handle special characters such as ', ", ' '. function joinArgs (args) { var joinedArgs = "" args.forEach(function(arg) { if (arg.match(/[ '"]/)) arg = '"' + arg.replace(/"/g, '\\"') + '"' joinedArgs += " " + arg }) return joinedArgs }