diff options
| author | ruki <waruqi@gmail.com> | 2018-11-08 00:38:48 +0800 |
|---|---|---|
| committer | ruki <waruqi@gmail.com> | 2018-11-07 21:53:09 +0800 |
| commit | 26105034da4fcce7ac883c899d781f016559310d (patch) | |
| tree | c459a5dc4e3aa0972d9919033ece511ce76dd129 /node_modules/merge-options/index.js | |
| parent | 2c77f00f1a7ecb6c8192f9c16d3b2001b254a107 (diff) | |
| download | xmake-docs-26105034da4fcce7ac883c899d781f016559310d.tar.gz xmake-docs-26105034da4fcce7ac883c899d781f016559310d.zip | |
switch to vuepress
Diffstat (limited to 'node_modules/merge-options/index.js')
| -rw-r--r-- | node_modules/merge-options/index.js | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/node_modules/merge-options/index.js b/node_modules/merge-options/index.js new file mode 100644 index 00000000..8eb954de --- /dev/null +++ b/node_modules/merge-options/index.js @@ -0,0 +1,163 @@ +'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; +}; |
