UNPKG

testem

Version:

Test'em 'scripts! Javascript Unit testing made easy.

115 lines (91 loc) 3.74 kB
// Modified version of https://github.com/douglascrockford/JSON-js/blob/master/cycle.js // Handle DOM elements // Removed global reference // Stop traversing beyond a max depth /* cycle.js 2013-02-19 Public Domain. NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. This code should be minified before deployment. See http://javascript.crockford.com/jsmin.html USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO NOT CONTROL. */ /*jslint evil: true, regexp: true */ /*members $ref, apply, call, decycle, hasOwnProperty, length, prototype, push, retrocycle, stringify, test, toString, nodeType */ /* exported decycle */ 'use strict'; function decycle(object, maxDepth) { // Make a deep copy of an object or array, assuring that there is at most // one instance of each object or array in the resulting structure. The // duplicate references (which might be forming cycles) are replaced with // an object of the form // {$ref: PATH} // where the PATH is a JSONPath string that locates the first occurance. // So, // var a = []; // a[0] = a; // return JSON.stringify(JSON.decycle(a)); // produces the string '[{"$ref":"$"}]'. // JSONPath is used to locate the unique object. $ indicates the top level of // the object or array. [NUMBER] or [STRING] indicates a child member or // property. var objects = []; // Keep a reference to each unique object or array var paths = []; // Keep the path to each unique object or array maxDepth = maxDepth || 5; return (function derez(value, path, depth) { if (depth > maxDepth) { return 'Decycle max depth reached at ' + maxDepth + '. You may override the default by setting "client_decycle_depth" in your testem config.'; } // The derez recurses through the object, producing the deep copy. var i, // The loop counter name, // Property name nu; // The new object or array // typeof null === 'object', so go on if this value is really an object but not // one of the weird builtin objects. // Handle DOM elements if (value === null || typeof value === 'undefined' || value instanceof Boolean || value instanceof Number) { return value; } if (typeof value === 'object' && typeof value.nodeType === 'number') { return String(value); } if (typeof value === 'object' && value !== null && !(value instanceof Date) && !(value instanceof RegExp) && !(value instanceof String)) { // If the value is an object or array, look to see if we have already // encountered it. If so, return a $ref/path object. This is a hard way, // linear search that will get slower as the number of unique objects grows. for (i = 0; i < objects.length; i += 1) { if (objects[i] === value) { return {$ref: paths[i]}; } } // Otherwise, accumulate the unique value and its path. objects.push(value); paths.push(path); // If it is an array, replicate the array. if (Object.prototype.toString.apply(value) === '[object Array]') { nu = []; for (i = 0; i < value.length; i += 1) { nu[i] = derez(value[i], path + '[' + i + ']', depth + 1); } } else { // If it is an object, replicate the object. nu = {}; for (name in value) { if (Object.prototype.hasOwnProperty.call(value, name)) { nu[name] = derez(value[name], path + '[' + JSON.stringify(name) + ']', depth + 1); } } } return nu; } return value; }(object, '$', 0)); }