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

fix(class-properties): replace new.target in static properties with undefined #13560

Merged
merged 7 commits into from Jul 16, 2021
20 changes: 20 additions & 0 deletions packages/babel-helper-create-class-features-plugin/src/fields.ts
@@ -1,4 +1,5 @@
import { template, traverse, types as t } from "@babel/core";
import type { NodePath } from "@babel/traverse";
import ReplaceSupers, {
environmentVisitor,
} from "@babel/helper-replace-supers";
Expand Down Expand Up @@ -665,6 +666,24 @@ const thisContextVisitor = traverse.visitors.merge([
state.needsClassRef = true;
path.replaceWith(t.cloneNode(state.classRef));
},
Function(path: NodePath<t.Function>, state) {
// only `() => { new.target }` needs to be replaced
state.shouldReplaceNewTarget = path.isArrowFunctionExpression();
},
MetaProperty(path: NodePath<t.MetaProperty>, state) {
const meta = path.get("meta");
const property = path.get("property");
const { scope } = path;
// if there are `new.target` in static field
// we should replace it with `undefined`
if (
state.shouldReplaceNewTarget &&
nicolo-ribaudo marked this conversation as resolved.
Show resolved Hide resolved
meta.isIdentifier({ name: "new" }) &&
property.isIdentifier({ name: "target" })
) {
path.replaceWith(scope.buildUndefinedNode());
}
},
},
environmentVisitor,
]);
Expand Down Expand Up @@ -693,6 +712,7 @@ function replaceThisContext(
classRef: ref,
needsClassRef: false,
innerBinding: innerBindingRef,
shouldReplaceNewTarget: true,
};

const replacer = new ReplaceSupers({
Expand Down
@@ -0,0 +1,13 @@
class Base {
constructor() {
var _class, _temp;

this.Foo = (_temp = _class = class {}, (() => {
// fixme: new.target should be undefined after transformed
Copy link
Member

Choose a reason for hiding this comment

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

Nit: you can delete this comment from input.js

_class.foo = void 0;
})(), _temp);
}

}

expect(new Base().Foo.foo).toBe(undefined);
@@ -0,0 +1,9 @@
class Foo {
constructor() {
this.Bar = class {
static p = new.target
}
}
}

expect((new Foo).Bar.p).toBeUndefined()
@@ -0,0 +1,20 @@
class Foo {
constructor() {
this.Bar = class {
static p = new.target
static p1 = class { constructor() { new.target } } // should not replace
static p2 = new function () { new.target } // should not replace
static p3 = () => { new.target } // should replace
static p4 = function () { new.target } // should not replace
q = new.target // should not replace
}
}

test = function() {
new.target;
};

test2 = () => {
new.target;
}
}
@@ -0,0 +1,7 @@
{
"plugins": [
"transform-new-target",
"transform-arrow-functions",
["proposal-class-properties", { "loose": true }]
]
}
@@ -0,0 +1,35 @@
class Foo {
constructor() {
var _newtarget = this.constructor,
_class,
_temp;

this.test = function _target() {
this instanceof _target ? this.constructor : void 0;
};

this.test2 = function () {
_newtarget;
};

this.Bar = (_temp = _class = class _target2 {
constructor() {
this.q = this.constructor;
} // should not replace


}, _class.p = void 0, _class.p1 = class _target3 {
constructor() {
this.constructor;
}

}, _class.p2 = new function _target4() {
this instanceof _target4 ? this.constructor : void 0;
}(), _class.p3 = function () {
void 0;
}, _class.p4 = function _target5() {
this instanceof _target5 ? this.constructor : void 0;
}, _temp);
}

}
@@ -0,0 +1,9 @@
class Foo {
constructor() {
this.Bar = class {
static p = new.target
}
}
}

expect((new Foo).Bar.p).toBeUndefined()
@@ -1,4 +1,15 @@
class Foo {
constructor() {
this.Bar = class {
static p = new.target
static p1 = class { constructor() { new.target } } // should not replace
static p2 = new function () { new.target } // should not replace
static p3 = () => { new.target } // should replace
static p4 = function () { new.target } // should not replace
q = new.target // should not replace
}
}

test = function() {
new.target;
};
Expand Down
Expand Up @@ -2,6 +2,6 @@
"plugins": [
"transform-new-target",
"transform-arrow-functions",
["proposal-class-properties", { "loose": true }]
["proposal-class-properties", { "loose": false }]
colinaaa marked this conversation as resolved.
Show resolved Hide resolved
]
}
@@ -1,14 +1,33 @@
class Foo {
constructor() {
var _newtarget = this.constructor;
var _newtarget = this.constructor,
_class,
_temp;

this.test = function _target() {
babelHelpers.defineProperty(this, "test", function _target() {
this instanceof _target ? this.constructor : void 0;
};

this.test2 = function () {
});
babelHelpers.defineProperty(this, "test2", function () {
_newtarget;
};
});
this.Bar = (_temp = _class = class _target2 {
constructor() {
babelHelpers.defineProperty(this, "q", this.constructor);
} // should not replace


}, babelHelpers.defineProperty(_class, "p", void 0), babelHelpers.defineProperty(_class, "p1", class _target3 {
constructor() {
this.constructor;
}

}), babelHelpers.defineProperty(_class, "p2", new function _target4() {
this instanceof _target4 ? this.constructor : void 0;
}()), babelHelpers.defineProperty(_class, "p3", function () {
void 0;
}), babelHelpers.defineProperty(_class, "p4", function _target5() {
this instanceof _target5 ? this.constructor : void 0;
}), _temp);
}

}