From 797fa0af78c01e85de9dfcf2d0ed3b71730e9e01 Mon Sep 17 00:00:00 2001 From: jfet97 Date: Tue, 8 Jan 2019 21:19:58 +0100 Subject: [PATCH] 7.0.0 --- README.md | 7 ++-- __test__/omniclone.test.js | 25 +++++------- dist/main.js | 2 +- package.json | 2 +- src/deepClone.js | 18 +++++---- src/handlers/mapEntriesHandler.js | 38 +++---------------- .../otherObjectsDescriptorsHandler.js | 23 +++-------- src/handlers/setEntriesHandler.js | 16 +++----- src/omniclone.js | 5 ++- src/utility/circReferencesHelper.js | 16 -------- src/utility/dependenciesMapHandler.js | 2 +- src/utility/prevReferencesHelper.js | 8 ++++ 12 files changed, 55 insertions(+), 107 deletions(-) delete mode 100644 src/utility/circReferencesHelper.js create mode 100644 src/utility/prevReferencesHelper.js diff --git a/README.md b/README.md index 35e4d77..0cce0cf 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ import omniclone from 'omniclone'; 3. let you to clone objects with circular references (customizable behavior) 4. let you to copy getters and setters, non enumerables properties and also symbols (customizable behavior) 5. correct handling of String, Boolean, Number, Error, Promise, Map, Set, WeakMap and WeakSet objects -6. safe similar sibilings references are not duplicated +6. similar references are not duplicated 7. correct cloning of Array objects 8. correct cloning of RegExp and Date objects @@ -151,9 +151,10 @@ const res = omniclone(source, { ``` Odds are that to properly copy gets&setts you have also to enable the `copyNonEnumerables` flag. -### allowCircularReferences (default false) +### allowCircularReferences (default true) Enable it to allow circular references.\ Disable it to throw an error if one is met. +Know that `omniclone` is more performing with this flag __enabled__, so disable it only if you really need. ```js const res = omniclone(source, { allowCircularReferences: true @@ -179,7 +180,7 @@ omniclone(source, { copyNonEnumerables : false, copySymbols : false, copyGettersSetters : false, - allowCircularReferences: false, + allowCircularReferences: true, discardErrorObjects: true, }); ``` diff --git a/__test__/omniclone.test.js b/__test__/omniclone.test.js index 7108ec9..5e79c84 100644 --- a/__test__/omniclone.test.js +++ b/__test__/omniclone.test.js @@ -14,7 +14,7 @@ describe("omniclone", () => { it(`should set setPrototype to false, invokeConstructors to true, discardErrorObjects to true, copyNonEnumerables to false, copySymbols to false, copyGettersSetters to false and - allowCircularReferences to false if the config argument is undefined`, () => { + allowCircularReferences to true if the config argument is undefined`, () => { (() => { let i = 0; class Test { @@ -48,7 +48,7 @@ describe("omniclone", () => { const ob1 = {}; ob1.ob1 = ob1; omniclone(ob1); - }).toThrow(TypeError("TypeError: circular reference found")); + }).not.toThrow(TypeError("TypeError: circular reference found")); (() => { class MyError extends Error {} @@ -544,16 +544,7 @@ describe("omniclone", () => { const ob1 = {}; ob1.ob1 = ob1; expect(() => { - omniclone(ob1); - }).toThrow(TypeError("TypeError: circular reference found")); - })(); - - (() => { - const ob1 = {}; - const ob2 = { ob1 }; - ob1.ob2 = ob2; - expect(() => { - omniclone(ob1); + omniclone(ob1, { allowCircularReferences: false }); }).toThrow(TypeError("TypeError: circular reference found")); })(); }); @@ -572,7 +563,7 @@ describe("omniclone", () => { const ob2 = { ob1 }; ob1.ob2 = ob2; expect(() => { - omniclone(ob1, { allowCircularReferences: true }); + omniclone(ob1); }).toBeDefined(); })(); @@ -1037,7 +1028,9 @@ describe("omniclone", () => { const map = new Map(); map.set(map, map); expect(() => { - omniclone(map); + omniclone(map, { + allowCircularReferences: false + }); }).toThrow(TypeError("TypeError: circular reference found")); })(); @@ -1335,7 +1328,9 @@ describe("omniclone", () => { const set = new Set(); set.add(set); expect(() => { - omniclone(set); + omniclone(set, { + allowCircularReferences: false + }); }).toThrow(TypeError("TypeError: circular reference found")); })(); diff --git a/dist/main.js b/dist/main.js index 2b7f680..21e73a7 100644 --- a/dist/main.js +++ b/dist/main.js @@ -1 +1 @@ -module.exports=function(e){var t={};function n(o){if(t[o])return t[o].exports;var r=t[o]={i:o,l:!1,exports:{}};return e[o].call(r.exports,r,r.exports,n),r.l=!0,r.exports}return n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)n.d(o,r,function(t){return e[t]}.bind(null,r));return o},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=6)}([function(e,t){e.exports=(e=>{if(e)return null;throw new TypeError("TypeError: cannot copy Error objects")})},function(e,t){e.exports=(e=>{const{source:t,flags:n,lastIndex:o}=e,r=new RegExp(t,n);return r.lastIndex=o,r})},function(e,t){e.exports=(e=>new Date(e.getTime()))},function(e,t){e.exports=(e=>e.valueOf())},function(e,t){e.exports=((e,t,n)=>{if(e.has(t)){if(n)return e.get(t);throw new TypeError("TypeError: circular reference found")}return null})},function(e,t){e.exports=((e,t)=>e.has(t)?e.get(t):null)},function(e,t,n){const o=n(7),r=n(0),s=n(1),i=n(2),c=n(16),f=n(17);e.exports=function(e={},{setPrototype:t=!1,invokeConstructors:n=!0,copyNonEnumerables:a=!1,copySymbols:u=!1,copyGettersSetters:p=!1,allowCircularReferences:l=!1,discardErrorObjects:y=!0}={}){if(!e||"object"!=typeof e)throw new TypeError("TypeError: invalid 'obj' argument's type");if(e instanceof Number||e instanceof String||e instanceof Boolean)return null;if(e instanceof Promise||e instanceof WeakMap||e instanceof WeakSet)return e;if(e instanceof Error)return r(y);if(e instanceof RegExp)return s(e);if(e instanceof Date)return i(e);if("boolean"!=typeof t)throw new TypeError("TypeError: invalid 'setPrototype' flag's type");if("boolean"!=typeof n)throw new TypeError("TypeError: invalid 'invokeConstructors' flag's type");if("boolean"!=typeof a)throw new TypeError("TypeError: invalid 'copyNonEnumerables' flag's type");if("boolean"!=typeof u)throw new TypeError("TypeError: invalid 'copySymbols' flag's type");if("boolean"!=typeof p)throw new TypeError("TypeError: invalid 'copyGettersSetters' flag's type");if("boolean"!=typeof l)throw new TypeError("TypeError: invalid 'allowCircularReferences' flag's type");if("boolean"!=typeof y)throw new TypeError("TypeError: invalid 'discardErrorObjects' flag's type");if(!l){const t=c(e,a,u);l=f(t)}return o(e,{setPrototype:t,invokeConstructors:n,copyNonEnumerables:a,copySymbols:u,copyGettersSetters:p,allowCircularReferences:l,discardErrorObjects:y})}},function(e,t,n){const o=n(8),r=n(12);e.exports=function(e,t){return function e(t,n,s,i){const{setPrototype:c,invokeConstructors:f,allowCircularReferences:a}=n;s.set(t,t);let u=null;if(u=f?new t.constructor:c?Object.create(Object.getPrototypeOf(t)):{},t instanceof Array&&(u=[]),t instanceof Map){u=new Map;const o=[...t.entries()];r(u,{mapEntries:o},n,i,s,e)}else if(t instanceof Set){u=new Set;const o=[...t.values()];r(u,{setEntries:o},n,i,s,e)}else{const o=Object.getOwnPropertyDescriptors(t);r(u,{ownPropsDcps:o},n,i,s,e)}return a&&(s.set(t,u),i===t&&o(u,s)),u}(e,t,new WeakMap,e)}},function(e,t,n){const o=n(9),r=n(10),s=n(11);e.exports=function(e,t){const n=new WeakMap;n.set(e),function e(t,n,i){return t instanceof Map?o(t,n,i,e):t instanceof Set?r(t,n,i,e):s(t,n,i,e)}(e,t,n)}},function(e,t){e.exports=((e,t,n,o)=>{const r=[...e.entries()];for(const[s,i]of r)if(i&&"object"==typeof i)if(t.has(i))e.set(s,t.get(i));else{if(n.has(i))continue;n.set(i),o(i,t,n)}})},function(e,t){e.exports=((e,t,n,o)=>{const r=[...e.values()];for(const s of r)if(s&&"object"==typeof s)if(t.has(s))e.delete(s),e.add(t.get(s));else{if(n.has(s))continue;n.set(s),o(s,t,n)}})},function(e,t){e.exports=((e,t,n,o)=>{const r=Object.getOwnPropertyDescriptors(e);Object.entries(r).forEach(([r,s])=>{if(s.set||s.get)return;const{value:i}=s;if(i&&"object"==typeof i)if(t.has(i))e[r]=t.get(i);else{if(n.has(i))return;n.set(i),o(i,t,n)}})})},function(e,t,n){const o=n(13),r=n(14),s=n(15);e.exports=function(e,t,n,i,c,f){return function(e,t,n,c,a){const{mapEntries:u,setEntries:p,ownPropsDcps:l}=t;if(u)return o(e,u,n,i,c,a,f);if(p)return r(e,p,n,i,a,f);if(l)return s(e,l,n,i,c,a,f);throw new Error("wrong data parameter for innerPropsHandler function")}(e,t,n,new WeakMap,c)}},function(e,t,n){const o=n(0),r=n(1),s=n(2),i=n(3),c=n(4),f=n(5);e.exports=((e,t,n,a,u,p,l)=>{const y=t,{allowCircularReferences:d,discardErrorObjects:b}=n;for(const[t,E]of y)if(E&&"object"==typeof E){const y=f(u,E);if(y){e.set(t,y);continue}const w=c(p,E,d);if(w){e.set(t,w);continue}if(p.has(E)){if(d){e.set(t,p.get(E));continue}throw new TypeError("TypeError: circular reference found")}if(E instanceof Error){o(b);continue}if(E instanceof Number||E instanceof Boolean||E instanceof String){e.set(t,i(E));continue}if(E instanceof Date){const n=s(E);e.set(t,n),u.set(E,n);continue}if(E instanceof RegExp){const n=r(E);e.set(t,n),u.set(E,n);continue}if(E instanceof Promise){e.set(t,E);continue}if(E instanceof WeakMap){e.set(t,E);continue}if(E instanceof WeakSet){e.set(t,E);continue}e.set(t,l(E,n,p,a)),u.set(E,e.get(t))}else e.set(t,E)})},function(e,t,n){const o=n(0),r=n(1),s=n(2),i=n(3),c=n(4);e.exports=((e,t,n,f,a,u)=>{const p=t,{allowCircularReferences:l,discardErrorObjects:y}=n;for(const t of p)if(t&&"object"==typeof t){const p=c(a,t,l);if(p){e.add(p);continue}if(t instanceof Error){o(y);continue}if(t instanceof Number||t instanceof Boolean||t instanceof String){e.add(i(t));continue}if(t instanceof Date){const n=s(t);e.add(n);continue}if(t instanceof RegExp){const n=r(t);e.add(n);continue}if(t instanceof Promise){e.add(t);continue}if(t instanceof WeakMap){e.add(t);continue}if(t instanceof WeakSet){e.add(t);continue}const d=u(t,n,a,f);e.add(d)}else e.add(t)})},function(e,t,n){const o=n(0),r=n(1),s=n(2),i=n(3),c=n(4),f=n(5);e.exports=((e,t,n,a,u,p,l)=>{const y=t,{copyNonEnumerables:d,copySymbols:b,copyGettersSetters:E,allowCircularReferences:w,discardErrorObjects:j}=n;Object.entries(y).forEach(([t,y])=>{const{value:g,enumerable:v}=y;if((d||v)&&(b||"symbol"!=typeof t)&&(E||!y.get&&!y.set))if(g&&"object"==typeof g){const d=f(u,g);if(d)return void(e[t]=d);const b=c(p,g,w);if(b)return void(e[t]=b);if(g instanceof Error)return void o(j);if(g instanceof Number||g instanceof Boolean||g instanceof String){const n=i(g);return void Object.defineProperty(e,t,{...y,...{value:n}})}if(g instanceof Date){const n=s(g);return Object.defineProperty(e,t,{...y,...{value:n}}),void u.set(g,n)}if(g instanceof RegExp){const n=r(g);return Object.defineProperty(e,t,{...y,...{value:n}}),void u.set(g,n)}if(g instanceof Promise)return void Object.defineProperty(e,t,y);if(g instanceof WeakMap)return void Object.defineProperty(e,t,y);if(g instanceof WeakSet)return void Object.defineProperty(e,t,y);e[t]=l(g,n,p,a),u.set(g,e[t])}else{const n=Object.getOwnPropertyDescriptor(e,t);n&&!n.configurable||Object.defineProperty(e,t,y)}})})},function(e,t){e.exports=((e,t=!1,n=!1)=>{const o=new Set,r=new Map;return function e(s){o.add(s);const i=new Set;if(s instanceof Map)[...s.entries()].forEach(([,t])=>{"object"==typeof t&&(i.add(t),o.has(t)||e(t))});else if(s instanceof Set)[...s.values()].forEach(t=>{"object"==typeof t&&(i.add(t),o.has(t)||e(t))});else if(t||n){const r=Object.getOwnPropertyDescriptors(s);Object.entries(r).forEach(([r,s])=>{if(s.set||s.get)return;if(!1===s.enumerable&&!1===t)return;if("symbol"==typeof r&&!1===n)return;const{value:c}=s;c&&"object"==typeof c&&(i.add(c),o.has(c)||e(c))})}else Object.values(s).forEach(t=>{"object"==typeof t&&(i.add(t),o.has(t)||e(t))});r.set(s,i)}(e),r})},function(e,t){e.exports=function(e){return!function e(t){if(0===t.size)return t;const n=[...t.entries()].find(([,e])=>0===e.size);if(!n)return t;const[o]=n;return function(e,t){[...t.entries()].forEach(([,t])=>{t.has(e)&&t.delete(e)})}(o,t),t.delete(o),e(t)}(e).size}}]); \ No newline at end of file +module.exports=function(e){var t={};function n(o){if(t[o])return t[o].exports;var r=t[o]={i:o,l:!1,exports:{}};return e[o].call(r.exports,r,r.exports,n),r.l=!0,r.exports}return n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)n.d(o,r,function(t){return e[t]}.bind(null,r));return o},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=5)}([function(e,t){e.exports=(e=>{if(e)return null;throw new TypeError("TypeError: cannot copy Error objects")})},function(e,t){e.exports=(e=>{const{source:t,flags:n,lastIndex:o}=e,r=new RegExp(t,n);return r.lastIndex=o,r})},function(e,t){e.exports=(e=>new Date(e.getTime()))},function(e,t){e.exports=(e=>e.valueOf())},function(e,t){e.exports=((e,t)=>e.has(t)?e.get(t):null)},function(e,t,n){const o=n(6),r=n(0),s=n(1),i=n(2),c=n(15),f=n(16);e.exports=function(e={},{setPrototype:t=!1,invokeConstructors:n=!0,copyNonEnumerables:a=!1,copySymbols:u=!1,copyGettersSetters:p=!1,allowCircularReferences:l=!0,discardErrorObjects:y=!0}={}){if(!e||"object"!=typeof e)throw new TypeError("TypeError: invalid 'obj' argument's type");if(e instanceof Number||e instanceof String||e instanceof Boolean)return null;if(e instanceof Promise||e instanceof WeakMap||e instanceof WeakSet)return e;if(e instanceof Error)return r(y);if(e instanceof RegExp)return s(e);if(e instanceof Date)return i(e);if("boolean"!=typeof t)throw new TypeError("TypeError: invalid 'setPrototype' flag's type");if("boolean"!=typeof n)throw new TypeError("TypeError: invalid 'invokeConstructors' flag's type");if("boolean"!=typeof a)throw new TypeError("TypeError: invalid 'copyNonEnumerables' flag's type");if("boolean"!=typeof u)throw new TypeError("TypeError: invalid 'copySymbols' flag's type");if("boolean"!=typeof p)throw new TypeError("TypeError: invalid 'copyGettersSetters' flag's type");if("boolean"!=typeof l)throw new TypeError("TypeError: invalid 'allowCircularReferences' flag's type");if("boolean"!=typeof y)throw new TypeError("TypeError: invalid 'discardErrorObjects' flag's type");if(!l){const t=c(e,a,u);if(f(t))throw new TypeError("TypeError: circular reference found")}return o(e,{setPrototype:t,invokeConstructors:n,copyNonEnumerables:a,copySymbols:u,copyGettersSetters:p,allowCircularReferences:l,discardErrorObjects:y})}},function(e,t,n){const o=n(7),r=n(11);e.exports=function(e,t){return function e(t,n,s,i){const{setPrototype:c,invokeConstructors:f,allowCircularReferences:a}=n;s.set(t,t);let u=null;if(u=f?new t.constructor:c?Object.create(Object.getPrototypeOf(t)):{},t instanceof Array&&(u=[]),t instanceof Map){u=new Map;const o=[...t.entries()];r(u,{mapEntries:o},n,i,s,e)}else if(t instanceof Set){u=new Set;const o=[...t.values()];r(u,{setEntries:o},n,i,s,e)}else{const o=Object.getOwnPropertyDescriptors(t);r(u,{ownPropsDcps:o},n,i,s,e)}return s.set(t,u),a&&i===t&&o(u,s),u}(e,t,new WeakMap,e)}},function(e,t,n){const o=n(8),r=n(9),s=n(10);e.exports=function(e,t){const n=new WeakMap;n.set(e),function e(t,n,i){return t instanceof Map?o(t,n,i,e):t instanceof Set?r(t,n,i,e):s(t,n,i,e)}(e,t,n)}},function(e,t){e.exports=((e,t,n,o)=>{const r=[...e.entries()];for(const[s,i]of r)if(i&&"object"==typeof i)if(t.has(i))e.set(s,t.get(i));else{if(n.has(i))continue;n.set(i),o(i,t,n)}})},function(e,t){e.exports=((e,t,n,o)=>{const r=[...e.values()];for(const s of r)if(s&&"object"==typeof s)if(t.has(s))e.delete(s),e.add(t.get(s));else{if(n.has(s))continue;n.set(s),o(s,t,n)}})},function(e,t){e.exports=((e,t,n,o)=>{const r=Object.getOwnPropertyDescriptors(e);Object.entries(r).forEach(([r,s])=>{if(s.set||s.get)return;const{value:i}=s;if(i&&"object"==typeof i)if(t.has(i))e[r]=t.get(i);else{if(n.has(i))return;n.set(i),o(i,t,n)}})})},function(e,t,n){const o=n(12),r=n(13),s=n(14);e.exports=function(e,t,n,i,c,f){return function(e,t,n,c,a){const{mapEntries:u,setEntries:p,ownPropsDcps:l}=t;if(u)return o(e,u,n,i,c,a,f);if(p)return r(e,p,n,i,a,f);if(l)return s(e,l,n,i,c,a,f);throw new Error("wrong data parameter for innerPropsHandler function")}(e,t,n,new WeakMap,c)}},function(e,t,n){const o=n(0),r=n(1),s=n(2),i=n(3),c=n(4);e.exports=((e,t,n,f,a,u,p)=>{const l=t,{discardErrorObjects:y}=n;for(const[t,d]of l)if(d&&"object"==typeof d){const l=c(u,d);if(l){e.set(t,l);continue}if(d instanceof Error){o(y);continue}if(d instanceof Number||d instanceof Boolean||d instanceof String){e.set(t,i(d));continue}if(d instanceof Date){const n=s(d);e.set(t,n),a.set(d,n);continue}if(d instanceof RegExp){const n=r(d);e.set(t,n),a.set(d,n);continue}if(d instanceof Promise){e.set(t,d);continue}if(d instanceof WeakMap){e.set(t,d);continue}if(d instanceof WeakSet){e.set(t,d);continue}e.set(t,p(d,n,u,f)),a.set(d,e.get(t))}else e.set(t,d)})},function(e,t,n){const o=n(0),r=n(1),s=n(2),i=n(3),c=n(4);e.exports=((e,t,n,f,a,u)=>{const p=t,{discardErrorObjects:l}=n;for(const t of p)if(t&&"object"==typeof t){const p=c(a,t);if(p){e.add(p);continue}if(t instanceof Error){o(l);continue}if(t instanceof Number||t instanceof Boolean||t instanceof String){e.add(i(t));continue}if(t instanceof Date){const n=s(t);e.add(n);continue}if(t instanceof RegExp){const n=r(t);e.add(n);continue}if(t instanceof Promise){e.add(t);continue}if(t instanceof WeakMap){e.add(t);continue}if(t instanceof WeakSet){e.add(t);continue}const y=u(t,n,a,f);e.add(y)}else e.add(t)})},function(e,t,n){const o=n(0),r=n(1),s=n(2),i=n(3),c=n(4);e.exports=((e,t,n,f,a,u,p)=>{const l=t,{copyNonEnumerables:y,copySymbols:d,copyGettersSetters:b,discardErrorObjects:E}=n;Object.entries(l).forEach(([t,l])=>{const{value:w,enumerable:j}=l;if((y||j)&&(d||"symbol"!=typeof t)&&(b||!l.get&&!l.set))if(w&&"object"==typeof w){const y=c(u,w);if(y)return void(e[t]=y);if(w instanceof Error)return void o(E);if(w instanceof Number||w instanceof Boolean||w instanceof String){const n=i(w);return void Object.defineProperty(e,t,{...l,...{value:n}})}if(w instanceof Date){const n=s(w);return Object.defineProperty(e,t,{...l,...{value:n}}),void a.set(w,n)}if(w instanceof RegExp){const n=r(w);return Object.defineProperty(e,t,{...l,...{value:n}}),void a.set(w,n)}if(w instanceof Promise)return void Object.defineProperty(e,t,l);if(w instanceof WeakMap)return void Object.defineProperty(e,t,l);if(w instanceof WeakSet)return void Object.defineProperty(e,t,l);e[t]=p(w,n,u,f),a.set(w,e[t])}else{const n=Object.getOwnPropertyDescriptor(e,t);n&&!n.configurable||Object.defineProperty(e,t,l)}})})},function(e,t){e.exports=((e,t=!1,n=!1)=>{const o=new Set,r=new Map;return function e(s){o.add(s);const i=new Set;if(s instanceof Map)[...s.entries()].forEach(([,t])=>{"object"==typeof t&&(i.add(t),o.has(t)||e(t))});else if(s instanceof Set)[...s.values()].forEach(t=>{"object"==typeof t&&(i.add(t),o.has(t)||e(t))});else if(t||n){const r=Object.getOwnPropertyDescriptors(s);Object.entries(r).forEach(([r,s])=>{if(s.set||s.get)return;if(!1===s.enumerable&&!1===t)return;if("symbol"==typeof r&&!1===n)return;const{value:c}=s;c&&"object"==typeof c&&(i.add(c),o.has(c)||e(c))})}else Object.values(s).forEach(t=>{"object"==typeof t&&(i.add(t),o.has(t)||e(t))});r.set(s,i)}(e),r})},function(e,t){e.exports=function(e){return function e(t){if(0===t.size)return t;const n=[...t.entries()].find(([,e])=>0===e.size);if(!n)return t;const[o]=n;return function(e,t){[...t.entries()].forEach(([,t])=>{t.has(e)&&t.delete(e)})}(o,t),t.delete(o),e(t)}(e).size}}]); \ No newline at end of file diff --git a/package.json b/package.json index 046edd7..63df4ff 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "omniclone", - "version": "0.6.0", + "version": "0.7.0", "description": "deep cloning function for js objects", "main": "dist/main.js", "scripts": { diff --git a/src/deepClone.js b/src/deepClone.js index 8c52a31..a460580 100644 --- a/src/deepClone.js +++ b/src/deepClone.js @@ -2,10 +2,10 @@ const updateReferences = require("./updateReferences"); const propsHandler = require("./propsHandler"); function deepClone(source, config) { - // circular references guard + // already visited references map // each analized object will store its reference here - // so we can check each of its object properties to see if there are - // reference to already analized objects + // so we can check each of its chilren object to see if there are + // references to already analized objects const references = new WeakMap(); // A reference to the initial source object @@ -102,13 +102,15 @@ function deepClone(source, config) { ); } + // each time an object is cloned I update the references map + // with its new reference. The object could still have some old circ refs + // but I'll handle this later + references.set(source, res); + // circular references update from temp old values to new ones + // we don't it if allowCircularReferences is false because the previous check + // in omniclone.js would have trown an error if (allowCircularReferences) { - // each time an object is cloned I update the references map - // with its new reference. The object could still have some old circ refs - // but I'll handle this later - references.set(source, res); - if (start === source) { // if I've recursively handled all 'virtual' children // I've completely updated the references map diff --git a/src/handlers/mapEntriesHandler.js b/src/handlers/mapEntriesHandler.js index fae9e09..f693d21 100644 --- a/src/handlers/mapEntriesHandler.js +++ b/src/handlers/mapEntriesHandler.js @@ -2,8 +2,7 @@ const errorObjectsHandler = require("./errorsObjectsHandler"); const regexpObjectsHandler = require("./regexpObjectsHanlder"); const dateObjectsHandler = require("./dateObjectsHandler"); const primitiveObjectsHandler = require("./primitiveObjectsHandler"); -const circReferencesHelper = require("./../utility/circReferencesHelper"); -const safeReferencesHelper = require("./../utility/safeReferencesHelper"); +const prevReferencesHelper = require("./../utility/prevReferencesHelper"); module.exports = ( res, @@ -16,42 +15,17 @@ module.exports = ( ) => { const mapEntries = data; - const { allowCircularReferences, discardErrorObjects } = config; + const { discardErrorObjects } = config; for (const [key, value] of mapEntries) { if (value && typeof value === "object") { - // check for duplicated sibiling object references - const safeReference = safeReferencesHelper(safeReferences, value); - if (safeReference) { - res.set(key, safeReference); + // check if I've already found this object + const prevRef = prevReferencesHelper(references, value); + if (prevRef) { + res.set(key, prevRef); continue; } - // check for circular references - const circRef = circReferencesHelper( - references, - value, - allowCircularReferences - ); - if (circRef) { - res.set(key, circRef); - continue; - } - - if (references.has(value)) { - if (!allowCircularReferences) { - throw new TypeError("TypeError: circular reference found"); - } else { - // if circulary references are allowed - // the temporary result is exactly the circ referred object - // it could be an 'old' object (map included) - // or an already copied object with or without - // some 'old' circ references inside it - res.set(key, references.get(value)); - continue; - } - } - // check discardErrorObjects flag to see how to handle Error objects if (value instanceof Error) { errorObjectsHandler(discardErrorObjects); diff --git a/src/handlers/otherObjectsDescriptorsHandler.js b/src/handlers/otherObjectsDescriptorsHandler.js index f1e492c..b5eb094 100644 --- a/src/handlers/otherObjectsDescriptorsHandler.js +++ b/src/handlers/otherObjectsDescriptorsHandler.js @@ -2,8 +2,7 @@ const errorObjectsHandler = require("./errorsObjectsHandler"); const regexpObjectsHandler = require("./regexpObjectsHanlder"); const dateObjectsHandler = require("./dateObjectsHandler"); const primitiveObjectsHandler = require("./primitiveObjectsHandler"); -const circReferencesHelper = require("./../utility/circReferencesHelper"); -const safeReferencesHelper = require("./../utility/safeReferencesHelper"); +const prevReferencesHelper = require("./../utility/prevReferencesHelper"); module.exports = ( res, @@ -20,7 +19,6 @@ module.exports = ( copyNonEnumerables, copySymbols, copyGettersSetters, - allowCircularReferences, discardErrorObjects } = config; @@ -44,21 +42,10 @@ module.exports = ( if (!copyGettersSetters && (descriptor.get || descriptor.set)) return; if (value && typeof value === "object") { - // check for duplicated sibiling object references - const safeReference = safeReferencesHelper(safeReferences, value); - if (safeReference) { - res[prop] = safeReference; - return; - } - - // check for circular references - - const circRef = circReferencesHelper( - references, - value, - allowCircularReferences - ); - if (circRef) { - res[prop] = circRef; + // check if I've already found this object + const prevRef = prevReferencesHelper(references, value); + if (prevRef) { + res[prop] = prevRef; return; } diff --git a/src/handlers/setEntriesHandler.js b/src/handlers/setEntriesHandler.js index 2996a79..a41056e 100644 --- a/src/handlers/setEntriesHandler.js +++ b/src/handlers/setEntriesHandler.js @@ -2,7 +2,7 @@ const errorObjectsHandler = require("./errorsObjectsHandler"); const regexpObjectsHandler = require("./regexpObjectsHanlder"); const dateObjectsHandler = require("./dateObjectsHandler"); const primitiveObjectsHandler = require("./primitiveObjectsHandler"); -const circReferencesHelper = require("./../utility/circReferencesHelper"); +const prevReferencesHelper = require("./../utility/prevReferencesHelper"); module.exports = ( res, @@ -14,20 +14,16 @@ module.exports = ( ) => { const setEntries = data; - const { allowCircularReferences, discardErrorObjects } = config; + const { discardErrorObjects } = config; // for set key == value for (const value of setEntries) { if (value && typeof value === "object") { - // check for circular references - const circRef = circReferencesHelper( - references, - value, - allowCircularReferences - ); - if (circRef) { - res.add(circRef); + // check if I've already found this object + const prevRef = prevReferencesHelper(references, value); + if (prevRef) { + res.add(prevRef); continue; } diff --git a/src/omniclone.js b/src/omniclone.js index 16951de..17fe77a 100644 --- a/src/omniclone.js +++ b/src/omniclone.js @@ -13,7 +13,7 @@ function omniclone( copyNonEnumerables = false, copySymbols = false, copyGettersSetters = false, - allowCircularReferences = false, + allowCircularReferences = true, discardErrorObjects = true } = {} ) { @@ -85,7 +85,8 @@ function omniclone( // so we have to force the allowCircularReferences if there are not const depsMap = createDependenciesMap(obj, copyNonEnumerables, copySymbols); // eslint-disable-next-line no-param-reassign - allowCircularReferences = checkCircRef(depsMap); + if (checkCircRef(depsMap)) + throw new TypeError("TypeError: circular reference found"); } const config = { diff --git a/src/utility/circReferencesHelper.js b/src/utility/circReferencesHelper.js deleted file mode 100644 index 941c42b..0000000 --- a/src/utility/circReferencesHelper.js +++ /dev/null @@ -1,16 +0,0 @@ -module.exports = (references, value, allowCircularReferencesFlag) => { - if (references.has(value)) { - if (!allowCircularReferencesFlag) { - throw new TypeError("TypeError: circular reference found"); - } else { - // if circulary references are allowed - // the temporary result returned is exactly the circ referred object - // it could be an 'old' object (map included) - // or an already copied object with or without - // some 'old' circ references inside it - return references.get(value); // is an object, that is always a truthy value - } - } else { - return null; - } -}; diff --git a/src/utility/dependenciesMapHandler.js b/src/utility/dependenciesMapHandler.js index 93cc299..88931d4 100644 --- a/src/utility/dependenciesMapHandler.js +++ b/src/utility/dependenciesMapHandler.js @@ -43,7 +43,7 @@ function dependenciesMapHandler(map) { } function checkCircRefs(map) { - return !dependenciesMapHandler(map).size; + return dependenciesMapHandler(map).size; } module.exports = checkCircRefs; diff --git a/src/utility/prevReferencesHelper.js b/src/utility/prevReferencesHelper.js new file mode 100644 index 0000000..001eee2 --- /dev/null +++ b/src/utility/prevReferencesHelper.js @@ -0,0 +1,8 @@ +module.exports = (references, value) => { + if (references.has(value)) { + // if I've previously found thid object value + // I can return it because I've stored it in the references map + return references.get(value); // is an object, that is always a truthy value + } + return null; +};