| 'use strict'; |
| const fs = require('fs'); |
| const path = require('path'); |
| const types = require('./types'); |
| |
| // https://github.com/npm/npm/blob/latest/lib/config/core.js#L409-L423 |
| const envReplace = str => { |
| if (typeof str !== 'string' || !str) { |
| return str; |
| } |
| |
| // Replace any ${ENV} values with the appropriate environment |
| const regex = /(\\*)\$\{([^}]+)\}/g; |
| |
| return str.replace(regex, (orig, esc, name) => { |
| esc = esc.length > 0 && esc.length % 2; |
| |
| if (esc) { |
| return orig; |
| } |
| |
| if (process.env[name] === undefined) { |
| throw new Error(`Failed to replace env in config: ${orig}`); |
| } |
| |
| return process.env[name]; |
| }); |
| }; |
| |
| // https://github.com/npm/npm/blob/latest/lib/config/core.js#L362-L407 |
| const parseField = (field, key) => { |
| if (typeof field !== 'string') { |
| return field; |
| } |
| |
| const typeList = [].concat(types[key]); |
| const isPath = typeList.indexOf(path) !== -1; |
| const isBool = typeList.indexOf(Boolean) !== -1; |
| const isString = typeList.indexOf(String) !== -1; |
| const isNumber = typeList.indexOf(Number) !== -1; |
| |
| field = `${field}`.trim(); |
| |
| if (/^".*"$/.test(field)) { |
| try { |
| field = JSON.parse(field); |
| } catch (err) { |
| throw new Error(`Failed parsing JSON config key ${key}: ${field}`); |
| } |
| } |
| |
| if (isBool && !isString && field === '') { |
| return true; |
| } |
| |
| switch (field) { // eslint-disable-line default-case |
| case 'true': { |
| return true; |
| } |
| |
| case 'false': { |
| return false; |
| } |
| |
| case 'null': { |
| return null; |
| } |
| |
| case 'undefined': { |
| return undefined; |
| } |
| } |
| |
| field = envReplace(field); |
| |
| if (isPath) { |
| const regex = process.platform === 'win32' ? /^~(\/|\\)/ : /^~\//; |
| |
| if (regex.test(field) && process.env.HOME) { |
| field = path.resolve(process.env.HOME, field.substr(2)); |
| } |
| |
| field = path.resolve(field); |
| } |
| |
| if (isNumber && !field.isNan()) { |
| field = Number(field); |
| } |
| |
| return field; |
| }; |
| |
| // https://github.com/npm/npm/blob/latest/lib/config/find-prefix.js |
| const findPrefix = name => { |
| name = path.resolve(name); |
| |
| let walkedUp = false; |
| |
| while (path.basename(name) === 'node_modules') { |
| name = path.dirname(name); |
| walkedUp = true; |
| } |
| |
| if (walkedUp) { |
| return name; |
| } |
| |
| const find = (name, original) => { |
| const regex = /^[a-zA-Z]:(\\|\/)?$/; |
| |
| if (name === '/' || (process.platform === 'win32' && regex.test(name))) { |
| return original; |
| } |
| |
| try { |
| const files = fs.readdirSync(name); |
| |
| if (files.indexOf('node_modules') !== -1 || files.indexOf('package.json') !== -1) { |
| return name; |
| } |
| |
| const dirname = path.dirname(name); |
| |
| if (dirname === name) { |
| return original; |
| } |
| |
| return find(dirname, original); |
| } catch (err) { |
| if (name === original) { |
| if (err.code === 'ENOENT') { |
| return original; |
| } |
| |
| throw err; |
| } |
| |
| return original; |
| } |
| }; |
| |
| return find(name, name); |
| }; |
| |
| exports.envReplace = envReplace; |
| exports.findPrefix = findPrefix; |
| exports.parseField = parseField; |