@@ -35,8 +35,8 @@ const JSONPatcherProxy = (function() {
3535 * @param {Object } obj the object you need to find its path
3636 */
3737 function findObjectPath ( instance , obj ) {
38- var pathComponents = [ ] ;
39- var parentAndPath = instance . parenthoodMap . get ( obj ) ;
38+ const pathComponents = [ ] ;
39+ let parentAndPath = instance . parenthoodMap . get ( obj ) ;
4040 while ( parentAndPath && parentAndPath . path ) {
4141 // because we're walking up-tree, we need to use the array as a stack
4242 pathComponents . unshift ( parentAndPath . path ) ;
@@ -59,17 +59,17 @@ const JSONPatcherProxy = (function() {
5959 function setTrap ( instance , target , key , newValue ) {
6060 const parentPath = findObjectPath ( instance , target ) ;
6161
62- var destinationPropKey = parentPath + '/' + escapePathComponent ( key ) ;
63- {
64- if ( instance . proxifiedObjectsMap . has ( newValue ) ) {
65- var newValueOriginalObject = instance . proxifiedObjectsMap . get ( newValue ) ;
62+ const destinationPropKey = parentPath + '/' + escapePathComponent ( key ) ;
6663
67- instance . parenthoodMap . set ( newValueOriginalObject . originalObject , {
68- parent : target ,
69- path : key
70- } ) ;
71- }
72- /*
64+ if ( instance . proxifiedObjectsMap . has ( newValue ) ) {
65+ const newValueOriginalObject = instance . proxifiedObjectsMap . get ( newValue ) ;
66+
67+ instance . parenthoodMap . set ( newValueOriginalObject . originalObject , {
68+ parent : target ,
69+ path : key
70+ } ) ;
71+ }
72+ /*
7373 mark already proxified values as inherited.
7474 rationale: proxy.arr.shift()
7575 will emit
@@ -79,22 +79,22 @@ const JSONPatcherProxy = (function() {
7979 by default, the second operation would revoke the proxy, and this renders arr revoked.
8080 That's why we need to remember the proxies that are inherited.
8181 */
82- const revokableInstance = instance . proxifiedObjectsMap . get ( newValue ) ;
83- /*
84- Why do we need to check instance.isProxifyingTreeNow?
82+ const revokableInstance = instance . proxifiedObjectsMap . get ( newValue ) ;
83+ /*
84+ Why do we need to check instance.isProxifyingTreeNow?
8585
86- We need to make sure we mark revokables as inherited ONLY when we're observing,
87- because throughout the first proxification, a sub-object is proxified and then assigned to
88- its parent object. This assignment of a pre-proxified object can fool us into thinking
89- that it's a proxified object moved around, while in fact it's the first assignment ever.
86+ We need to make sure we mark revokables as inherited ONLY when we're observing,
87+ because throughout the first proxification, a sub-object is proxified and then assigned to
88+ its parent object. This assignment of a pre-proxified object can fool us into thinking
89+ that it's a proxified object moved around, while in fact it's the first assignment ever.
9090
91- Checking isProxifyingTreeNow ensures this is not happening in the first proxification,
92- but in fact is is a proxified object moved around the tree
93- */
94- if ( revokableInstance && ! instance . isProxifyingTreeNow ) {
95- revokableInstance . inherited = true ;
96- }
91+ Checking isProxifyingTreeNow ensures this is not happening in the first proxification,
92+ but in fact is is a proxified object moved around the tree
93+ */
94+ if ( revokableInstance && ! instance . isProxifyingTreeNow ) {
95+ revokableInstance . inherited = true ;
9796 }
97+
9898 // if the new value is an object, make sure to watch it
9999 if (
100100 newValue &&
@@ -107,70 +107,46 @@ const JSONPatcherProxy = (function() {
107107 } ) ;
108108 newValue = instance . _proxifyObjectTreeRecursively ( target , newValue , key ) ;
109109 }
110+ // let's start with this operation, and may or may not update it later
111+ const operation = {
112+ op : 'remove' ,
113+ path : destinationPropKey
114+ } ;
110115 if ( typeof newValue == 'undefined' ) {
111- if ( target . hasOwnProperty ( key ) ) {
116+ // applying De Morgan's laws would be a tad faster, but less readable
117+ if ( ! Array . isArray ( target ) && ! target . hasOwnProperty ( key ) ) {
118+ // `undefined` is being set to an already undefined value, keep silent
119+ return Reflect . set ( target , key , newValue ) ;
120+ } else {
112121 // when array element is set to `undefined`, should generate replace to `null`
113122 if ( Array . isArray ( target ) ) {
114- //undefined array elements are JSON.stringified to `null`
115- instance . defaultCallback ( {
116- op : 'replace' ,
117- path : destinationPropKey ,
118- value : null
119- } ) ;
120- } else {
121- instance . defaultCallback ( {
122- op : 'remove' ,
123- path : destinationPropKey
124- } ) ;
123+ // undefined array elements are JSON.stringified to `null`
124+ ( operation . op = 'replace' ) , ( operation . value = null ) ;
125125 }
126126 const oldValue = instance . proxifiedObjectsMap . get ( target [ key ] ) ;
127127 // was the deleted a proxified object?
128- if ( oldValue ) {
128+ if ( oldValue ) {
129129 instance . parenthoodMap . delete ( target [ key ] ) ;
130130 instance . disableTrapsForProxy ( oldValue ) ;
131131 instance . proxifiedObjectsMap . delete ( oldValue ) ;
132132 }
133- return Reflect . set ( target , key , newValue ) ;
134- } else if ( ! Array . isArray ( target ) ) {
133+ }
134+ } else {
135+ if ( Array . isArray ( target ) && ! Number . isInteger ( + key . toString ( ) ) ) {
136+ /* array props (as opposed to indices) don't emit any patches, to avoid needless `length` patches */
135137 return Reflect . set ( target , key , newValue ) ;
136138 }
137- }
138- /* array props don't emit any patches, to avoid needless `length` patches */
139- if ( Array . isArray ( target ) && ! Number . isInteger ( + key . toString ( ) ) ) {
140- return Reflect . set ( target , key , newValue ) ;
141- }
142- if ( target . hasOwnProperty ( key ) ) {
143- if ( typeof target [ key ] == 'undefined' ) {
144- if ( Array . isArray ( target ) ) {
145- instance . defaultCallback ( {
146- op : 'replace' ,
147- path : destinationPropKey ,
148- value : newValue
149- } ) ;
150- } else {
151- instance . defaultCallback ( {
152- op : 'add' ,
153- path : destinationPropKey ,
154- value : newValue
155- } ) ;
139+ operation . op = 'add' ;
140+ if ( target . hasOwnProperty ( key ) ) {
141+ if ( typeof target [ key ] !== 'undefined' || Array . isArray ( target ) ) {
142+ operation . op = 'replace' ; // setting `undefined` array elements is a `replace` op
156143 }
157- return Reflect . set ( target , key , newValue ) ;
158- } else {
159- instance . defaultCallback ( {
160- op : 'replace' ,
161- path : destinationPropKey ,
162- value : newValue
163- } ) ;
164- return Reflect . set ( target , key , newValue ) ;
165144 }
166- } else {
167- instance . defaultCallback ( {
168- op : 'add' ,
169- path : destinationPropKey ,
170- value : newValue
171- } ) ;
172- return Reflect . set ( target , key , newValue ) ;
145+ operation . value = newValue ;
173146 }
147+ const reflectionResult = Reflect . set ( target , key , newValue ) ;
148+ instance . defaultCallback ( operation ) ;
149+ return reflectionResult ;
174150 }
175151 /**
176152 * A callback to be used as th proxy delete trap callback.
@@ -182,13 +158,8 @@ const JSONPatcherProxy = (function() {
182158 function deleteTrap ( instance , target , key ) {
183159 if ( typeof target [ key ] !== 'undefined' ) {
184160 const parentPath = findObjectPath ( instance , target ) ;
185-
186161 const destinationPropKey = parentPath + '/' + escapePathComponent ( key ) ;
187162
188- instance . defaultCallback ( {
189- op : 'remove' ,
190- path : destinationPropKey
191- } ) ;
192163 const revokableProxyInstance = instance . proxifiedObjectsMap . get (
193164 target [ key ]
194165 ) ;
@@ -197,7 +168,7 @@ const JSONPatcherProxy = (function() {
197168 if ( revokableProxyInstance . inherited ) {
198169 /*
199170 this is an inherited proxy (an already proxified object that was moved around),
200- we shouldn't revoke it, because even though it was removed from path1, it is indeed used in path2.
171+ we shouldn't revoke it, because even though it was removed from path1, it is still used in path2.
201172 And we know that because we mark moved proxies with `inherited` flag when we move them
202173
203174 it is a good idea to remove this flag if we come across it here, in deleteProperty trap.
@@ -210,8 +181,15 @@ const JSONPatcherProxy = (function() {
210181 instance . proxifiedObjectsMap . delete ( target [ key ] ) ;
211182 }
212183 }
184+ const reflectionResult = Reflect . deleteProperty ( target , key ) ;
185+
186+ instance . defaultCallback ( {
187+ op : 'remove' ,
188+ path : destinationPropKey
189+ } ) ;
190+
191+ return reflectionResult ;
213192 }
214- return Reflect . deleteProperty ( target , key ) ;
215193 }
216194 /* pre-define resume and pause functions to enhance constructors performance */
217195 function resume ( ) {
@@ -263,11 +241,10 @@ const JSONPatcherProxy = (function() {
263241 if ( ! obj ) {
264242 return obj ;
265243 }
266- const instance = this ;
267244 const traps = {
268245 set : ( target , key , value , receiver ) =>
269- setTrap ( instance , target , key , value , receiver ) ,
270- deleteProperty : ( target , key ) => deleteTrap ( instance , target , key )
246+ setTrap ( this , target , key , value , receiver ) ,
247+ deleteProperty : ( target , key ) => deleteTrap ( this , target , key )
271248 } ;
272249 const revocableInstance = Proxy . revocable ( obj , traps ) ;
273250 // cache traps object to disable them later.
0 commit comments