diff --git a/lib/6to5/file.js b/lib/6to5/file.js index f9a6eb7d5e..a9777e7b91 100644 --- a/lib/6to5/file.js +++ b/lib/6to5/file.js @@ -39,7 +39,8 @@ File.helpers = [ "interop-require-wildcard", "typeof", "extends", - "get" + "get", + "set" ]; File.excludeHelpersFromRuntime = [ diff --git a/lib/6to5/transformation/helpers/replace-supers.js b/lib/6to5/transformation/helpers/replace-supers.js index 2403e878cb..d15d9c4f28 100644 --- a/lib/6to5/transformation/helpers/replace-supers.js +++ b/lib/6to5/transformation/helpers/replace-supers.js @@ -24,6 +24,36 @@ function ReplaceSupers(methodNode, className, superName, isLoose, file) { this.file = 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), + t.identifier(value.name), + thisExpression + ] + ); +}; + /** * Gets a node representing the super class value of the named property. * @@ -194,6 +224,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)) { @@ -221,11 +252,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 76004a0881..5b9693298c 100644 --- a/test/fixtures/esnext/es6-classes/getter-setter-super.js +++ b/test/fixtures/esnext/es6-classes/getter-setter-super.js @@ -21,6 +21,10 @@ class Cat extends Animal { return super.sound + ' MEOW!'; } + get name() { + return super.name; + } + set name(val) { super.name = val; this._name += ' Cat'; @@ -31,4 +35,4 @@ var cat = new Cat(); assert.equal(cat.sound, 'I am a cat. MEOW!'); cat.name = 'Nyan'; -assert.equal(new Cat().name, 'Nyan Cat'); +assert.equal(cat.name, 'Nyan Cat');