This commit is contained in:
Douglas Barone 2022-04-20 14:55:38 -04:00
parent 11619d5d81
commit d414480f5b

View File

@ -1,15 +1,13 @@
// https://github.com/douglascrockford/JSON-js/blob/master/cycle.js
/* /*
cycle.js cycle.js
2018-05-15 2021-05-31
Public Domain. Public Domain.
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
This code should be minified before deployment. This code should be minified before deployment.
See http://javascript.crockford.com/jsmin.html See https://www.crockford.com/jsmin.html
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
NOT CONTROL. NOT CONTROL.
@ -24,9 +22,9 @@
retrocycle, set, stringify, test retrocycle, set, stringify, test
*/ */
if (typeof JSON.decycle !== 'function') { if (typeof JSON.decycle !== "function") {
JSON.decycle = function decycle(object, replacer) { JSON.decycle = function decycle(object, replacer) {
'use strict' "use strict";
// Make a deep copy of an object or array, assuring that there is at most // 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 // one instance of each object or array in the resulting structure. The
@ -52,73 +50,77 @@ if (typeof JSON.decycle !== 'function') {
// the object or array. [NUMBER] or [STRING] indicates a child element or // the object or array. [NUMBER] or [STRING] indicates a child element or
// property. // property.
var objects = new WeakMap() // object to path mappings var objects = new WeakMap(); // object to path mappings
return (function derez(value, path) { return (function derez(value, path) {
// The derez function recurses through the object, producing the deep copy. // The derez function recurses through the object, producing the deep copy.
var old_path // The path of an earlier occurance of value var old_path; // The path of an earlier occurance of value
var nu // The new object or array var nu; // The new object or array
// If a replacer function was provided, then call it to get a replacement value. // If a replacer function was provided, then call it to get a replacement value.
if (replacer !== undefined) { if (replacer !== undefined) {
value = replacer(value) value = replacer(value);
} }
// typeof null === "object", so go on if this value is really an object but not // typeof null === "object", so go on if this value is really an object but not
// one of the weird builtin objects. // one of the weird builtin objects.
if ( if (
typeof value === 'object' && typeof value === "object"
value !== null && && value !== null
!(value instanceof Boolean) && && !(value instanceof Boolean)
!(value instanceof Date) && && !(value instanceof Date)
!(value instanceof Number) && && !(value instanceof Number)
!(value instanceof RegExp) && && !(value instanceof RegExp)
!(value instanceof String) && !(value instanceof String)
) { ) {
// If the value is an object or array, look to see if we have already // 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 uses an // encountered it. If so, return a {"$ref":PATH} object. This uses an
// ES6 WeakMap. // ES6 WeakMap.
old_path = objects.get(value) old_path = objects.get(value);
if (old_path !== undefined) { if (old_path !== undefined) {
return { $ref: old_path } return { $ref: old_path };
} }
// Otherwise, accumulate the unique value and its path. // Otherwise, accumulate the unique value and its path.
objects.set(value, path) objects.set(value, path);
// If it is an array, replicate the array. // If it is an array, replicate the array.
if (Array.isArray(value)) { if (Array.isArray(value)) {
nu = [] nu = [];
value.forEach(function (element, i) { value.forEach(function (element, i) {
nu[i] = derez(element, path + '[' + i + ']') nu[i] = derez(element, path + "[" + i + "]");
}) });
} else { } else {
// If it is an object, replicate the object. // If it is an object, replicate the object.
nu = {} nu = {};
Object.keys(value).forEach(function (name) { Object.keys(value).forEach(function (name) {
nu[name] = derez( nu[name] = derez(
value[name], value[name],
path + '[' + JSON.stringify(name) + ']' path + "[" + JSON.stringify(name) + "]"
) );
}) });
} }
return nu return nu;
}
return value
})(object, '$')
} }
return value;
}(object, "$"));
};
} }
if (typeof JSON.retrocycle !== 'function') {
if (typeof JSON.retrocycle !== "function") {
JSON.retrocycle = function retrocycle($) { JSON.retrocycle = function retrocycle($) {
'use strict' "use strict";
// Restore an object that was reduced by decycle. Members whose values are // Restore an object that was reduced by decycle. Members whose values are
// objects of the form // objects of the form
@ -139,41 +141,42 @@ if (typeof JSON.retrocycle !== 'function') {
// return JSON.retrocycle(JSON.parse(s)); // return JSON.retrocycle(JSON.parse(s));
// produces an array containing a single element which is the array itself. // produces an array containing a single element which is the array itself.
var px = /^\$(?:\[(?:\d+|"(?:[^\\"\u0000-\u001f]|\\(?:[\\"\/bfnrt]|u[0-9a-zA-Z]{4}))*")\])*$/ var px = /^\$(?:\[(?:\d+|"(?:[^\\"\u0000-\u001f]|\\(?:[\\"\/bfnrt]|u[0-9a-zA-Z]{4}))*")\])*$/;
(function rez(value) {
;(function rez(value) {
// The rez function walks recursively through the object looking for $ref // The rez function walks recursively through the object looking for $ref
// properties. When it finds one that has a value that is a path, then it // properties. When it finds one that has a value that is a path, then it
// replaces the $ref object with a reference to the value that is found by // replaces the $ref object with a reference to the value that is found by
// the path. // the path.
if (value && typeof value === 'object') { if (value && typeof value === "object") {
if (Array.isArray(value)) { if (Array.isArray(value)) {
value.forEach(function (element, i) { value.forEach(function (element, i) {
if (typeof element === 'object' && element !== null) { if (typeof element === "object" && element !== null) {
var path = element.$ref var path = element.$ref;
if (typeof path === 'string' && px.test(path)) { if (typeof path === "string" && px.test(path)) {
value[i] = eval(path) value[i] = eval(path);
} else { } else {
rez(element) rez(element);
} }
} }
}) });
} else { } else {
Object.keys(value).forEach(function (name) { Object.keys(value).forEach(function (name) {
var item = value[name] var item = value[name];
if (typeof item === 'object' && item !== null) { if (typeof item === "object" && item !== null) {
var path = item.$ref var path = item.$ref;
if (typeof path === 'string' && px.test(path)) { if (typeof path === "string" && px.test(path)) {
value[name] = eval(path) value[name] = eval(path);
} else { } else {
rez(item) rez(item);
} }
} }
}) });
} }
} }
})($) }($));
return $ return $;
} };
} }