• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict'
2
3const BB = require('bluebird')
4
5const fs = require('fs')
6const figgyPudding = require('figgy-pudding')
7const ini = require('ini')
8const path = require('path')
9const spawn = require('child_process').spawn
10
11const readFileAsync = BB.promisify(fs.readFile)
12
13const NpmConfig = figgyPudding({
14  cache: { default: '' },
15  then: {},
16  userconfig: {}
17})
18
19module.exports = NpmConfig
20
21module.exports.fromNpm = getNpmConfig
22function getNpmConfig (argv) {
23  return new BB((resolve, reject) => {
24    const npmBin = process.platform === 'win32' ? 'npm.cmd' : 'npm'
25    const child = spawn(npmBin, [
26      'config', 'ls', '--json', '-l'
27      // We add argv here to get npm to parse those options for us :D
28    ].concat(argv || []), {
29      env: process.env,
30      cwd: process.cwd(),
31      stdio: [0, 'pipe', 2]
32    })
33
34    let stdout = ''
35    if (child.stdout) {
36      child.stdout.on('data', (chunk) => {
37        stdout += chunk
38      })
39    }
40
41    child.on('error', reject)
42    child.on('close', (code) => {
43      if (code === 127) {
44        reject(new Error('`npm` command not found. Please ensure you have npm@5.4.0 or later installed.'))
45      } else {
46        try {
47          resolve(JSON.parse(stdout))
48        } catch (e) {
49          reject(new Error('`npm config ls --json` failed to output json. Please ensure you have npm@5.4.0 or later installed.'))
50        }
51      }
52    })
53  }).then(opts => {
54    return BB.all(
55      process.cwd().split(path.sep).reduce((acc, next) => {
56        acc.path = path.join(acc.path, next)
57        acc.promises.push(maybeReadIni(path.join(acc.path, '.npmrc')))
58        acc.promises.push(maybeReadIni(path.join(acc.path, 'npmrc')))
59        return acc
60      }, {
61        path: '',
62        promises: []
63      }).promises.concat(
64        opts.userconfig ? maybeReadIni(opts.userconfig) : {}
65      )
66    ).then(configs => NpmConfig(...configs, opts))
67  }).then(opts => {
68    if (opts.cache) {
69      return opts.concat({ cache: path.join(opts.cache, '_cacache') })
70    } else {
71      return opts
72    }
73  })
74}
75
76function maybeReadIni (f) {
77  return readFileAsync(f, 'utf8').catch(err => {
78    if (err.code === 'ENOENT') {
79      return ''
80    } else {
81      throw err
82    }
83  }).then(ini.parse)
84}
85