Class instance properties define their own context (#6158)

This commit is contained in:
Justin Ridgewell
2017-08-28 14:47:17 -04:00
committed by Henry Zhu
parent 960151c876
commit ac6eda2709
15 changed files with 261 additions and 23 deletions

View File

@@ -52,6 +52,10 @@ const visitor = {
if (!path.isArrowFunctionExpression()) path.skip();
},
ClassProperty(path) {
if (!path.node.static) path.skip();
},
ReturnStatement(path, state) {
if (!path.getFunctionParent().isArrowFunctionExpression()) {
state.returns.push(path);

View File

@@ -0,0 +1,3 @@
class Foo {
static fn = () => console.log(this);
}

View File

@@ -0,0 +1,7 @@
var _this = this;
class Foo {
static fn = function () {
return console.log(_this);
};
}

View File

@@ -0,0 +1,3 @@
{
"plugins": ["external-helpers", "transform-es2015-arrow-functions", "syntax-class-properties"]
}

View File

@@ -0,0 +1,3 @@
class Foo {
fn = () => console.log(this);
}

View File

@@ -0,0 +1,4 @@
{
"plugins": ["external-helpers", "transform-es2015-arrow-functions", "syntax-class-properties"],
"throws": "Unable to transform arrow inside class property"
}

View File

@@ -0,0 +1,28 @@
() => {
class Foo {
fn = () => console.log(this);
static fn = () => console.log(this);
}
};
() => class Bar {
fn = () => console.log(this);
static fn = () => console.log(this);
};
() => {
class Baz {
fn = () => console.log(this);
force = force
static fn = () => console.log(this);
constructor(force) {}
}
};
var qux = function() {
class Qux {
fn = () => console.log(this);
static fn = () => console.log(this);
}
}.bind(this)

View File

@@ -0,0 +1,121 @@
var _this = this;
(function () {
class Foo {
constructor() {
var _this2 = this;
Object.defineProperty(this, "fn", {
configurable: true,
enumerable: true,
writable: true,
value: function () {
return console.log(_this2);
}
});
}
}
Object.defineProperty(Foo, "fn", {
configurable: true,
enumerable: true,
writable: true,
value: function () {
return console.log(_this);
}
});
});
(function () {
var _class, _temp;
return _temp = _class = class Bar {
constructor() {
var _this3 = this;
Object.defineProperty(this, "fn", {
configurable: true,
enumerable: true,
writable: true,
value: function () {
return console.log(_this3);
}
});
}
}, Object.defineProperty(_class, "fn", {
configurable: true,
enumerable: true,
writable: true,
value: function () {
return console.log(_this);
}
}), _temp;
});
(function () {
class Baz {
constructor(force) {
_initialiseProps.call(this);
}
}
Object.defineProperty(Baz, "fn", {
configurable: true,
enumerable: true,
writable: true,
value: function () {
return console.log(_this);
}
});
var _initialiseProps = function () {
var _this4 = this;
Object.defineProperty(this, "fn", {
configurable: true,
enumerable: true,
writable: true,
value: function () {
return console.log(_this4);
}
});
Object.defineProperty(this, "force", {
configurable: true,
enumerable: true,
writable: true,
value: force
});
};
});
var qux = function () {
var _this6 = this;
class Qux {
constructor() {
var _this5 = this;
Object.defineProperty(this, "fn", {
configurable: true,
enumerable: true,
writable: true,
value: function () {
return console.log(_this5);
}
});
}
}
Object.defineProperty(Qux, "fn", {
configurable: true,
enumerable: true,
writable: true,
value: function () {
return console.log(_this6);
}
});
}.bind(this);

View File

@@ -0,0 +1,3 @@
{
"plugins": ["external-helpers", "transform-class-properties", "transform-es2015-arrow-functions"]
}

View File

@@ -0,0 +1,8 @@
class Test {
constructor() {
class Other extends Test {
a = () => super.test;
static a = () => super.test;
}
}
}

View File

@@ -0,0 +1,53 @@
"use strict";
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Test = function Test() {
var _this2 = this;
_classCallCheck(this, Test);
var Other = function (_Test) {
_inherits(Other, _Test);
function Other() {
var _ref;
var _temp, _this;
_classCallCheck(this, Other);
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return _possibleConstructorReturn(_this, (_temp = _this = _possibleConstructorReturn(this, (_ref = Other.__proto__ || Object.getPrototypeOf(Other)).call.apply(_ref, [this].concat(args))), Object.defineProperty(_this, "a", {
configurable: true,
enumerable: true,
writable: true,
value: function value() {
return _get(Other.prototype.__proto__ || Object.getPrototypeOf(Other.prototype), "test", _this);
}
}), _temp));
}
return Other;
}(Test);
Object.defineProperty(Other, "a", {
configurable: true,
enumerable: true,
writable: true,
value: function value() {
return _get(Test.prototype.__proto__ || Object.getPrototypeOf(Test.prototype), "test", _this2);
}
});
};

View File

@@ -0,0 +1,3 @@
{
"presets": ["es2015", "stage-2"]
}

View File

@@ -0,0 +1,3 @@
{
"plugins": ["external-helpers", ["transform-class-properties", {"loose": true}], "transform-es2015-classes", "transform-es2015-block-scoping", "syntax-class-properties"]
}

View File

@@ -123,7 +123,7 @@ function hoistFunctionEnvironment(
p =>
(p.isFunction() && !p.isArrowFunctionExpression()) ||
p.isProgram() ||
p.isClassProperty(),
p.isClassProperty({ static: false }),
);
const inConstructor = thisEnvFn && thisEnvFn.node.kind === "constructor";
@@ -148,28 +148,22 @@ function hoistFunctionEnvironment(
"Unable to handle nested super() usage in arrow",
);
}
const allSuperCalls = [];
thisEnvFn.traverse({
Function: child => {
if (
child.isArrowFunctionExpression() ||
child.isClassProperty() ||
child === fnPath
) {
return;
}
Function(child) {
if (child.isArrowFunctionExpression()) return;
child.skip();
},
ClassProperty(child) {
if (child.node.static) return;
child.skip();
},
CallExpression(child) {
if (!child.get("callee").isSuper()) return;
allSuperCalls.push(child);
},
});
const superBinding = getSuperBinding(thisEnvFn);
allSuperCalls.forEach(superCall =>
superCall.get("callee").replaceWith(t.identifier(superBinding)),
);
@@ -399,15 +393,12 @@ function getThisBinding(thisEnvFn, inConstructor) {
const supers = new WeakSet();
thisEnvFn.traverse({
Function: child => {
if (
child.isArrowFunctionExpression() ||
child.isClassProperty() ||
child === this
) {
return;
}
Function(child) {
if (child.isArrowFunctionExpression()) return;
child.skip();
},
ClassProperty(child) {
if (child.node.static) return;
child.skip();
},
CallExpression(child) {
@@ -529,8 +520,12 @@ function getScopeInformation(fnPath) {
const superCalls = [];
fnPath.traverse({
ClassProperty(child) {
if (child.node.static) return;
child.skip();
},
Function(child) {
if (child.isArrowFunctionExpression() || child.isClassProperty()) return;
if (child.isArrowFunctionExpression()) return;
child.skip();
},
ThisExpression(child) {