cscg24-guacamole

CSCG 2024 Challenge 'Guacamole Mashup'
git clone https://git.sinitax.com/sinitax/cscg24-guacamole
Log | Files | Refs | sfeed.txt

deep-extend.js (4293B)


      1/*!
      2 * @description Recursive object extending
      3 * @author Viacheslav Lotsmanov <lotsmanov89@gmail.com>
      4 * @license MIT
      5 *
      6 * The MIT License (MIT)
      7 *
      8 * Copyright (c) 2013-2018 Viacheslav Lotsmanov
      9 *
     10 * Permission is hereby granted, free of charge, to any person obtaining a copy of
     11 * this software and associated documentation files (the "Software"), to deal in
     12 * the Software without restriction, including without limitation the rights to
     13 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
     14 * the Software, and to permit persons to whom the Software is furnished to do so,
     15 * subject to the following conditions:
     16 *
     17 * The above copyright notice and this permission notice shall be included in all
     18 * copies or substantial portions of the Software.
     19 *
     20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
     22 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
     23 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
     24 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     26 */
     27
     28'use strict';
     29
     30function isSpecificValue(val) {
     31	return (
     32		val instanceof Buffer
     33		|| val instanceof Date
     34		|| val instanceof RegExp
     35	) ? true : false;
     36}
     37
     38function cloneSpecificValue(val) {
     39	if (val instanceof Buffer) {
     40		var x = Buffer.alloc
     41			? Buffer.alloc(val.length)
     42			: new Buffer(val.length);
     43		val.copy(x);
     44		return x;
     45	} else if (val instanceof Date) {
     46		return new Date(val.getTime());
     47	} else if (val instanceof RegExp) {
     48		return new RegExp(val);
     49	} else {
     50		throw new Error('Unexpected situation');
     51	}
     52}
     53
     54/**
     55 * Recursive cloning array.
     56 */
     57function deepCloneArray(arr) {
     58	var clone = [];
     59	arr.forEach(function (item, index) {
     60		if (typeof item === 'object' && item !== null) {
     61			if (Array.isArray(item)) {
     62				clone[index] = deepCloneArray(item);
     63			} else if (isSpecificValue(item)) {
     64				clone[index] = cloneSpecificValue(item);
     65			} else {
     66				clone[index] = deepExtend({}, item);
     67			}
     68		} else {
     69			clone[index] = item;
     70		}
     71	});
     72	return clone;
     73}
     74
     75function safeGetProperty(object, property) {
     76	return property === '__proto__' ? undefined : object[property];
     77}
     78
     79/**
     80 * Extening object that entered in first argument.
     81 *
     82 * Returns extended object or false if have no target object or incorrect type.
     83 *
     84 * If you wish to clone source object (without modify it), just use empty new
     85 * object as first argument, like this:
     86 *   deepExtend({}, yourObj_1, [yourObj_N]);
     87 */
     88var deepExtend = module.exports = function (/*obj_1, [obj_2], [obj_N]*/) {
     89	if (arguments.length < 1 || typeof arguments[0] !== 'object') {
     90		return false;
     91	}
     92
     93	if (arguments.length < 2) {
     94		return arguments[0];
     95	}
     96
     97	var target = arguments[0];
     98
     99	// convert arguments to array and cut off target object
    100	var args = Array.prototype.slice.call(arguments, 1);
    101
    102	var val, src, clone;
    103
    104	args.forEach(function (obj) {
    105		// skip argument if isn't an object, is null, or is an array
    106		if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
    107			return;
    108		}
    109
    110		Object.keys(obj).forEach(function (key) {
    111			src = safeGetProperty(target, key); // source value
    112			val = safeGetProperty(obj, key); // new value
    113
    114			// recursion prevention
    115			if (val === target) {
    116				return;
    117
    118			/**
    119			 * if new value isn't object then just overwrite by new value
    120			 * instead of extending.
    121			 */
    122			} else if (typeof val !== 'object' || val === null) {
    123				target[key] = val;
    124				return;
    125
    126			// just clone arrays (and recursive clone objects inside)
    127			} else if (Array.isArray(val)) {
    128				target[key] = deepCloneArray(val);
    129				return;
    130
    131			// custom cloning and overwrite for specific objects
    132			} else if (isSpecificValue(val)) {
    133				target[key] = cloneSpecificValue(val);
    134				return;
    135
    136			// overwrite by new value if source isn't object or array
    137			} else if (typeof src !== 'object' || src === null || Array.isArray(src)) {
    138				target[key] = deepExtend({}, val);
    139				return;
    140
    141			// source value and new value is objects both, extending...
    142			} else {
    143				target[key] = deepExtend(src, val);
    144				return;
    145			}
    146		});
    147	});
    148
    149	return target;
    150};