From 8455a586ecf09f50abe3ee8add37464a9feccfe9 Mon Sep 17 00:00:00 2001 From: ahmedkandel Date: Fri, 27 Mar 2020 13:52:28 +0100 Subject: [PATCH 1/2] Fix issue with array methods that re-assign indexes --- src/reactive-handler.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/reactive-handler.ts b/src/reactive-handler.ts index 6a4e631..93e47c0 100644 --- a/src/reactive-handler.ts +++ b/src/reactive-handler.ts @@ -71,8 +71,16 @@ export class ReactiveProxyHandler { return membrane.getProxy(value); } set(shadowTarget: ReactiveMembraneShadowTarget, key: PropertyKey, value: any): boolean { - const { originalTarget, membrane: { valueMutated } } = this; + const { originalTarget, membrane: { valueMutated, valueIsObservable, unwrapProxy } } = this; const oldValue = originalTarget[key]; + if (isArray(originalTarget) && valueIsObservable(value) && originalTarget.includes(unwrapProxy(value))) { + // fix issue #44 using array methods that re-assign indexes + // like (splice, shift, unshift, sort, reverse) + // will get() re-assigned items wrapped with proxy. + // So it will replace originalTarget items with proxies. + // This to unwrap those proxies and assign the original value. + value = unwrapProxy(value); + } if (oldValue !== value) { originalTarget[key] = value; valueMutated(originalTarget, key); From 436caf254973ede93447a27a42e8eb98b7e61c76 Mon Sep 17 00:00:00 2001 From: ahmedkandel Date: Sat, 28 Mar 2020 16:28:59 +0100 Subject: [PATCH 2/2] make unwrapProxy method more safe for read-only proxies and use it for set trap --- src/reactive-handler.ts | 19 ++++++------------- src/reactive-membrane.ts | 8 +++++++- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/reactive-handler.ts b/src/reactive-handler.ts index 93e47c0..f7b13d3 100644 --- a/src/reactive-handler.ts +++ b/src/reactive-handler.ts @@ -1,7 +1,6 @@ import { toString, isUndefined, - unwrap, ArrayConcat, isArray, ObjectDefineProperty, @@ -29,9 +28,9 @@ function wrapValue(membrane: ReactiveMembrane, value: any): any { * We only need to unwrap if value is specified * @param descriptor external descrpitor provided to define new property on original value */ -function unwrapDescriptor(descriptor: PropertyDescriptor): PropertyDescriptor { +function unwrapDescriptor(membrane: ReactiveMembrane, descriptor: PropertyDescriptor): PropertyDescriptor { if (hasOwnProperty.call(descriptor, 'value')) { - descriptor.value = unwrap(descriptor.value); + descriptor.value = membrane.unwrapProxy(descriptor.value); } return descriptor; } @@ -71,16 +70,10 @@ export class ReactiveProxyHandler { return membrane.getProxy(value); } set(shadowTarget: ReactiveMembraneShadowTarget, key: PropertyKey, value: any): boolean { - const { originalTarget, membrane: { valueMutated, valueIsObservable, unwrapProxy } } = this; + const { originalTarget, membrane } = this; const oldValue = originalTarget[key]; - if (isArray(originalTarget) && valueIsObservable(value) && originalTarget.includes(unwrapProxy(value))) { - // fix issue #44 using array methods that re-assign indexes - // like (splice, shift, unshift, sort, reverse) - // will get() re-assigned items wrapped with proxy. - // So it will replace originalTarget items with proxies. - // This to unwrap those proxies and assign the original value. - value = unwrapProxy(value); - } + const { valueMutated } = membrane; + value = membrane.unwrapProxy(value); if (oldValue !== value) { originalTarget[key] = value; valueMutated(originalTarget, key); @@ -190,7 +183,7 @@ export class ReactiveProxyHandler { const originalDescriptor = getOwnPropertyDescriptor(originalTarget, key) as PropertyDescriptor; descriptor.value = originalDescriptor.value; } - ObjectDefineProperty(originalTarget, key, unwrapDescriptor(descriptor)); + ObjectDefineProperty(originalTarget, key, unwrapDescriptor(membrane, descriptor)); if (configurable === false) { ObjectDefineProperty(shadowTarget, key, wrapDescriptor(membrane, descriptor, wrapValue)); } diff --git a/src/reactive-membrane.ts b/src/reactive-membrane.ts index e7311da..faaad51 100644 --- a/src/reactive-membrane.ts +++ b/src/reactive-membrane.ts @@ -140,7 +140,13 @@ export class ReactiveMembrane { } unwrapProxy(p: any) { - return unwrap(p); + const unwrapped = unwrap(p); + const distorted = this.valueDistortion(unwrapped); + const reactiveState = this.objectGraph.get(distorted); + if (reactiveState && reactiveState.readOnly === p) { + return p; + } + return distorted; } private getReactiveState(value: any, distortedValue: any): ReactiveState {