You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							163 lines
						
					
					
						
							3.6 KiB
						
					
					
				
			
		
		
	
	
							163 lines
						
					
					
						
							3.6 KiB
						
					
					
				'use strict'; | 
						|
const isOptionObject = require('is-plain-obj'); | 
						|
 | 
						|
const hasOwnProperty = Object.prototype.hasOwnProperty; | 
						|
const propIsEnumerable = Object.propertyIsEnumerable; | 
						|
const defineProperty = (obj, name, value) => Object.defineProperty(obj, name, { | 
						|
	value, | 
						|
	writable: true, | 
						|
	enumerable: true, | 
						|
	configurable: true | 
						|
}); | 
						|
 | 
						|
const globalThis = this; | 
						|
const defaultMergeOpts = { | 
						|
	concatArrays: false | 
						|
}; | 
						|
 | 
						|
const getEnumerableOwnPropertyKeys = value => { | 
						|
	const keys = []; | 
						|
 | 
						|
	for (const key in value) { | 
						|
		if (hasOwnProperty.call(value, key)) { | 
						|
			keys.push(key); | 
						|
		} | 
						|
	} | 
						|
 | 
						|
	/* istanbul ignore else  */ | 
						|
	if (Object.getOwnPropertySymbols) { | 
						|
		const symbols = Object.getOwnPropertySymbols(value); | 
						|
 | 
						|
		for (let i = 0; i < symbols.length; i++) { | 
						|
			if (propIsEnumerable.call(value, symbols[i])) { | 
						|
				keys.push(symbols[i]); | 
						|
			} | 
						|
		} | 
						|
	} | 
						|
 | 
						|
	return keys; | 
						|
}; | 
						|
 | 
						|
function clone(value) { | 
						|
	if (Array.isArray(value)) { | 
						|
		return cloneArray(value); | 
						|
	} | 
						|
 | 
						|
	if (isOptionObject(value)) { | 
						|
		return cloneOptionObject(value); | 
						|
	} | 
						|
 | 
						|
	return value; | 
						|
} | 
						|
 | 
						|
function cloneArray(array) { | 
						|
	const result = array.slice(0, 0); | 
						|
 | 
						|
	getEnumerableOwnPropertyKeys(array).forEach(key => { | 
						|
		defineProperty(result, key, clone(array[key])); | 
						|
	}); | 
						|
 | 
						|
	return result; | 
						|
} | 
						|
 | 
						|
function cloneOptionObject(obj) { | 
						|
	const result = Object.getPrototypeOf(obj) === null ? Object.create(null) : {}; | 
						|
 | 
						|
	getEnumerableOwnPropertyKeys(obj).forEach(key => { | 
						|
		defineProperty(result, key, clone(obj[key])); | 
						|
	}); | 
						|
 | 
						|
	return result; | 
						|
} | 
						|
 | 
						|
/** | 
						|
 * @param merged {already cloned} | 
						|
 * @return {cloned Object} | 
						|
 */ | 
						|
const mergeKeys = (merged, source, keys, mergeOpts) => { | 
						|
	keys.forEach(key => { | 
						|
		// Do not recurse into prototype chain of merged | 
						|
		if (key in merged && merged[key] !== Object.getPrototypeOf(merged)) { | 
						|
			defineProperty(merged, key, merge(merged[key], source[key], mergeOpts)); | 
						|
		} else { | 
						|
			defineProperty(merged, key, clone(source[key])); | 
						|
		} | 
						|
	}); | 
						|
 | 
						|
	return merged; | 
						|
}; | 
						|
 | 
						|
/** | 
						|
 * @param merged {already cloned} | 
						|
 * @return {cloned Object} | 
						|
 * | 
						|
 * see [Array.prototype.concat ( ...arguments )](http://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.concat) | 
						|
 */ | 
						|
const concatArrays = (merged, source, mergeOpts) => { | 
						|
	let result = merged.slice(0, 0); | 
						|
	let resultIndex = 0; | 
						|
 | 
						|
	[merged, source].forEach(array => { | 
						|
		const indices = []; | 
						|
 | 
						|
		// `result.concat(array)` with cloning | 
						|
		for (let k = 0; k < array.length; k++) { | 
						|
			if (!hasOwnProperty.call(array, k)) { | 
						|
				continue; | 
						|
			} | 
						|
 | 
						|
			indices.push(String(k)); | 
						|
 | 
						|
			if (array === merged) { | 
						|
				// Already cloned | 
						|
				defineProperty(result, resultIndex++, array[k]); | 
						|
			} else { | 
						|
				defineProperty(result, resultIndex++, clone(array[k])); | 
						|
			} | 
						|
		} | 
						|
 | 
						|
		// Merge non-index keys | 
						|
		result = mergeKeys(result, array, getEnumerableOwnPropertyKeys(array).filter(key => { | 
						|
			return indices.indexOf(key) === -1; | 
						|
		}), mergeOpts); | 
						|
	}); | 
						|
 | 
						|
	return result; | 
						|
}; | 
						|
 | 
						|
/** | 
						|
 * @param merged {already cloned} | 
						|
 * @return {cloned Object} | 
						|
 */ | 
						|
function merge(merged, source, mergeOpts) { | 
						|
	if (mergeOpts.concatArrays && Array.isArray(merged) && Array.isArray(source)) { | 
						|
		return concatArrays(merged, source, mergeOpts); | 
						|
	} | 
						|
 | 
						|
	if (!isOptionObject(source) || !isOptionObject(merged)) { | 
						|
		return clone(source); | 
						|
	} | 
						|
 | 
						|
	return mergeKeys(merged, source, getEnumerableOwnPropertyKeys(source), mergeOpts); | 
						|
} | 
						|
 | 
						|
module.exports = function () { | 
						|
	const mergeOpts = merge(clone(defaultMergeOpts), (this !== globalThis && this) || {}, defaultMergeOpts); | 
						|
	let merged = {foobar: {}}; | 
						|
 | 
						|
	for (let i = 0; i < arguments.length; i++) { | 
						|
		const option = arguments[i]; | 
						|
 | 
						|
		if (option === undefined) { | 
						|
			continue; | 
						|
		} | 
						|
 | 
						|
		if (!isOptionObject(option)) { | 
						|
			throw new TypeError('`' + option + '` is not an Option Object'); | 
						|
		} | 
						|
 | 
						|
		merged = merge(merged, {foobar: option}, mergeOpts); | 
						|
	} | 
						|
 | 
						|
	return merged.foobar; | 
						|
};
 | 
						|
 |