diff --git a/lib/6to5/file.js b/lib/6to5/file.js index fd8117e65f..d7f0fe91b3 100644 --- a/lib/6to5/file.js +++ b/lib/6to5/file.js @@ -49,7 +49,8 @@ File.helpers = [ "interop-require-wildcard", "typeof", "extends", - "get" + "get", + "set" ]; File.validOptions = [ diff --git a/lib/6to5/transformation/helpers/replace-supers.js b/lib/6to5/transformation/helpers/replace-supers.js index 5c70d64c57..1b990479d8 100644 --- a/lib/6to5/transformation/helpers/replace-supers.js +++ b/lib/6to5/transformation/helpers/replace-supers.js @@ -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])) { diff --git a/lib/6to5/transformation/templates/set.js b/lib/6to5/transformation/templates/set.js new file mode 100644 index 0000000000..f00cb746a8 --- /dev/null +++ b/lib/6to5/transformation/templates/set.js @@ -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); + } +}); diff --git a/test/fixtures/esnext/es6-classes/getter-setter-super.js b/test/fixtures/esnext/es6-classes/getter-setter-super.js index a1974f8335..218ccbd2fe 100644 --- a/test/fixtures/esnext/es6-classes/getter-setter-super.js +++ b/test/fixtures/esnext/es6-classes/getter-setter-super.js @@ -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; + } + + set name(val) { + super.name = val + ' Cat'; + } } -assert.equal(new Cat().sound, 'I am a cat. MEOW!'); +var cat = new Cat(); + +assert.equal(cat.sound, 'I am a cat. MEOW!'); +cat.name = 'Nyan'; +assert.equal(cat.name, 'Nyan Cat');