UNPKG

5.29 kBJavaScriptView Raw
1module.exports = runScript
2
3var lifecycle = require('./utils/lifecycle.js')
4var npm = require('./npm.js')
5var path = require('path')
6var readJson = require('read-package-json')
7var log = require('npmlog')
8var chain = require('slide').chain
9var usage = require('./utils/usage')
10var output = require('./utils/output.js')
11
12runScript.usage = usage(
13 'run-script',
14 'npm run-script <command> [-- <args>...]'
15)
16
17runScript.completion = function (opts, cb) {
18 // see if there's already a package specified.
19 var argv = opts.conf.argv.remain
20
21 if (argv.length >= 4) return cb()
22
23 if (argv.length === 3) {
24 // either specified a script locally, in which case, done,
25 // or a package, in which case, complete against its scripts
26 var json = path.join(npm.localPrefix, 'package.json')
27 return readJson(json, function (er, d) {
28 if (er && er.code !== 'ENOENT' && er.code !== 'ENOTDIR') return cb(er)
29 if (er) d = {}
30 var scripts = Object.keys(d.scripts || {})
31 console.error('local scripts', scripts)
32 if (scripts.indexOf(argv[2]) !== -1) return cb()
33 // ok, try to find out which package it was, then
34 var pref = npm.config.get('global') ? npm.config.get('prefix')
35 : npm.localPrefix
36 var pkgDir = path.resolve(pref, 'node_modules', argv[2], 'package.json')
37 readJson(pkgDir, function (er, d) {
38 if (er && er.code !== 'ENOENT' && er.code !== 'ENOTDIR') return cb(er)
39 if (er) d = {}
40 var scripts = Object.keys(d.scripts || {})
41 return cb(null, scripts)
42 })
43 })
44 }
45
46 readJson(path.join(npm.localPrefix, 'package.json'), function (er, d) {
47 if (er && er.code !== 'ENOENT' && er.code !== 'ENOTDIR') return cb(er)
48 d = d || {}
49 cb(null, Object.keys(d.scripts || {}))
50 })
51}
52
53function runScript (args, cb) {
54 if (!args.length) return list(cb)
55
56 var pkgdir = npm.localPrefix
57 var cmd = args.shift()
58
59 readJson(path.resolve(pkgdir, 'package.json'), function (er, d) {
60 if (er) return cb(er)
61 run(d, pkgdir, cmd, args, cb)
62 })
63}
64
65function list (cb) {
66 var json = path.join(npm.localPrefix, 'package.json')
67 var cmdList = [
68 'publish',
69 'install',
70 'uninstall',
71 'test',
72 'stop',
73 'start',
74 'restart',
75 'version'
76 ].reduce(function (l, p) {
77 return l.concat(['pre' + p, p, 'post' + p])
78 }, [])
79 return readJson(json, function (er, d) {
80 if (er && er.code !== 'ENOENT' && er.code !== 'ENOTDIR') return cb(er)
81 if (er) d = {}
82 var allScripts = Object.keys(d.scripts || {})
83 var scripts = []
84 var runScripts = []
85 allScripts.forEach(function (script) {
86 if (cmdList.indexOf(script) !== -1) scripts.push(script)
87 else runScripts.push(script)
88 })
89
90 if (log.level === 'silent') {
91 return cb(null, allScripts)
92 }
93
94 if (npm.config.get('json')) {
95 output(JSON.stringify(d.scripts || {}, null, 2))
96 return cb(null, allScripts)
97 }
98
99 if (npm.config.get('parseable')) {
100 allScripts.forEach(function (script) {
101 output(script + ':' + d.scripts[script])
102 })
103 return cb(null, allScripts)
104 }
105
106 var s = '\n '
107 var prefix = ' '
108 if (scripts.length) {
109 output('Lifecycle scripts included in %s:', d.name)
110 }
111 scripts.forEach(function (script) {
112 output(prefix + script + s + d.scripts[script])
113 })
114 if (!scripts.length && runScripts.length) {
115 output('Scripts available in %s via `npm run-script`:', d.name)
116 } else if (runScripts.length) {
117 output('\navailable via `npm run-script`:')
118 }
119 runScripts.forEach(function (script) {
120 output(prefix + script + s + d.scripts[script])
121 })
122 return cb(null, allScripts)
123 })
124}
125
126function run (pkg, wd, cmd, args, cb) {
127 if (!pkg.scripts) pkg.scripts = {}
128
129 var cmds
130 if (cmd === 'restart' && !pkg.scripts.restart) {
131 cmds = [
132 'prestop', 'stop', 'poststop',
133 'restart',
134 'prestart', 'start', 'poststart'
135 ]
136 } else {
137 if (!pkg.scripts[cmd]) {
138 if (cmd === 'test') {
139 pkg.scripts.test = 'echo \'Error: no test specified\''
140 } else if (cmd === 'env') {
141 if (process.platform === 'win32') {
142 log.verbose('run-script using default platform env: SET (Windows)')
143 pkg.scripts[cmd] = 'SET'
144 } else {
145 log.verbose('run-script using default platform env: env (Unix)')
146 pkg.scripts[cmd] = 'env'
147 }
148 } else if (npm.config.get('if-present')) {
149 return cb(null)
150 } else {
151 return cb(new Error('missing script: ' + cmd))
152 }
153 }
154 cmds = [cmd]
155 }
156
157 if (!cmd.match(/^(pre|post)/)) {
158 cmds = ['pre' + cmd].concat(cmds).concat('post' + cmd)
159 }
160
161 log.verbose('run-script', cmds)
162 chain(cmds.map(function (c) {
163 // pass cli arguments after -- to script.
164 if (pkg.scripts[c] && c === cmd) {
165 pkg.scripts[c] = pkg.scripts[c] + joinArgs(args)
166 }
167
168 // when running scripts explicitly, assume that they're trusted.
169 return [lifecycle, pkg, c, wd, true]
170 }), cb)
171}
172
173// join arguments after '--' and pass them to script,
174// handle special characters such as ', ", ' '.
175function joinArgs (args) {
176 var joinedArgs = ''
177 args.forEach(function (arg) {
178 joinedArgs += ' "' + arg.replace(/"/g, '\\"') + '"'
179 })
180 return joinedArgs
181}