Merge pull request #582 from kruppel/kurt/setter-super

Support use of super inside instance setter.
This commit is contained in:
Sebastian McKenzie 2015-01-30 21:47:24 +11:00
commit 1cbbe00b7a
4 changed files with 86 additions and 3 deletions

View File

@ -49,7 +49,8 @@ File.helpers = [
"interop-require-wildcard",
"typeof",
"extends",
"get"
"get",
"set"
];
File.validOptions = [

View File

@ -21,6 +21,36 @@ function ReplaceSupers(opts) {
this.file = opts.file;
}
/**
* Sets a super class value of the named property.
*
* @example
*
* _set(Object.getPrototypeOf(CLASS.prototype), "METHOD", "VALUE", this)
*
* @param {Node} property
* @param {boolean} isStatic
* @param {boolean} isComputed
*
* @returns {Node}
*/
ReplaceSupers.prototype.setSuperProperty = function (property, value, isStatic, isComputed, thisExpression) {
return t.callExpression(
this.file.addHelper("set"),
[
t.callExpression(
t.memberExpression(t.identifier("Object"), t.identifier("getPrototypeOf")),
[
isStatic ? this.className : t.memberExpression(this.className, t.identifier("prototype"))
]
),
isComputed ? property : t.literal(property.name),
value,
thisExpression
]
);
};
/**
* Gets a node representing the super class value of the named property.
*
@ -191,6 +221,7 @@ ReplaceSupers.prototype.specHandle = function (getThisReference, node, parent) {
var property;
var computed;
var args;
var thisReference;
if (t.isIdentifier(node, { name: "super" })) {
if (!(t.isMemberExpression(parent) && !parent.computed && parent.property === node)) {
@ -226,11 +257,18 @@ ReplaceSupers.prototype.specHandle = function (getThisReference, node, parent) {
// super.name; -> _get(Object.getPrototypeOf(ClassName.prototype), "name", this);
property = node.property;
computed = node.computed;
} else if (t.isAssignmentExpression(node)) {
if (!t.isIdentifier(node.left.object, { name: "super" })) return;
if (methodNode.kind !== 'set') return;
thisReference = getThisReference();
// super.name = "val"; -> _set(Object.getPrototypeOf(ClassName.prototype), "name", this);
return this.setSuperProperty(node.left.property, node.right, methodNode.static, node.left.computed, thisReference);
}
if (!property) return;
var thisReference = getThisReference();
thisReference = getThisReference();
var superProperty = this.superProperty(property, methodNode.static, computed, thisReference);
if (args) {
if (args.length === 1 && t.isSpreadElement(args[0])) {

View File

@ -0,0 +1,24 @@
(function set(object, property, value, receiver) {
var desc = Object.getOwnPropertyDescriptor(object, property);
if (desc === undefined) {
var parent = Object.getPrototypeOf(object);
if (parent === null) {
return;
} else {
return set(parent, property, value, receiver);
}
} else if ("value" in desc && desc.writable) {
desc.value = value;
return;
} else {
var setter = desc.set;
if (setter === undefined) {
return;
}
return setter.call(receiver, value);
}
});

View File

@ -2,6 +2,14 @@ class Base {
get sound() {
return 'I am a ' + this.type + '.';
}
get name() {
return this._name;
}
set name(val) {
this._name = val;
}
}
class Animal extends Base {}
@ -12,6 +20,18 @@ class Cat extends Animal {
get sound() {
return super.sound + ' MEOW!';
}
get name() {
return super.name;
}
assert.equal(new Cat().sound, 'I am a cat. MEOW!');
set name(val) {
super.name = val + ' Cat';
}
}
var cat = new Cat();
assert.equal(cat.sound, 'I am a cat. MEOW!');
cat.name = 'Nyan';
assert.equal(cat.name, 'Nyan Cat');