UNPKG

7.05 kBJavaScriptView Raw
1/**
2 * lodash 3.0.0 (Custom Build) <https://lodash.com/>
3 * Build: `lodash modern modularize exports="npm" -o ./`
4 * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
5 * Based on Underscore.js 1.7.0 <http://underscorejs.org/LICENSE>
6 * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
7 * Available under MIT license <https://lodash.com/license>
8 */
9var arrayCopy = require('lodash._arraycopy'),
10 arrayEach = require('lodash._arrayeach'),
11 baseFor = require('lodash._basefor'),
12 createAssigner = require('lodash._createassigner'),
13 isArguments = require('lodash.isarguments'),
14 isArray = require('lodash.isarray'),
15 isPlainObject = require('lodash.isplainobject'),
16 isTypedArray = require('lodash.istypedarray'),
17 keys = require('lodash.keys'),
18 toPlainObject = require('lodash.toplainobject');
19
20/**
21 * Checks if `value` is object-like.
22 *
23 * @private
24 * @param {*} value The value to check.
25 * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
26 */
27function isObjectLike(value) {
28 return (value && typeof value == 'object') || false;
29}
30
31/**
32 * Used as the maximum length of an array-like value.
33 * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength)
34 * for more details.
35 */
36var MAX_SAFE_INTEGER = Math.pow(2, 53) - 1;
37
38/**
39 * The base implementation of `_.forOwn` without support for callback
40 * shorthands and `this` binding.
41 *
42 * @private
43 * @param {Object} object The object to iterate over.
44 * @param {Function} iteratee The function invoked per iteration.
45 * @returns {Object} Returns `object`.
46 */
47function baseForOwn(object, iteratee) {
48 return baseFor(object, iteratee, keys);
49}
50
51/**
52 * The base implementation of `_.merge` without support for argument juggling,
53 * multiple sources, and `this` binding `customizer` functions.
54 *
55 * @private
56 * @param {Object} object The destination object.
57 * @param {Object} source The source object.
58 * @param {Function} [customizer] The function to customize merging properties.
59 * @param {Array} [stackA=[]] Tracks traversed source objects.
60 * @param {Array} [stackB=[]] Associates values with source counterparts.
61 * @returns {Object} Returns the destination object.
62 */
63function baseMerge(object, source, customizer, stackA, stackB) {
64 var isSrcArr = isLength(source.length) && (isArray(source) || isTypedArray(source));
65
66 (isSrcArr ? arrayEach : baseForOwn)(source, function(srcValue, key, source) {
67 if (isObjectLike(srcValue)) {
68 stackA || (stackA = []);
69 stackB || (stackB = []);
70 return baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB);
71 }
72 var value = object[key],
73 result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
74 isCommon = typeof result == 'undefined';
75
76 if (isCommon) {
77 result = srcValue;
78 }
79 if ((isSrcArr || typeof result != 'undefined') &&
80 (isCommon || (result === result ? result !== value : value === value))) {
81 object[key] = result;
82 }
83 });
84 return object;
85}
86
87/**
88 * A specialized version of `baseMerge` for arrays and objects which performs
89 * deep merges and tracks traversed objects enabling objects with circular
90 * references to be merged.
91 *
92 * @private
93 * @param {Object} object The destination object.
94 * @param {Object} source The source object.
95 * @param {string} key The key of the value to merge.
96 * @param {Function} mergeFunc The function to merge values.
97 * @param {Function} [customizer] The function to customize merging properties.
98 * @param {Array} [stackA=[]] Tracks traversed source objects.
99 * @param {Array} [stackB=[]] Associates values with source counterparts.
100 * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
101 */
102function baseMergeDeep(object, source, key, mergeFunc, customizer, stackA, stackB) {
103 var length = stackA.length,
104 srcValue = source[key];
105
106 while (length--) {
107 if (stackA[length] == srcValue) {
108 object[key] = stackB[length];
109 return;
110 }
111 }
112 var value = object[key],
113 result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
114 isCommon = typeof result == 'undefined';
115
116 if (isCommon) {
117 result = srcValue;
118 if (isLength(srcValue.length) && (isArray(srcValue) || isTypedArray(srcValue))) {
119 result = isArray(value)
120 ? value
121 : (value ? arrayCopy(value) : []);
122 }
123 else if (isPlainObject(srcValue) || isArguments(srcValue)) {
124 result = isArguments(value)
125 ? toPlainObject(value)
126 : (isPlainObject(value) ? value : {});
127 }
128 else {
129 isCommon = false;
130 }
131 }
132 // Add the source value to the stack of traversed objects and associate
133 // it with its merged value.
134 stackA.push(srcValue);
135 stackB.push(result);
136
137 if (isCommon) {
138 // Recursively merge objects and arrays (susceptible to call stack limits).
139 object[key] = mergeFunc(result, srcValue, customizer, stackA, stackB);
140 } else if (result === result ? result !== value : value === value) {
141 object[key] = result;
142 }
143}
144
145/**
146 * Checks if `value` is a valid array-like length.
147 *
148 * @private
149 * @param {*} value The value to check.
150 * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
151 */
152function isLength(value) {
153 return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
154}
155
156/**
157 * Recursively merges own enumerable properties of the source object(s), that
158 * don't resolve to `undefined` into the destination object. Subsequent sources
159 * overwrite property assignments of previous sources. If `customizer` is
160 * provided it is invoked to produce the merged values of the destination and
161 * source properties. If `customizer` returns `undefined` merging is handled
162 * by the method instead. The `customizer` is bound to `thisArg` and invoked
163 * with five arguments; (objectValue, sourceValue, key, object, source).
164 *
165 * @static
166 * @memberOf _
167 * @category Object
168 * @param {Object} object The destination object.
169 * @param {...Object} [sources] The source objects.
170 * @param {Function} [customizer] The function to customize merging properties.
171 * @param {*} [thisArg] The `this` binding of `customizer`.
172 * @returns {Object} Returns `object`.
173 * @example
174 *
175 * var users = {
176 * 'data': [{ 'user': 'barney' }, { 'user': 'fred' }]
177 * };
178 *
179 * var ages = {
180 * 'data': [{ 'age': 36 }, { 'age': 40 }]
181 * };
182 *
183 * _.merge(users, ages);
184 * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] }
185 *
186 * // using a customizer callback
187 * var object = {
188 * 'fruits': ['apple'],
189 * 'vegetables': ['beet']
190 * };
191 *
192 * var other = {
193 * 'fruits': ['banana'],
194 * 'vegetables': ['carrot']
195 * };
196 *
197 * _.merge(object, other, function(a, b) {
198 * return _.isArray(a) ? a.concat(b) : undefined;
199 * });
200 * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] }
201 */
202var merge = createAssigner(baseMerge);
203
204module.exports = merge;