148 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			148 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| '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;
 |