Skip to content

Commit

Permalink
fix(class-properties): replace new.target in static properties with…
Browse files Browse the repository at this point in the history
… `undefined` (babel#13560)

* fix(class-properties): replace `new.target` in static properties with `undefined`

non-static prop is not affected

fix babel#12737

* Update packages/babel-helper-create-class-features-plugin/src/fields.ts

fix typo

Co-authored-by: Brian Ng <bng412@gmail.com>

* fix: add loose test case and fix replace condition

* test: add new.target tests for static block

* feat: move new-target replace into thisContextVisitor

defaults to replace new.target, do not replace within function

* feat: simplify thisContextVisitor

remove function visitor since environmentVisitor is skipping arrow function

* test: remove unused fixme comments

Co-authored-by: Brian Ng <bng412@gmail.com>
  • Loading branch information
2 people authored and nicolo-ribaudo committed Jul 30, 2021
1 parent bb3722c commit 0910a28
Show file tree
Hide file tree
Showing 12 changed files with 143 additions and 8 deletions.
14 changes: 14 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,19 @@ const thisContextVisitor = traverse.visitors.merge([
state.needsClassRef = true;
path.replaceWith(t.cloneNode(state.classRef));
},
MetaProperty(path: NodePath<t.MetaProperty>) {
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 (
meta.isIdentifier({ name: "new" }) &&
property.isIdentifier({ name: "target" })
) {
path.replaceWith(scope.buildUndefinedNode());
}
},
},
environmentVisitor,
]);
Expand Down
Expand Up @@ -2,7 +2,6 @@ class Base {
constructor() {
this.Foo = class {
static {
// fixme: new.target should be undefined after transformed
this.foo = new.target;
}
}
Expand Down
@@ -0,0 +1,12 @@
class Base {
constructor() {
var _class, _temp;

this.Foo = (_temp = _class = class {}, (() => {
_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 }]
]
}
@@ -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);
}

}

0 comments on commit 0910a28

Please sign in to comment.