1- module . exports = runScript
2-
3- var lifecycle = require ( './utils/lifecycle.js' )
4- var npm = require ( './npm.js' )
5- var path = require ( 'path' )
6- var readJson = require ( 'read-package-json' )
7- var log = require ( 'npmlog' )
8- var chain = require ( 'slide' ) . chain
9- var usage = require ( './utils/usage' )
10- var output = require ( './utils/output.js' )
11- var didYouMean = require ( './utils/did-you-mean' )
12- var isWindowsShell = require ( './utils/is-windows-shell.js' )
13-
14- runScript . usage = usage (
1+ module . exports = runScriptCmd
2+
3+ const run = require ( '@npmcli/run-script' )
4+ const npm = require ( './npm.js' )
5+ const readJson = require ( 'read-package-json-fast' )
6+ const { resolve, join } = require ( 'path' )
7+ const output = require ( './utils/output.js' )
8+ const log = require ( 'npmlog' )
9+ const usage = require ( './utils/usage' )
10+ const didYouMean = require ( './utils/did-you-mean' )
11+ const isWindowsShell = require ( './utils/is-windows-shell.js' )
12+
13+ runScriptCmd . usage = usage (
1514 'run-script' ,
1615 'npm run-script <command> [-- <args>...]'
1716)
1817
19- runScript . completion = function ( opts , cb ) {
18+ runScriptCmd . completion = function ( opts , cb ) {
2019 // see if there's already a package specified.
2120 var argv = opts . conf . argv . remain
2221
@@ -25,17 +24,16 @@ runScript.completion = function (opts, cb) {
2524 if ( argv . length === 3 ) {
2625 // either specified a script locally, in which case, done,
2726 // or a package, in which case, complete against its scripts
28- var json = path . join ( npm . localPrefix , 'package.json' )
27+ var json = join ( npm . localPrefix , 'package.json' )
2928 return readJson ( json , function ( er , d ) {
3029 if ( er && er . code !== 'ENOENT' && er . code !== 'ENOTDIR' ) return cb ( er )
3130 if ( er ) d = { }
3231 var scripts = Object . keys ( d . scripts || { } )
33- console . error ( 'local scripts' , scripts )
3432 if ( scripts . indexOf ( argv [ 2 ] ) !== - 1 ) return cb ( )
3533 // ok, try to find out which package it was, then
3634 var pref = npm . config . get ( 'global' ) ? npm . config . get ( 'prefix' )
3735 : npm . localPrefix
38- var pkgDir = path . resolve ( pref , 'node_modules' , argv [ 2 ] , 'package.json' )
36+ var pkgDir = resolve ( pref , 'node_modules' , argv [ 2 ] , 'package.json' )
3937 readJson ( pkgDir , function ( er , d ) {
4038 if ( er && er . code !== 'ENOENT' && er . code !== 'ENOTDIR' ) return cb ( er )
4139 if ( er ) d = { }
@@ -45,28 +43,71 @@ runScript.completion = function (opts, cb) {
4543 } )
4644 }
4745
48- readJson ( path . join ( npm . localPrefix , 'package.json' ) , function ( er , d ) {
46+ readJson ( join ( npm . localPrefix , 'package.json' ) , function ( er , d ) {
4947 if ( er && er . code !== 'ENOENT' && er . code !== 'ENOTDIR' ) return cb ( er )
5048 d = d || { }
5149 cb ( null , Object . keys ( d . scripts || { } ) )
5250 } )
5351}
5452
55- function runScript ( args , cb ) {
56- if ( ! args . length ) return list ( cb )
53+ function runScriptCmd ( args , cb ) {
54+ const fn = args . length ? runScript : list
55+ fn ( args ) . then ( ( ) => cb ( ) ) . catch ( cb )
56+ }
5757
58- var pkgdir = npm . localPrefix
59- var cmd = args . shift ( )
58+ const runScript = async ( args ) => {
59+ const path = npm . localPrefix
60+ const event = args . shift ( )
61+ const { scriptShell } = npm . flatOptions
6062
61- readJson ( path . resolve ( pkgdir , 'package.json' ) , function ( er , d ) {
62- if ( er ) return cb ( er )
63- run ( d , pkgdir , cmd , args , cb )
64- } )
63+ const pkg = await readJson ( `${ path } /package.json` )
64+ const { _id, scripts = { } } = pkg
65+
66+ if ( event === 'restart' && ! scripts . restart ) {
67+ scripts . restart = 'npm stop && npm start'
68+ } else if ( event === 'env' ) {
69+ scripts . env = isWindowsShell ? 'SET' : 'env'
70+ }
71+
72+ if ( ! scripts [ event ] ) {
73+ if ( npm . config . get ( 'if-present' ) ) {
74+ return
75+ }
76+ const suggestions = didYouMean ( event , Object . keys ( scripts ) )
77+ throw new Error ( `missing script: ${ event } ${
78+ suggestions ? `\n${ suggestions } ` : '' } `)
79+ }
80+
81+ // positional args only added to the main event, not pre/post
82+ const events = [ [ event , args ] ]
83+ if ( scripts [ `pre${ event } ` ] ) {
84+ events . unshift ( [ `pre${ event } ` , [ ] ] )
85+ }
86+ if ( scripts [ `post${ event } ` ] ) {
87+ events . push ( [ `post${ event } ` , [ ] ] )
88+ }
89+
90+ const opts = {
91+ path,
92+ args,
93+ scriptShell,
94+ stdio : log . level === 'silent' ? 'pipe' : 'inherit' ,
95+ pkg
96+ }
97+
98+ for ( const [ event , args ] of events ) {
99+ await run ( {
100+ ...opts ,
101+ event,
102+ args
103+ } )
104+ }
65105}
66106
67- function list ( cb ) {
68- var json = path . join ( npm . localPrefix , 'package.json' )
69- var cmdList = [
107+ const list = async ( ) => {
108+ const path = npm . localPrefix
109+ const { scripts, name } = await readJson ( `${ path } /package.json` )
110+ const cmdList = [
70111 'publish' ,
71112 'install' ,
72113 'uninstall' ,
@@ -75,111 +116,51 @@ function list (cb) {
75116 'start' ,
76117 'restart' ,
77118 'version'
78- ] . reduce ( function ( l , p ) {
79- return l . concat ( [ 'pre' + p , p , 'post' + p ] )
80- } , [ ] )
81- return readJson ( json , function ( er , d ) {
82- if ( er && er . code !== 'ENOENT' && er . code !== 'ENOTDIR' ) return cb ( er )
83- if ( er ) d = { }
84- var allScripts = Object . keys ( d . scripts || { } )
85- var scripts = [ ]
86- var runScripts = [ ]
87- allScripts . forEach ( function ( script ) {
88- if ( cmdList . indexOf ( script ) !== - 1 ) scripts . push ( script )
89- else runScripts . push ( script )
90- } )
91-
92- if ( log . level === 'silent' ) {
93- return cb ( null , allScripts )
94- }
95-
96- if ( npm . config . get ( 'json' ) ) {
97- output ( JSON . stringify ( d . scripts || { } , null , 2 ) )
98- return cb ( null , allScripts )
99- }
119+ ] . reduce ( ( l , p ) => l . concat ( [ 'pre' + p , p , 'post' + p ] ) )
100120
101- if ( npm . config . get ( 'parseable' ) ) {
102- allScripts . forEach ( function ( script ) {
103- output ( script + ':' + d . scripts [ script ] )
104- } )
105- return cb ( null , allScripts )
106- }
107-
108- var s = '\n '
109- var prefix = ' '
110- if ( scripts . length ) {
111- output ( 'Lifecycle scripts included in %s:' , d . name )
112- }
113- scripts . forEach ( function ( script ) {
114- output ( prefix + script + s + d . scripts [ script ] )
115- } )
116- if ( ! scripts . length && runScripts . length ) {
117- output ( 'Scripts available in %s via `npm run-script`:' , d . name )
118- } else if ( runScripts . length ) {
119- output ( '\navailable via `npm run-script`:' )
120- }
121- runScripts . forEach ( function ( script ) {
122- output ( prefix + script + s + d . scripts [ script ] )
123- } )
124- return cb ( null , allScripts )
125- } )
126- }
121+ if ( ! scripts ) {
122+ return [ ]
123+ }
127124
128- function run ( pkg , wd , cmd , args , cb ) {
129- if ( ! pkg . scripts ) pkg . scripts = { }
130-
131- var cmds
132- if ( cmd === 'restart' && ! pkg . scripts . restart ) {
133- cmds = [
134- 'prestop' , 'stop' , 'poststop' ,
135- 'restart' ,
136- 'prestart' , 'start' , 'poststart'
137- ]
138- } else {
139- if ( pkg . scripts [ cmd ] == null ) {
140- if ( cmd === 'test' ) {
141- pkg . scripts . test = 'echo \'Error: no test specified\''
142- } else if ( cmd === 'env' ) {
143- if ( isWindowsShell ) {
144- log . verbose ( 'run-script using default platform env: SET (Windows)' )
145- pkg . scripts [ cmd ] = 'SET'
146- } else {
147- log . verbose ( 'run-script using default platform env: env (Unix)' )
148- pkg . scripts [ cmd ] = 'env'
149- }
150- } else if ( npm . config . get ( 'if-present' ) ) {
151- return cb ( null )
152- } else {
153- let suggestions = didYouMean ( cmd , Object . keys ( pkg . scripts ) )
154- suggestions = suggestions ? '\n' + suggestions : ''
155- return cb ( new Error ( 'missing script: ' + cmd + suggestions ) )
156- }
157- }
158- cmds = [ cmd ]
125+ const allScripts = scripts ? Object . keys ( scripts ) : [ ]
126+ if ( log . level === 'silent' ) {
127+ return allScripts
159128 }
160129
161- if ( ! cmd . match ( / ^ ( p r e | p o s t ) / ) ) {
162- cmds = [ 'pre' + cmd ] . concat ( cmds ) . concat ( 'post' + cmd )
130+ if ( npm . flatOptions . json ) {
131+ output ( JSON . stringify ( scripts , null , 2 ) )
132+ return allScripts
163133 }
164134
165- log . verbose ( 'run-script' , cmds )
166- chain ( cmds . map ( function ( c ) {
167- // pass cli arguments after -- to script.
168- if ( pkg . scripts [ c ] && c === cmd ) {
169- pkg . scripts [ c ] = pkg . scripts [ c ] + joinArgs ( args )
135+ if ( npm . flatOptions . parseable ) {
136+ for ( const [ script , cmd ] of Object . entries ( scripts ) ) {
137+ output ( `${ script } :${ cmd } ` )
170138 }
139+ return allScripts
140+ }
171141
172- // when running scripts explicitly, assume that they're trusted.
173- return [ lifecycle , pkg , c , wd , { unsafePerm : true } ]
174- } ) , cb )
175- }
142+ const indent = '\n '
143+ const prefix = ' '
144+ const cmds = [ ]
145+ const runScripts = [ ]
146+ for ( const script of allScripts ) {
147+ const list = cmdList . includes ( script ) ? cmds : runScripts
148+ list . push ( script )
149+ }
176150
177- // join arguments after '--' and pass them to script,
178- // handle special characters such as ', ", ' '.
179- function joinArgs ( args ) {
180- var joinedArgs = ''
181- args . forEach ( function ( arg ) {
182- joinedArgs += ' "' + arg . replace ( / " / g, '\\"' ) + '"'
183- } )
184- return joinedArgs
151+ if ( cmds . length ) {
152+ output ( `Lifecycle scripts included in ${ name } :` )
153+ }
154+ for ( const script of cmds ) {
155+ output ( prefix + script + indent + scripts [ script ] )
156+ }
157+ if ( ! cmds . length && runScripts . length ) {
158+ output ( `Scripts available in ${ name } via \`npm run-script\`:` )
159+ } else if ( runScripts . length ) {
160+ output ( `\navailable via \`npm run-script\`:` )
161+ }
162+ for ( const script of runScripts ) {
163+ output ( prefix + script + indent + scripts [ script ] )
164+ }
165+ return allScripts
185166}
0 commit comments