@@ -11,6 +11,7 @@ const Config = require('@npmcli/config')
1111// Patch the global fs module here at the app level
1212require ( 'graceful-fs' ) . gracefulify ( require ( 'fs' ) )
1313
14+ // TODO make this only ever load once (or unload) in tests
1415const procLogListener = require ( './utils/proc-log-listener.js' )
1516
1617const proxyCmds = new Proxy ( { } , {
@@ -48,6 +49,7 @@ const _title = Symbol('_title')
4849const npm = module . exports = new class extends EventEmitter {
4950 constructor ( ) {
5051 super ( )
52+ // TODO make this only ever load once (or unload) in tests
5153 require ( './utils/perf.js' )
5254 this . started = Date . now ( )
5355 this . command = null
@@ -77,8 +79,8 @@ const npm = module.exports = new class extends EventEmitter {
7779 [ _runCmd ] ( cmd , impl , args , cb ) {
7880 if ( ! this . loaded ) {
7981 throw new Error (
80- 'Call npm.load(cb ) before using this command.\n' +
81- 'See the README.md or bin/npm- cli.js for example usage.'
82+ 'Call npm.load() before using this command.\n' +
83+ 'See lib/ cli.js for example usage.'
8284 )
8385 }
8486
@@ -96,7 +98,7 @@ const npm = module.exports = new class extends EventEmitter {
9698 args . filter ( arg => / ^ [ \u2010 - \u2015 \u2212 \uFE58 \uFE63 \uFF0D ] / . test ( arg ) )
9799 . forEach ( arg => {
98100 warnedNonDashArg = true
99- log . error ( 'arg' , 'Argument starts with non-ascii dash, this is probably invalid:' , arg )
101+ this . log . error ( 'arg' , 'Argument starts with non-ascii dash, this is probably invalid:' , arg )
100102 } )
101103 }
102104
@@ -123,33 +125,32 @@ const npm = module.exports = new class extends EventEmitter {
123125 }
124126 }
125127
126- // call with parsed CLI options and a callback when done loading
127- // XXX promisify this and stop taking a callback
128128 load ( cb ) {
129- if ( ! cb || typeof cb !== 'function' )
130- throw new TypeError ( 'must call as: npm.load(callback)' )
131-
132- this . once ( 'load' , cb )
133- if ( this . loaded || this . loadErr ) {
134- this . emit ( 'load' , this . loadErr )
135- return
129+ if ( cb && typeof cb !== 'function' )
130+ throw new TypeError ( 'callback must be a function if provided' )
131+
132+ if ( ! this . loadPromise ) {
133+ process . emit ( 'time' , 'npm:load' )
134+ this . log . pause ( )
135+ this . loadPromise = new Promise ( ( resolve , reject ) => {
136+ this [ _load ] ( ) . catch ( er => er ) . then ( ( er ) => {
137+ this . loadErr = er
138+ if ( ! er && this . config . get ( 'force' ) )
139+ this . log . warn ( 'using --force' , 'Recommended protections disabled.' )
140+
141+ process . emit ( 'timeEnd' , 'npm:load' )
142+ if ( er )
143+ return reject ( er )
144+ resolve ( )
145+ } )
146+ } )
136147 }
137- if ( this . loading )
138- return
148+ if ( ! cb )
149+ return this . loadPromise
139150
140- this . loading = true
141-
142- process . emit ( 'time' , 'npm:load' )
143- this . log . pause ( )
144- return this [ _load ] ( ) . catch ( er => er ) . then ( ( er ) => {
145- this . loading = false
146- this . loadErr = er
147- if ( ! er && this . config . get ( 'force' ) )
148- this . log . warn ( 'using --force' , 'Recommended protections disabled.' )
149-
150- process . emit ( 'timeEnd' , 'npm:load' )
151- this . emit ( 'load' , er )
152- } )
151+ // loadPromise is returned here for legacy purposes, old code was allowing
152+ // the mixing of callback and promise here.
153+ return this . loadPromise . then ( cb , cb )
153154 }
154155
155156 get loaded ( ) {
@@ -167,10 +168,10 @@ const npm = module.exports = new class extends EventEmitter {
167168
168169 async [ _load ] ( ) {
169170 process . emit ( 'time' , 'npm:load:whichnode' )
170- const node = await which ( process . argv [ 0 ] ) . catch ( er => null )
171+ const node = which . sync ( process . argv [ 0 ] )
171172 process . emit ( 'timeEnd' , 'npm:load:whichnode' )
172173 if ( node && node . toUpperCase ( ) !== process . execPath . toUpperCase ( ) ) {
173- log . verbose ( 'node symlink' , node )
174+ this . log . verbose ( 'node symlink' , node )
174175 process . execPath = node
175176 this . config . execPath = node
176177 }
@@ -198,10 +199,10 @@ const npm = module.exports = new class extends EventEmitter {
198199 process . env . COLOR = this . color ? '1' : '0'
199200
200201 process . emit ( 'time' , 'npm:load:cleanupLog' )
201- cleanUpLogFiles ( this . cache , this . config . get ( 'logs-max' ) , log . warn )
202+ cleanUpLogFiles ( this . cache , this . config . get ( 'logs-max' ) , this . log . warn )
202203 process . emit ( 'timeEnd' , 'npm:load:cleanupLog' )
203204
204- log . resume ( )
205+ this . log . resume ( )
205206
206207 process . emit ( 'time' , 'npm:load:configScope' )
207208 const configScope = this . config . get ( 'scope' )
@@ -314,9 +315,8 @@ const npm = module.exports = new class extends EventEmitter {
314315// now load everything required by the class methods
315316
316317const log = require ( 'npmlog' )
317- const { promisify } = require ( 'util' )
318318
319- const which = promisify ( require ( 'which' ) )
319+ const which = require ( 'which' )
320320
321321const deref = require ( './utils/deref-command.js' )
322322const setupLog = require ( './utils/setup-log.js' )
0 commit comments