Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Descriptor #14138

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 37 additions & 41 deletions packages/ember-metal/lib/alias.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,64 +18,60 @@ export default function alias(altKey) {
return new AliasedProperty(altKey);
}

export function AliasedProperty(altKey) {
this.isDescriptor = true;
this.altKey = altKey;
this._dependentKeys = [altKey];
}
export class AliasedProperty extends Descriptor {
constructor(altKey) {
super();
this.altKey = altKey;
this._dependentKeys = [altKey];
}

setup(obj, keyName, isWatching, meta) {
assert(`Setting alias '${keyName}' on self`, this.altKey !== keyName);

AliasedProperty.prototype = Object.create(Descriptor.prototype);
super.setup(obj, keyName, isWatching);

AliasedProperty.prototype.setup = function(obj, keyName) {
assert(`Setting alias '${keyName}' on self`, this.altKey !== keyName);
let meta = metaFor(obj);
if (meta.peekWatching(keyName)) {
addDependentKeys(this, obj, keyName, meta);
if (isWatching) {
addDependentKeys(this, obj, keyName, meta);
}
}
};

AliasedProperty.prototype._addDependentKeyIfMissing = function(obj, keyName) {
let meta = metaFor(obj);
if (!meta.peekDeps(this.altKey, keyName)) {
addDependentKeys(this, obj, keyName, meta);
teardown(obj, keyName, isWatching, meta) {
if (isWatching) {
removeDependentKeys(this, obj, keyName, meta);
}
}
};

AliasedProperty.prototype._removeDependentKeyIfAdded = function(obj, keyName) {
let meta = metaFor(obj);
if (meta.peekDeps(this.altKey, keyName)) {
removeDependentKeys(this, obj, keyName, meta);
get(obj, keyName) {
return get(obj, this.altKey);
}
};

AliasedProperty.prototype.willWatch = AliasedProperty.prototype._addDependentKeyIfMissing;
AliasedProperty.prototype.didUnwatch = AliasedProperty.prototype._removeDependentKeyIfAdded;
AliasedProperty.prototype.teardown = AliasedProperty.prototype._removeDependentKeyIfAdded;
set(obj, keyName, value) {
return set(obj, this.altKey, value);
}

AliasedProperty.prototype.get = function AliasedProperty_get(obj, keyName) {
this._addDependentKeyIfMissing(obj, keyName);
willWatch(obj, keyName) {
addDependentKeys(this, obj, keyName, meta(obj));
}

return get(obj, this.altKey);
};
didUnwatch(obj, keyName) {
removeDependentKeys(this, obj, keyName, meta(obj));
}

AliasedProperty.prototype.set = function AliasedProperty_set(obj, keyName, value) {
return set(obj, this.altKey, value);
};
readOnly() {
this.set = AliasedProperty_readOnlySet;
return this;
}

AliasedProperty.prototype.readOnly = function() {
this.set = AliasedProperty_readOnlySet;
return this;
};
oneWay() {
this.set = AliasedProperty_oneWaySet;
return this;
}
}

function AliasedProperty_readOnlySet(obj, keyName, value) {
throw new EmberError(`Cannot set read-only property '${keyName}' on object: ${inspect(obj)}`);
}

AliasedProperty.prototype.oneWay = function() {
this.set = AliasedProperty_oneWaySet;
return this;
};

function AliasedProperty_oneWaySet(obj, keyName, value) {
defineProperty(obj, keyName, null);
return set(obj, keyName, value);
Expand Down
3 changes: 1 addition & 2 deletions packages/ember-metal/lib/computed.js
Original file line number Diff line number Diff line change
Expand Up @@ -435,11 +435,10 @@ ComputedPropertyPrototype._set = function computedPropertySet(obj, keyName, valu
};

/* called before property is overridden */
ComputedPropertyPrototype.teardown = function(obj, keyName) {
ComputedPropertyPrototype.teardown = function(obj, keyName, isWatching, meta) {
if (this._volatile) {
return;
}
let meta = metaFor(obj);
let cache = meta.readableCache();
if (cache && cache[keyName] !== undefined) {
removeDependentKeys(this, obj, keyName, meta);
Expand Down
19 changes: 11 additions & 8 deletions packages/ember-metal/lib/mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ function applyMergedProperties(obj, key, value, values) {
}

function addNormalizedProperty(base, key, value, meta, descs, values, concats, mergings) {
if (value instanceof Descriptor) {
if (typeof value === 'object' && value && value.isDescriptor) {
if (value === REQUIRED && descs[key]) { return CONTINUE; }

// Wrap descriptor function to implement
Expand Down Expand Up @@ -661,8 +661,11 @@ Mixin.mixins = function(obj) {
return ret;
};

const REQUIRED = new Descriptor();
REQUIRED.toString = function() { return '(Required Property)'; };
const REQUIRED = new (class extends Descriptor {
toString() {
return '(Required Property)';
}
});

/**
Denotes a required property for a mixin
Expand All @@ -680,13 +683,13 @@ export function required() {
return REQUIRED;
}

function Alias(methodName) {
this.isDescriptor = true;
this.methodName = methodName;
class Alias extends Descriptor {
constructor() {
super();
this.methodName = methodName;
}
}

Alias.prototype = new Descriptor();

/**
Makes a method available via an additional name.

Expand Down
86 changes: 45 additions & 41 deletions packages/ember-metal/lib/properties.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,29 @@ import { overrideChains } from './property_events';
@class Descriptor
@private
*/
export function Descriptor() {
this.isDescriptor = true;
export class Descriptor {
constructor() {
this.isDescriptor = true;
}

setup(obj, key, isWatching) {
if (isEnabled('mandatory-setter')) {
if (isWatching) {
Object.defineProperty(obj, key, {
configurable: true,
enumerable: true,
writable: true,
value: this
});
} else {
obj[key] = this;
}
} else {
obj[key] = this;
}
}

teardown(obj, key, isWatching) {}
}

const REDEFINE_SUPPORTED = (function () {
Expand Down Expand Up @@ -139,58 +160,41 @@ export function defineProperty(obj, keyName, desc, data, meta) {
watching = watchEntry !== undefined && watchEntry > 0;

if (existingDesc) {
existingDesc.teardown(obj, keyName);
existingDesc.teardown(obj, keyName, watching, meta);
}

if (desc instanceof Descriptor) {
value = desc;
if (desc === null || desc === undefined) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This branch was just moved up, mostly unchanged. The condition was previously if (desc == null) – note the double equal.

value = data;

if (isEnabled('mandatory-setter')) {
if (watching) {
Object.defineProperty(obj, keyName, {
meta.writeValues(keyName, data);

let defaultDescriptor = {
configurable: true,
enumerable: true,
writable: true,
value: value
});
} else {
obj[keyName] = value;
}
} else {
obj[keyName] = value;
}
if (desc.setup) { desc.setup(obj, keyName); }
} else {
if (desc == null) {
value = data;

if (isEnabled('mandatory-setter')) {
if (watching) {
meta.writeValues(keyName, data);

let defaultDescriptor = {
configurable: true,
enumerable: true,
set: MANDATORY_SETTER_FUNCTION(keyName),
get: DEFAULT_GETTER_FUNCTION(keyName)
};

if (REDEFINE_SUPPORTED) {
Object.defineProperty(obj, keyName, defaultDescriptor);
} else {
handleBrokenPhantomDefineProperty(obj, keyName, defaultDescriptor);
}
set: MANDATORY_SETTER_FUNCTION(keyName),
get: DEFAULT_GETTER_FUNCTION(keyName)
};

if (REDEFINE_SUPPORTED) {
Object.defineProperty(obj, keyName, defaultDescriptor);
} else {
obj[keyName] = data;
handleBrokenPhantomDefineProperty(obj, keyName, defaultDescriptor);
}
} else {
obj[keyName] = data;
}
} else {
value = desc;

// fallback to ES5
Object.defineProperty(obj, keyName, desc);
obj[keyName] = data;
}
} else if (desc.isDescriptor) {
value = desc;
desc.setup(obj, keyName, watching, meta);
} else {
// fallback to ES5
value = desc;
Object.defineProperty(obj, keyName, desc);
}

// if key is being watched, override chains that
Expand Down