1;(function () { 2 // windows: running 'npm blah' in this folder will invoke WSH, not node. 3 /* globals WScript */ 4 if (typeof WScript !== 'undefined') { 5 WScript.echo( 6 'npm does not work when run\n' + 7 'with the Windows Scripting Host\n\n' + 8 '"cd" to a different directory,\n' + 9 'or type "npm.cmd <args>",\n' + 10 'or type "node npm <args>".' 11 ) 12 WScript.quit(1) 13 return 14 } 15 16 var unsupported = require('../lib/utils/unsupported.js') 17 unsupported.checkForBrokenNode() 18 19 var gfs = require('graceful-fs') 20 // Patch the global fs module here at the app level 21 var fs = gfs.gracefulify(require('fs')) 22 23 var EventEmitter = require('events').EventEmitter 24 var npm = module.exports = new EventEmitter() 25 var npmconf = require('./config/core.js') 26 var log = require('npmlog') 27 var inspect = require('util').inspect 28 29 // capture global logging 30 process.on('log', function (level) { 31 try { 32 return log[level].apply(log, [].slice.call(arguments, 1)) 33 } catch (ex) { 34 log.verbose('attempt to log ' + inspect(arguments) + ' crashed: ' + ex.message) 35 } 36 }) 37 38 var path = require('path') 39 var abbrev = require('abbrev') 40 var which = require('which') 41 var glob = require('glob') 42 var rimraf = require('rimraf') 43 var parseJSON = require('./utils/parse-json.js') 44 var aliases = require('./config/cmd-list').aliases 45 var cmdList = require('./config/cmd-list').cmdList 46 var plumbing = require('./config/cmd-list').plumbing 47 var output = require('./utils/output.js') 48 var startMetrics = require('./utils/metrics.js').start 49 var perf = require('./utils/perf.js') 50 51 perf.emit('time', 'npm') 52 perf.on('timing', function (name, finished) { 53 log.timing(name, 'Completed in', finished + 'ms') 54 }) 55 56 npm.config = { 57 loaded: false, 58 get: function () { 59 throw new Error('npm.load() required') 60 }, 61 set: function () { 62 throw new Error('npm.load() required') 63 } 64 } 65 66 npm.commands = {} 67 68 // TUNING 69 npm.limit = { 70 fetch: 10, 71 action: 50 72 } 73 // *** 74 75 npm.lockfileVersion = 1 76 77 npm.rollbacks = [] 78 79 try { 80 // startup, ok to do this synchronously 81 var j = parseJSON(fs.readFileSync( 82 path.join(__dirname, '../package.json')) + '') 83 npm.name = j.name 84 npm.version = j.version 85 } catch (ex) { 86 try { 87 log.info('error reading version', ex) 88 } catch (er) {} 89 npm.version = ex 90 } 91 92 var commandCache = {} 93 var aliasNames = Object.keys(aliases) 94 95 var littleGuys = [ 'isntall', 'verison' ] 96 var fullList = cmdList.concat(aliasNames).filter(function (c) { 97 return plumbing.indexOf(c) === -1 98 }) 99 var abbrevs = abbrev(fullList) 100 101 // we have our reasons 102 fullList = npm.fullList = fullList.filter(function (c) { 103 return littleGuys.indexOf(c) === -1 104 }) 105 106 var registryRefer 107 108 Object.keys(abbrevs).concat(plumbing).forEach(function addCommand (c) { 109 Object.defineProperty(npm.commands, c, { get: function () { 110 if (!loaded) { 111 throw new Error( 112 'Call npm.load(config, cb) before using this command.\n' + 113 'See the README.md or bin/npm-cli.js for example usage.' 114 ) 115 } 116 var a = npm.deref(c) 117 if (c === 'la' || c === 'll') { 118 npm.config.set('long', true) 119 } 120 121 npm.command = c 122 if (commandCache[a]) return commandCache[a] 123 124 var cmd = require(path.join(__dirname, a + '.js')) 125 126 commandCache[a] = function () { 127 var args = Array.prototype.slice.call(arguments, 0) 128 if (typeof args[args.length - 1] !== 'function') { 129 args.push(defaultCb) 130 } 131 if (args.length === 1) args.unshift([]) 132 133 // Options are prefixed by a hyphen-minus (-, \u2d). 134 // Other dash-type chars look similar but are invalid. 135 Array(args[0]).forEach(function (arg) { 136 if (/^[\u2010-\u2015\u2212\uFE58\uFE63\uFF0D]/.test(arg)) { 137 log.error('arg', 'Argument starts with non-ascii dash, this is probably invalid:', arg) 138 } 139 }) 140 141 if (!registryRefer) { 142 registryRefer = [a].concat(args[0]).map(function (arg) { 143 // exclude anything that might be a URL, path, or private module 144 // Those things will always have a slash in them somewhere 145 if (arg && arg.match && arg.match(/\/|\\/)) { 146 return '[REDACTED]' 147 } else { 148 return arg 149 } 150 }).filter(function (arg) { 151 return arg && arg.match 152 }).join(' ') 153 npm.referer = registryRefer 154 } 155 156 cmd.apply(npm, args) 157 } 158 159 Object.keys(cmd).forEach(function (k) { 160 commandCache[a][k] = cmd[k] 161 }) 162 163 return commandCache[a] 164 }, 165 enumerable: fullList.indexOf(c) !== -1, 166 configurable: true }) 167 168 // make css-case commands callable via camelCase as well 169 if (c.match(/-([a-z])/)) { 170 addCommand(c.replace(/-([a-z])/g, function (a, b) { 171 return b.toUpperCase() 172 })) 173 } 174 }) 175 176 function defaultCb (er, data) { 177 log.disableProgress() 178 if (er) console.error(er.stack || er.message) 179 else output(data) 180 } 181 182 npm.deref = function (c) { 183 if (!c) return '' 184 if (c.match(/[A-Z]/)) { 185 c = c.replace(/([A-Z])/g, function (m) { 186 return '-' + m.toLowerCase() 187 }) 188 } 189 if (plumbing.indexOf(c) !== -1) return c 190 var a = abbrevs[c] 191 while (aliases[a]) { 192 a = aliases[a] 193 } 194 return a 195 } 196 197 var loaded = false 198 var loading = false 199 var loadErr = null 200 var loadListeners = [] 201 202 function loadCb (er) { 203 loadListeners.forEach(function (cb) { 204 process.nextTick(cb.bind(npm, er, npm)) 205 }) 206 loadListeners.length = 0 207 } 208 209 npm.load = function (cli, cb_) { 210 if (!cb_ && typeof cli === 'function') { 211 cb_ = cli 212 cli = {} 213 } 214 if (!cb_) cb_ = function () {} 215 if (!cli) cli = {} 216 loadListeners.push(cb_) 217 if (loaded || loadErr) return cb(loadErr) 218 if (loading) return 219 loading = true 220 var onload = true 221 222 function cb (er) { 223 if (loadErr) return 224 loadErr = er 225 if (er) return cb_(er) 226 if (npm.config.get('force')) { 227 log.warn('using --force', 'I sure hope you know what you are doing.') 228 } 229 npm.config.loaded = true 230 loaded = true 231 loadCb(loadErr = er) 232 onload = onload && npm.config.get('onload-script') 233 if (onload) { 234 try { 235 require(onload) 236 } catch (err) { 237 log.warn('onload-script', 'failed to require onload script', onload) 238 log.warn('onload-script', err) 239 } 240 onload = false 241 } 242 } 243 244 log.pause() 245 246 load(npm, cli, cb) 247 } 248 249 function load (npm, cli, cb) { 250 which(process.argv[0], function (er, node) { 251 if (!er && node.toUpperCase() !== process.execPath.toUpperCase()) { 252 log.verbose('node symlink', node) 253 process.execPath = node 254 process.installPrefix = path.resolve(node, '..', '..') 255 } 256 257 // look up configs 258 var builtin = path.resolve(__dirname, '..', 'npmrc') 259 npmconf.load(cli, builtin, function (er, config) { 260 if (er === config) er = null 261 262 npm.config = config 263 if (er) return cb(er) 264 265 // if the 'project' config is not a filename, and we're 266 // not in global mode, then that means that it collided 267 // with either the default or effective userland config 268 if (!config.get('global') && 269 config.sources.project && 270 config.sources.project.type !== 'ini') { 271 log.verbose( 272 'config', 273 'Skipping project config: %s. (matches userconfig)', 274 config.localPrefix + '/.npmrc' 275 ) 276 } 277 278 // Include npm-version and node-version in user-agent 279 var ua = config.get('user-agent') || '' 280 ua = ua.replace(/\{node-version\}/gi, process.version) 281 ua = ua.replace(/\{npm-version\}/gi, npm.version) 282 ua = ua.replace(/\{platform\}/gi, process.platform) 283 ua = ua.replace(/\{arch\}/gi, process.arch) 284 285 // continuous integration platforms 286 const ciName = process.env.GERRIT_PROJECT ? 'gerrit' 287 : process.env.GITLAB_CI ? 'gitlab' 288 : process.env.APPVEYOR ? 'appveyor' 289 : process.env.CIRCLECI ? 'circle-ci' 290 : process.env.SEMAPHORE ? 'semaphore' 291 : process.env.DRONE ? 'drone' 292 : process.env.GITHUB_ACTION ? 'github-actions' 293 : process.env.TDDIUM ? 'tddium' 294 : process.env.JENKINS_URL ? 'jenkins' 295 : process.env['bamboo.buildKey'] ? 'bamboo' 296 : process.env.GO_PIPELINE_NAME ? 'gocd' 297 // codeship and a few others 298 : process.env.CI_NAME ? process.env.CI_NAME 299 // test travis after the others, since several CI systems mimic it 300 : process.env.TRAVIS ? 'travis-ci' 301 // aws CodeBuild/CodePipeline 302 : process.env.CODEBUILD_SRC_DIR ? 'aws-codebuild' 303 : process.env.CI === 'true' || process.env.CI === '1' ? 'custom' 304 // Google Cloud Build - it sets almost nothing 305 : process.env.BUILDER_OUTPUT ? 'builder' 306 : false 307 const ci = ciName ? `ci/${ciName}` : '' 308 ua = ua.replace(/\{ci\}/gi, ci) 309 310 config.set('user-agent', ua.trim()) 311 312 if (config.get('metrics-registry') == null) { 313 config.set('metrics-registry', config.get('registry')) 314 } 315 316 var color = config.get('color') 317 318 if (npm.config.get('timing') && npm.config.get('loglevel') === 'notice') { 319 log.level = 'timing' 320 } else { 321 log.level = config.get('loglevel') 322 } 323 log.heading = config.get('heading') || 'npm' 324 log.stream = config.get('logstream') 325 326 switch (color) { 327 case 'always': 328 npm.color = true 329 break 330 case false: 331 npm.color = false 332 break 333 default: 334 npm.color = process.stdout.isTTY && process.env['TERM'] !== 'dumb' 335 break 336 } 337 if (npm.color) { 338 log.enableColor() 339 } else { 340 log.disableColor() 341 } 342 343 if (config.get('unicode')) { 344 log.enableUnicode() 345 } else { 346 log.disableUnicode() 347 } 348 349 if (config.get('progress') && process.stderr.isTTY && process.env['TERM'] !== 'dumb') { 350 log.enableProgress() 351 } else { 352 log.disableProgress() 353 } 354 355 glob(path.resolve(npm.cache, '_logs', '*-debug.log'), function (er, files) { 356 if (er) return cb(er) 357 358 while (files.length >= npm.config.get('logs-max')) { 359 rimraf.sync(files[0]) 360 files.splice(0, 1) 361 } 362 }) 363 364 log.resume() 365 366 var umask = npm.config.get('umask') 367 npm.modes = { 368 exec: parseInt('0777', 8) & (~umask), 369 file: parseInt('0666', 8) & (~umask), 370 umask: umask 371 } 372 373 var gp = Object.getOwnPropertyDescriptor(config, 'globalPrefix') 374 Object.defineProperty(npm, 'globalPrefix', gp) 375 376 var lp = Object.getOwnPropertyDescriptor(config, 'localPrefix') 377 Object.defineProperty(npm, 'localPrefix', lp) 378 379 config.set('scope', scopeifyScope(config.get('scope'))) 380 npm.projectScope = config.get('scope') || 381 scopeifyScope(getProjectScope(npm.prefix)) 382 383 startMetrics() 384 385 return cb(null, npm) 386 }) 387 }) 388 } 389 390 Object.defineProperty(npm, 'prefix', 391 { 392 get: function () { 393 return npm.config.get('global') ? npm.globalPrefix : npm.localPrefix 394 }, 395 set: function (r) { 396 var k = npm.config.get('global') ? 'globalPrefix' : 'localPrefix' 397 npm[k] = r 398 return r 399 }, 400 enumerable: true 401 }) 402 403 Object.defineProperty(npm, 'bin', 404 { 405 get: function () { 406 if (npm.config.get('global')) return npm.globalBin 407 return path.resolve(npm.root, '.bin') 408 }, 409 enumerable: true 410 }) 411 412 Object.defineProperty(npm, 'globalBin', 413 { 414 get: function () { 415 var b = npm.globalPrefix 416 if (process.platform !== 'win32') b = path.resolve(b, 'bin') 417 return b 418 } 419 }) 420 421 Object.defineProperty(npm, 'dir', 422 { 423 get: function () { 424 if (npm.config.get('global')) return npm.globalDir 425 return path.resolve(npm.prefix, 'node_modules') 426 }, 427 enumerable: true 428 }) 429 430 Object.defineProperty(npm, 'globalDir', 431 { 432 get: function () { 433 return (process.platform !== 'win32') 434 ? path.resolve(npm.globalPrefix, 'lib', 'node_modules') 435 : path.resolve(npm.globalPrefix, 'node_modules') 436 }, 437 enumerable: true 438 }) 439 440 Object.defineProperty(npm, 'root', 441 { get: function () { return npm.dir } }) 442 443 Object.defineProperty(npm, 'cache', 444 { get: function () { return npm.config.get('cache') }, 445 set: function (r) { return npm.config.set('cache', r) }, 446 enumerable: true 447 }) 448 449 var tmpFolder 450 var rand = require('crypto').randomBytes(4).toString('hex') 451 Object.defineProperty(npm, 'tmp', 452 { 453 get: function () { 454 if (!tmpFolder) tmpFolder = 'npm-' + process.pid + '-' + rand 455 return path.resolve(npm.config.get('tmp'), tmpFolder) 456 }, 457 enumerable: true 458 }) 459 460 // the better to repl you with 461 Object.getOwnPropertyNames(npm.commands).forEach(function (n) { 462 if (npm.hasOwnProperty(n) || n === 'config') return 463 464 Object.defineProperty(npm, n, { get: function () { 465 return function () { 466 var args = Array.prototype.slice.call(arguments, 0) 467 var cb = defaultCb 468 469 if (args.length === 1 && Array.isArray(args[0])) { 470 args = args[0] 471 } 472 473 if (typeof args[args.length - 1] === 'function') { 474 cb = args.pop() 475 } 476 npm.commands[n](args, cb) 477 } 478 }, 479 enumerable: false, 480 configurable: true }) 481 }) 482 483 if (require.main === module) { 484 require('../bin/npm-cli.js') 485 } 486 487 function scopeifyScope (scope) { 488 return (!scope || scope[0] === '@') ? scope : ('@' + scope) 489 } 490 491 function getProjectScope (prefix) { 492 try { 493 var pkg = JSON.parse(fs.readFileSync(path.join(prefix, 'package.json'))) 494 if (typeof pkg.name !== 'string') return '' 495 var sep = pkg.name.indexOf('/') 496 if (sep === -1) return '' 497 return pkg.name.slice(0, sep) 498 } catch (ex) { 499 return '' 500 } 501 } 502})() 503