diff options
author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2020-06-28 12:38:34 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-28 12:38:34 -0400 |
commit | cdf191336aa616a206b977ba3beeb1233cf41c32 (patch) | |
tree | 07df9e5eec80dd4379c7ed97854a2bd9ef5149eb /ext/mixed | |
parent | 5bf805755a33f6f10fd9621f8a2bff7ba1cb7440 (diff) |
Clone function (#624)
* Add clone function
* Replace utilIsolate with clone
* Replace JsonSchema.isolate with clone function
* Include core.js for tests which use json-schema.js
* Update visisted set
Diffstat (limited to 'ext/mixed')
-rw-r--r-- | ext/mixed/js/core.js | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/ext/mixed/js/core.js b/ext/mixed/js/core.js index 21b7bf5e..9b3ea3e2 100644 --- a/ext/mixed/js/core.js +++ b/ext/mixed/js/core.js @@ -157,6 +157,73 @@ function getSetDifference(set1, set2) { ); } +const clone = (() => { + // eslint-disable-next-line no-shadow + function clone(value) { + if (value === null) { return null; } + switch (typeof value) { + case 'boolean': + case 'number': + case 'string': + case 'bigint': + case 'symbol': + case 'undefined': + return value; + default: + return cloneInternal(value, new Set()); + } + } + + function cloneInternal(value, visited) { + if (value === null) { return null; } + switch (typeof value) { + case 'boolean': + case 'number': + case 'string': + case 'bigint': + case 'symbol': + case 'undefined': + return value; + case 'function': + return cloneObject(value, visited); + case 'object': + return Array.isArray(value) ? cloneArray(value, visited) : cloneObject(value, visited); + } + } + + function cloneArray(value, visited) { + if (visited.has(value)) { throw new Error('Circular'); } + try { + visited.add(value); + const result = []; + for (const item of value) { + result.push(cloneInternal(item, visited)); + } + return result; + } finally { + visited.delete(value); + } + } + + function cloneObject(value, visited) { + if (visited.has(value)) { throw new Error('Circular'); } + try { + visited.add(value); + const result = {}; + for (const key in value) { + if (Object.prototype.hasOwnProperty.call(value, key)) { + result[key] = cloneInternal(value[key], visited); + } + } + return result; + } finally { + visited.delete(value); + } + } + + return clone; +})(); + /* * Async utilities |