1// defaults, types, and shorthands. 2 3var path = require('path') 4var url = require('url') 5var Stream = require('stream').Stream 6var semver = require('semver') 7var stableFamily = semver.parse(process.version) 8var nopt = require('nopt') 9var os = require('os') 10var osenv = require('osenv') 11var umask = require('../utils/umask') 12var hasUnicode = require('has-unicode') 13 14var log 15try { 16 log = require('npmlog') 17} catch (er) { 18 var util = require('util') 19 log = { warn: function (m) { 20 console.warn(m + ' ' + util.format.apply(util, [].slice.call(arguments, 1))) 21 } } 22} 23 24exports.Umask = Umask 25function Umask () {} 26function validateUmask (data, k, val) { 27 return umask.validate(data, k, val) 28} 29 30function validateSemver (data, k, val) { 31 if (!semver.valid(val)) return false 32 data[k] = semver.valid(val) 33} 34 35function validateStream (data, k, val) { 36 if (!(val instanceof Stream)) return false 37 data[k] = val 38} 39 40nopt.typeDefs.semver = { type: semver, validate: validateSemver } 41nopt.typeDefs.Stream = { type: Stream, validate: validateStream } 42nopt.typeDefs.Umask = { type: Umask, validate: validateUmask } 43 44nopt.invalidHandler = function (k, val, type) { 45 log.warn('invalid config', k + '=' + JSON.stringify(val)) 46 47 if (Array.isArray(type)) { 48 if (type.indexOf(url) !== -1) type = url 49 else if (type.indexOf(path) !== -1) type = path 50 } 51 52 switch (type) { 53 case Umask: 54 log.warn('invalid config', 'Must be umask, octal number in range 0000..0777') 55 break 56 case url: 57 log.warn('invalid config', "Must be a full url with 'http://'") 58 break 59 case path: 60 log.warn('invalid config', 'Must be a valid filesystem path') 61 break 62 case Number: 63 log.warn('invalid config', 'Must be a numeric value') 64 break 65 case Stream: 66 log.warn('invalid config', 'Must be an instance of the Stream class') 67 break 68 } 69} 70 71if (!stableFamily || (+stableFamily.minor % 2)) stableFamily = null 72else stableFamily = stableFamily.major + '.' + stableFamily.minor 73 74var defaults 75 76var temp = osenv.tmpdir() 77var home = osenv.home() 78 79var uidOrPid = process.getuid ? process.getuid() : process.pid 80 81if (home) process.env.HOME = home 82else home = path.resolve(temp, 'npm-' + uidOrPid) 83 84var cacheExtra = process.platform === 'win32' ? 'npm-cache' : '.npm' 85var cacheRoot = (process.platform === 'win32' && process.env.APPDATA) || home 86var cache = path.resolve(cacheRoot, cacheExtra) 87 88var globalPrefix 89Object.defineProperty(exports, 'defaults', {get: function () { 90 if (defaults) return defaults 91 92 if (process.env.PREFIX) { 93 globalPrefix = process.env.PREFIX 94 } else if (process.platform === 'win32') { 95 // c:\node\node.exe --> prefix=c:\node\ 96 globalPrefix = path.dirname(process.execPath) 97 } else { 98 // /usr/local/bin/node --> prefix=/usr/local 99 globalPrefix = path.dirname(path.dirname(process.execPath)) 100 101 // destdir only is respected on Unix 102 if (process.env.DESTDIR) { 103 globalPrefix = path.join(process.env.DESTDIR, globalPrefix) 104 } 105 } 106 107 defaults = { 108 access: null, 109 'allow-same-version': false, 110 'always-auth': false, 111 also: null, 112 audit: true, 113 'audit-level': 'low', 114 'auth-type': 'legacy', 115 116 'before': null, 117 'bin-links': true, 118 browser: null, 119 120 ca: null, 121 cafile: null, 122 123 cache: cache, 124 125 'cache-lock-stale': 60000, 126 'cache-lock-retries': 10, 127 'cache-lock-wait': 10000, 128 129 'cache-max': Infinity, 130 'cache-min': 10, 131 132 cert: null, 133 134 cidr: null, 135 136 color: process.env.NO_COLOR == null, 137 depth: Infinity, 138 description: true, 139 dev: false, 140 'dry-run': false, 141 editor: osenv.editor(), 142 'engine-strict': false, 143 force: false, 144 'format-package-lock': true, 145 146 fund: true, 147 148 'fetch-retries': 2, 149 'fetch-retry-factor': 10, 150 'fetch-retry-mintimeout': 10000, 151 'fetch-retry-maxtimeout': 60000, 152 153 git: 'git', 154 'git-tag-version': true, 155 'commit-hooks': true, 156 157 global: false, 158 globalconfig: path.resolve(globalPrefix, 'etc', 'npmrc'), 159 'global-style': false, 160 group: process.platform === 'win32' ? 0 161 : process.env.SUDO_GID || (process.getgid && process.getgid()), 162 'ham-it-up': false, 163 heading: 'npm', 164 'if-present': false, 165 'ignore-prepublish': false, 166 'ignore-scripts': false, 167 'init-module': path.resolve(home, '.npm-init.js'), 168 'init-author-name': '', 169 'init-author-email': '', 170 'init-author-url': '', 171 'init-version': '1.0.0', 172 'init-license': 'ISC', 173 json: false, 174 key: null, 175 'legacy-bundling': false, 176 link: false, 177 'local-address': undefined, 178 loglevel: 'notice', 179 logstream: process.stderr, 180 'logs-max': 10, 181 long: false, 182 maxsockets: 50, 183 message: '%s', 184 'metrics-registry': null, 185 'node-options': null, 186 'node-version': process.version, 187 'offline': false, 188 'onload-script': false, 189 only: null, 190 optional: true, 191 otp: null, 192 'package-lock': true, 193 'package-lock-only': false, 194 parseable: false, 195 'prefer-offline': false, 196 'prefer-online': false, 197 prefix: globalPrefix, 198 preid: '', 199 production: process.env.NODE_ENV === 'production', 200 'progress': !process.env.TRAVIS && !process.env.CI, 201 proxy: null, 202 'https-proxy': null, 203 'noproxy': null, 204 'user-agent': 'npm/{npm-version} ' + 205 'node/{node-version} ' + 206 '{platform} ' + 207 '{arch} ' + 208 '{ci}', 209 'read-only': false, 210 'rebuild-bundle': true, 211 registry: 'https://registry.npmjs.org/', 212 rollback: true, 213 save: true, 214 'save-bundle': false, 215 'save-dev': false, 216 'save-exact': false, 217 'save-optional': false, 218 'save-prefix': '^', 219 'save-prod': false, 220 scope: '', 221 'script-shell': null, 222 'scripts-prepend-node-path': 'warn-only', 223 searchopts: '', 224 searchexclude: null, 225 searchlimit: 20, 226 searchstaleness: 15 * 60, 227 'send-metrics': false, 228 shell: osenv.shell(), 229 shrinkwrap: true, 230 'sign-git-commit': false, 231 'sign-git-tag': false, 232 'sso-poll-frequency': 500, 233 'sso-type': 'oauth', 234 'strict-ssl': true, 235 tag: 'latest', 236 'tag-version-prefix': 'v', 237 timing: false, 238 tmp: temp, 239 unicode: hasUnicode(), 240 'unsafe-perm': process.platform === 'win32' || 241 process.platform === 'cygwin' || 242 !(process.getuid && process.setuid && 243 process.getgid && process.setgid) || 244 process.getuid() !== 0, 245 'update-notifier': true, 246 usage: false, 247 user: (process.platform === 'win32' || os.type() === 'OS400') ? 0 : 'nobody', 248 userconfig: path.resolve(home, '.npmrc'), 249 umask: process.umask ? process.umask() : umask.fromString('022'), 250 version: false, 251 versions: false, 252 viewer: process.platform === 'win32' ? 'browser' : 'man', 253 254 _exit: true 255 } 256 257 return defaults 258}}) 259 260exports.types = { 261 access: [null, 'restricted', 'public'], 262 'allow-same-version': Boolean, 263 'always-auth': Boolean, 264 also: [null, 'dev', 'development'], 265 audit: Boolean, 266 'audit-level': ['low', 'moderate', 'high', 'critical'], 267 'auth-type': ['legacy', 'sso', 'saml', 'oauth'], 268 'before': [null, Date], 269 'bin-links': Boolean, 270 browser: [null, String], 271 ca: [null, String, Array], 272 cafile: path, 273 cache: path, 274 'cache-lock-stale': Number, 275 'cache-lock-retries': Number, 276 'cache-lock-wait': Number, 277 'cache-max': Number, 278 'cache-min': Number, 279 cert: [null, String], 280 cidr: [null, String, Array], 281 color: ['always', Boolean], 282 depth: Number, 283 description: Boolean, 284 dev: Boolean, 285 'dry-run': Boolean, 286 editor: String, 287 'engine-strict': Boolean, 288 force: Boolean, 289 fund: Boolean, 290 'format-package-lock': Boolean, 291 'fetch-retries': Number, 292 'fetch-retry-factor': Number, 293 'fetch-retry-mintimeout': Number, 294 'fetch-retry-maxtimeout': Number, 295 git: String, 296 'git-tag-version': Boolean, 297 'commit-hooks': Boolean, 298 global: Boolean, 299 globalconfig: path, 300 'global-style': Boolean, 301 group: [Number, String], 302 'https-proxy': [null, url], 303 'user-agent': String, 304 'ham-it-up': Boolean, 305 'heading': String, 306 'if-present': Boolean, 307 'ignore-prepublish': Boolean, 308 'ignore-scripts': Boolean, 309 'init-module': path, 310 'init-author-name': String, 311 'init-author-email': String, 312 'init-author-url': ['', url], 313 'init-license': String, 314 'init-version': semver, 315 json: Boolean, 316 key: [null, String], 317 'legacy-bundling': Boolean, 318 link: Boolean, 319 'local-address': getLocalAddresses(), 320 loglevel: ['silent', 'error', 'warn', 'notice', 'http', 'timing', 'info', 'verbose', 'silly'], 321 logstream: Stream, 322 'logs-max': Number, 323 long: Boolean, 324 maxsockets: Number, 325 message: String, 326 'metrics-registry': [null, String], 327 'node-options': [null, String], 328 'node-version': [null, semver], 329 'noproxy': [null, String, Array], 330 offline: Boolean, 331 'onload-script': [null, String], 332 only: [null, 'dev', 'development', 'prod', 'production'], 333 optional: Boolean, 334 'package-lock': Boolean, 335 otp: [null, String], 336 'package-lock-only': Boolean, 337 parseable: Boolean, 338 'prefer-offline': Boolean, 339 'prefer-online': Boolean, 340 prefix: path, 341 preid: String, 342 production: Boolean, 343 progress: Boolean, 344 proxy: [null, false, url], // allow proxy to be disabled explicitly 345 'read-only': Boolean, 346 'rebuild-bundle': Boolean, 347 registry: [null, url], 348 rollback: Boolean, 349 save: Boolean, 350 'save-bundle': Boolean, 351 'save-dev': Boolean, 352 'save-exact': Boolean, 353 'save-optional': Boolean, 354 'save-prefix': String, 355 'save-prod': Boolean, 356 scope: String, 357 'script-shell': [null, String], 358 'scripts-prepend-node-path': [false, true, 'auto', 'warn-only'], 359 searchopts: String, 360 searchexclude: [null, String], 361 searchlimit: Number, 362 searchstaleness: Number, 363 'send-metrics': Boolean, 364 shell: String, 365 shrinkwrap: Boolean, 366 'sign-git-commit': Boolean, 367 'sign-git-tag': Boolean, 368 'sso-poll-frequency': Number, 369 'sso-type': [null, 'oauth', 'saml'], 370 'strict-ssl': Boolean, 371 tag: String, 372 timing: Boolean, 373 tmp: path, 374 unicode: Boolean, 375 'unsafe-perm': Boolean, 376 'update-notifier': Boolean, 377 usage: Boolean, 378 user: [Number, String], 379 userconfig: path, 380 umask: Umask, 381 version: Boolean, 382 'tag-version-prefix': String, 383 versions: Boolean, 384 viewer: String, 385 _exit: Boolean 386} 387 388function getLocalAddresses () { 389 var interfaces 390 // #8094: some environments require elevated permissions to enumerate 391 // interfaces, and synchronously throw EPERM when run without 392 // elevated privileges 393 try { 394 interfaces = os.networkInterfaces() 395 } catch (e) { 396 interfaces = {} 397 } 398 399 return Object.keys(interfaces).map( 400 nic => interfaces[nic].map(({address}) => address) 401 ).reduce((curr, next) => curr.concat(next), []).concat(undefined) 402} 403 404exports.shorthands = { 405 before: ['--enjoy-by'], 406 s: ['--loglevel', 'silent'], 407 d: ['--loglevel', 'info'], 408 dd: ['--loglevel', 'verbose'], 409 ddd: ['--loglevel', 'silly'], 410 noreg: ['--no-registry'], 411 N: ['--no-registry'], 412 reg: ['--registry'], 413 'no-reg': ['--no-registry'], 414 silent: ['--loglevel', 'silent'], 415 verbose: ['--loglevel', 'verbose'], 416 quiet: ['--loglevel', 'warn'], 417 q: ['--loglevel', 'warn'], 418 h: ['--usage'], 419 H: ['--usage'], 420 '?': ['--usage'], 421 help: ['--usage'], 422 v: ['--version'], 423 f: ['--force'], 424 desc: ['--description'], 425 'no-desc': ['--no-description'], 426 'local': ['--no-global'], 427 l: ['--long'], 428 m: ['--message'], 429 p: ['--parseable'], 430 porcelain: ['--parseable'], 431 readonly: ['--read-only'], 432 g: ['--global'], 433 S: ['--save'], 434 D: ['--save-dev'], 435 E: ['--save-exact'], 436 O: ['--save-optional'], 437 P: ['--save-prod'], 438 y: ['--yes'], 439 n: ['--no-yes'], 440 B: ['--save-bundle'], 441 C: ['--prefix'] 442} 443