'use strict'; function objectToString(o) { return Object.prototype.toString.call(o); } // shim for Node's 'util' package // DO NOT REMOVE THIS! It is required for compatibility with EnderJS (http://enderjs.com/). var util = { isArray: function (ar) { return Array.isArray(ar) || (typeof ar === 'object' && objectToString(ar) === '[object Array]'); }, isDate: function (d) { return typeof d === 'object' && objectToString(d) === '[object Date]'; }, isRegExp: function (re) { return typeof re === 'object' && objectToString(re) === '[object RegExp]'; }, getRegExpFlags: function (re) { var flags = ''; re.global && (flags += 'g'); re.ignoreCase && (flags += 'i'); re.multiline && (flags += 'm'); return flags; } }; if (typeof module === 'object') module.exports = clone; /** * Clones (copies) an Object using deep copying. * * This function supports circular references by default, but if you are certain * there are no circular references in your object, you can save some CPU time * by calling clone(obj, false). * * Caution: if `circular` is false and `parent` contains circular references, * your program may enter an infinite loop and crash. * * @param `parent` - the object to be cloned * @param `circular` - set to true if the object to be cloned may contain * circular references. (optional - true by default) * @param `depth` - set to a number if the object is only to be cloned to * a particular depth. (optional - defaults to Infinity) * @param `prototype` - sets the prototype to be used when cloning an object. * (optional - defaults to parent prototype). */ function clone(parent, circular, depth, prototype) { // maintain two arrays for circular references, where corresponding parents // and children have the same index var allParents = []; var allChildren = []; var useBuffer = typeof Buffer != 'undefined'; if (typeof circular == 'undefined') circular = true; if (typeof depth == 'undefined') depth = Infinity; // recurse this function so we don't reset allParents and allChildren function _clone(parent, depth) { // cloning null always returns null if (parent === null) return null; if (depth == 0) return parent; var child; var proto; if (typeof parent != 'object') { return parent; } if (util.isArray(parent)) { child = []; } else if (util.isRegExp(parent)) { child = new RegExp(parent.source, util.getRegExpFlags(parent)); if (parent.lastIndex) child.lastIndex = parent.lastIndex; } else if (util.isDate(parent)) { child = new Date(parent.getTime()); } else if (useBuffer && Buffer.isBuffer(parent)) { child = new Buffer(parent.length); parent.copy(child); return child; } else { if (typeof prototype == 'undefined') { proto = Object.getPrototypeOf(parent); child = Object.create(proto); } else { child = Object.create(prototype); proto = prototype; } } if (circular) { var index = allParents.indexOf(parent); if (index != -1) { return allChildren[index]; } allParents.push(parent); allChildren.push(child); } for (var i in parent) { var attrs; if (proto) { attrs = Object.getOwnPropertyDescriptor(proto, i); } if (attrs && attrs.set == null) { continue; } child[i] = _clone(parent[i], depth - 1); } return child; } return _clone(parent, depth); } /** * Simple flat clone using prototype, accepts only objects, usefull for property * override on FLAT configuration object (no nested props). * * USE WITH CAUTION! This may not behave as you wish if you do not know how this * works. */ clone.clonePrototype = function(parent) { if (parent === null) return null; var c = function () {}; c.prototype = parent; return new c(); };