diff --git a/packages/@ember/-internals/metal/lib/alias.ts b/packages/@ember/-internals/metal/lib/alias.ts index a681b2c86cb..74b70a88105 100644 --- a/packages/@ember/-internals/metal/lib/alias.ts +++ b/packages/@ember/-internals/metal/lib/alias.ts @@ -3,7 +3,7 @@ import { inspect } from '@ember/-internals/utils'; import { assert } from '@ember/debug'; import EmberError from '@ember/error'; import { ComputedProperty } from './computed'; -import { getCacheFor } from './computed_cache'; +import { getCachedValueFor, getCacheFor } from './computed_cache'; import { addDependentKeys, DescriptorWithDependentKeys, @@ -34,33 +34,44 @@ export class AliasedProperty extends Descriptor implements DescriptorWithDepende super.setup(obj, keyName); let meta = metaFor(obj); if (meta.peekWatching(keyName) > 0) { - addDependentKeys(this, obj, keyName, meta); + this.consume(obj, keyName, meta); } } teardown(obj: object, keyName: string, meta: Meta): void { - if (meta.peekWatching(keyName) > 0) { - removeDependentKeys(this, obj, keyName, meta); - } + this.unconsume(obj, keyName, meta); } willWatch(obj: object, keyName: string, meta: Meta): void { - addDependentKeys(this, obj, keyName, meta); + this.consume(obj, keyName, meta); } didUnwatch(obj: object, keyName: string, meta: Meta) { - removeDependentKeys(this, obj, keyName, meta); + this.unconsume(obj, keyName, meta); } get(obj: object, keyName: string) { let ret = get(obj, this.altKey); + this.consume(obj, keyName, metaFor(obj)); + return ret; + } + + unconsume(obj: object, keyName: string, meta: Meta) { + let wasConsumed = getCachedValueFor(obj, keyName) === CONSUMED; + if (wasConsumed || meta.peekWatching(keyName) > 0) { + removeDependentKeys(this, obj, keyName, meta); + } + if (wasConsumed) { + getCacheFor(obj).delete(keyName); + } + } + + consume(obj: object, keyName: string, meta: Meta) { let cache = getCacheFor(obj); if (cache.get(keyName) !== CONSUMED) { - let meta = metaFor(obj); cache.set(keyName, CONSUMED); addDependentKeys(this, obj, keyName, meta); } - return ret; } set(obj: object, _keyName: string, value: any) { diff --git a/packages/@ember/-internals/metal/tests/alias_test.js b/packages/@ember/-internals/metal/tests/alias_test.js index 777f24c4668..9dbb186ea48 100644 --- a/packages/@ember/-internals/metal/tests/alias_test.js +++ b/packages/@ember/-internals/metal/tests/alias_test.js @@ -116,5 +116,52 @@ moduleFor( "Setting alias 'bar' on self" ); } + + ['@test destroyed alias does not disturb watch count'](assert) { + defineProperty(obj, 'bar', alias('foo.faz')); + + assert.equal(get(obj, 'bar'), 'FOO'); + assert.ok(isWatching(obj, 'foo.faz')); + + defineProperty(obj, 'bar', null); + + assert.notOk(isWatching(obj, 'foo.faz')); + } + + ['@test setting on oneWay alias does not disturb watch count'](assert) { + defineProperty(obj, 'bar', alias('foo.faz').oneWay()); + + assert.equal(get(obj, 'bar'), 'FOO'); + assert.ok(isWatching(obj, 'foo.faz')); + + set(obj, 'bar', null); + + assert.notOk(isWatching(obj, 'foo.faz')); + } + + ['@test redefined alias with observer does not disturb watch count'](assert) { + defineProperty(obj, 'bar', alias('foo.faz').oneWay()); + + assert.equal(get(obj, 'bar'), 'FOO'); + assert.ok(isWatching(obj, 'foo.faz')); + + addObserver(obj, 'bar', incrementCount); + + assert.equal(count, 0); + + set(obj, 'bar', null); + + assert.equal(count, 1); + assert.notOk(isWatching(obj, 'foo.faz')); + + defineProperty(obj, 'bar', alias('foo.faz')); + + assert.equal(count, 1); + assert.ok(isWatching(obj, 'foo.faz')); + + set(obj, 'foo.faz', 'great'); + + assert.equal(count, 2); + } } );