time-to-botec

Benchmark sampling in different programming languages
Log | Files | Refs | README

deepmerge.js (3389B)


      1 /**
      2 * @license Apache-2.0
      3 *
      4 * Copyright (c) 2018 The Stdlib Authors.
      5 *
      6 * Licensed under the Apache License, Version 2.0 (the "License");
      7 * you may not use this file except in compliance with the License.
      8 * You may obtain a copy of the License at
      9 *
     10 *    http://www.apache.org/licenses/LICENSE-2.0
     11 *
     12 * Unless required by applicable law or agreed to in writing, software
     13 * distributed under the License is distributed on an "AS IS" BASIS,
     14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15 * See the License for the specific language governing permissions and
     16 * limitations under the License.
     17 */
     18 
     19 'use strict';
     20 
     21 // MODULES //
     22 
     23 var objectKeys = require( './../../keys' );
     24 var isObject = require( '@stdlib/assert/is-object' );
     25 var hasOwnProp = require( '@stdlib/assert/has-own-property' );
     26 var isBuffer = require( '@stdlib/assert/is-buffer' );
     27 var isFunction = require( '@stdlib/assert/is-function' );
     28 var typeOf = require( './../../type-of' );
     29 var deepCopy = require( './../../copy' );
     30 
     31 
     32 // MAIN //
     33 
     34 /**
     35 * Merges a source object into a target object.
     36 *
     37 * @private
     38 * @param {Object} target - target object
     39 * @param {Object} source - source object
     40 * @param {number} level - merge level
     41 * @param {boolean} copy - indicates whether to perform a deep copy of merged values
     42 * @param {(boolean|Function)} override - defines the merge strategy
     43 * @param {boolean} extend - indicates whether new properties can be added to the target object
     44 */
     45 function deepMerge( target, source, level, copy, override, extend ) {
     46 	var hasProp;
     47 	var isFunc;
     48 	var name;
     49 	var keys;
     50 	var curr;
     51 	var key;
     52 	var val;
     53 	var tmp;
     54 	var i;
     55 
     56 	// Determine if we were provided a custom override strategy:
     57 	isFunc = isFunction( override );
     58 
     59 	// Decrement the level:
     60 	level -= 1;
     61 
     62 	// Loop through the source keys and implement the merge strategy...
     63 	keys = objectKeys( source );
     64 	for ( i = 0; i < keys.length; i++ ) {
     65 		key = keys[ i ];
     66 		hasProp = hasOwnProp( target, key );
     67 
     68 		// Can we add new properties to the target?
     69 		if ( !hasProp && !extend ) {
     70 			continue;
     71 		}
     72 		val = source[ key ];
     73 
     74 		if ( hasProp ) {
     75 			curr = target[ key ];
     76 			name = typeOf( curr );
     77 
     78 			// Should we recurse to perform a deep(er) merge? (only if both the current value and the proposed value are objects and the level is > 0)
     79 			if (
     80 				!isBuffer( curr ) &&
     81 				name === 'object' &&
     82 				isObject( val ) &&
     83 				level
     84 			) {
     85 				deepMerge( curr, val, level, copy, override, extend );
     86 				continue;
     87 			}
     88 			// Should we apply a custom merge (override) strategy?
     89 			if ( isFunc ) {
     90 				tmp = override( curr, val, key );
     91 
     92 				// WARNING: the following check does NOT prevent shared (leaky) nested references. We only check for top-level reference equality. We will assume that the user knows best, given their having provided a custom override strategy.
     93 				if ( copy && tmp !== curr && tmp === val ) {
     94 					tmp = deepCopy( tmp );
     95 				}
     96 				target[ key ] = tmp;
     97 			}
     98 			// Are we allowed to override an existing target value?
     99 			else if ( override ) {
    100 				if ( copy ) {
    101 					target[ key ] = deepCopy( val );
    102 				} else {
    103 					target[ key ] = val;
    104 				}
    105 			}
    106 		}
    107 		// New property to be added to target object. Should we deep copy the source value?
    108 		else if ( copy ) {
    109 			target[ key ] = deepCopy( val );
    110 		}
    111 		// Perform a simple assignment...
    112 		else {
    113 			target[ key ] = val;
    114 		}
    115 	}
    116 }
    117 
    118 
    119 // EXPORTS //
    120 
    121 module.exports = deepMerge;