From d3fcd074bd65af6dba15928e1cfa83949ed1fd35 Mon Sep 17 00:00:00 2001 From: Chris Garrett Date: Tue, 13 Oct 2020 14:36:21 -0700 Subject: [PATCH] [BUGFIX lts] Restores the shadowed property set behavior Restores the previous behavior that would happen when setting a shadowed property. --- .../@ember/-internals/metal/lib/decorator.ts | 9 ++++++++- .../@ember/-internals/metal/lib/property_set.ts | 15 ++++++++++----- packages/@ember/-internals/metal/lib/tracked.ts | 3 +++ .../-internals/metal/tests/tracked/set_test.js | 16 ++++++++++++++++ 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/packages/@ember/-internals/metal/lib/decorator.ts b/packages/@ember/-internals/metal/lib/decorator.ts index 4ed14028884..a1e84c286a1 100644 --- a/packages/@ember/-internals/metal/lib/decorator.ts +++ b/packages/@ember/-internals/metal/lib/decorator.ts @@ -1,5 +1,6 @@ import { Meta, meta as metaFor, peekMeta } from '@ember/-internals/meta'; import { assert } from '@ember/debug'; +import { _WeakSet } from '@ember/polyfills'; export type DecoratorPropertyDescriptor = PropertyDescriptor & { initializer?: any } | undefined; @@ -79,11 +80,17 @@ function DESCRIPTOR_SETTER_FUNCTION( name: string, descriptor: ComputedDescriptor ): (value: any) => void { - return function CPSETTER_FUNCTION(this: object, value: any): void { + let set = function CPSETTER_FUNCTION(this: object, value: any): void { return descriptor.set(this, name, value); }; + + COMPUTED_SETTERS.add(set); + + return set; } +export const COMPUTED_SETTERS = new _WeakSet(); + export function makeComputedDecorator( desc: ComputedDescriptor, DecoratorClass: { prototype: object } diff --git a/packages/@ember/-internals/metal/lib/property_set.ts b/packages/@ember/-internals/metal/lib/property_set.ts index aef085266ed..06dc123f910 100644 --- a/packages/@ember/-internals/metal/lib/property_set.ts +++ b/packages/@ember/-internals/metal/lib/property_set.ts @@ -1,8 +1,13 @@ -import { HAS_NATIVE_PROXY, setWithMandatorySetter, toString } from '@ember/-internals/utils'; +import { + HAS_NATIVE_PROXY, + lookupDescriptor, + setWithMandatorySetter, + toString, +} from '@ember/-internals/utils'; import { assert } from '@ember/debug'; import EmberError from '@ember/error'; import { DEBUG } from '@glimmer/env'; -import { descriptorForProperty } from './decorator'; +import { COMPUTED_SETTERS } from './decorator'; import { isPath } from './path_cache'; import { notifyPropertyChange } from './property_events'; import { _getPath as getPath, getPossibleMandatoryProxyValue } from './property_get'; @@ -67,10 +72,10 @@ export function set(obj: object, keyName: string, value: any, tolerant?: boolean return setPath(obj, keyName, value, tolerant); } - let descriptor = descriptorForProperty(obj, keyName); + let descriptor = lookupDescriptor(obj, keyName); - if (descriptor !== undefined) { - descriptor.set(obj, keyName, value); + if (descriptor !== null && COMPUTED_SETTERS.has(descriptor.set!)) { + obj[keyName] = value; return value; } diff --git a/packages/@ember/-internals/metal/lib/tracked.ts b/packages/@ember/-internals/metal/lib/tracked.ts index d85a2636271..b111ff679dc 100644 --- a/packages/@ember/-internals/metal/lib/tracked.ts +++ b/packages/@ember/-internals/metal/lib/tracked.ts @@ -5,6 +5,7 @@ import { DEBUG } from '@glimmer/env'; import { consumeTag, dirtyTagFor, tagFor, trackedData } from '@glimmer/validator'; import { CHAIN_PASS_THROUGH } from './chain-tags'; import { + COMPUTED_SETTERS, Decorator, DecoratorPropertyDescriptor, isElementDescriptor, @@ -182,6 +183,8 @@ function descriptorForField([target, key, desc]: [ set, }; + COMPUTED_SETTERS.add(set); + metaFor(target).writeDescriptors(key, new TrackedDescriptor(get, set)); return newDesc; diff --git a/packages/@ember/-internals/metal/tests/tracked/set_test.js b/packages/@ember/-internals/metal/tests/tracked/set_test.js index 5b9eaa9a84d..389bcf0ec6a 100644 --- a/packages/@ember/-internals/metal/tests/tracked/set_test.js +++ b/packages/@ember/-internals/metal/tests/tracked/set_test.js @@ -31,5 +31,21 @@ moduleFor( assert.equal(get(newObj, key), obj[key], 'should set value'); } } + + ['@test set should not throw an error when setting on shadowed properties'](assert) { + class Obj { + @tracked value = 'emberjs'; + + constructor() { + Object.defineProperty(this, 'value', { writable: true, value: 'emberjs' }); + } + } + + let newObj = new Obj(); + + set(newObj, 'value', 123); + + assert.equal(newObj.value, 123, 'it worked'); + } } );