Skip to content

Commit

Permalink
Don't duplicate the base class when using constantSuper
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolo-ribaudo committed May 14, 2021
1 parent 3195883 commit f52b06b
Show file tree
Hide file tree
Showing 10 changed files with 77 additions and 33 deletions.
23 changes: 20 additions & 3 deletions packages/babel-helper-create-class-features-plugin/src/fields.js
Expand Up @@ -672,7 +672,7 @@ const thisContextVisitor = traverse.visitors.merge([
function replaceThisContext(
path,
ref,
superRef,
getSuperRef,
file,
isStaticBlock,
constantSuper,
Expand All @@ -682,9 +682,9 @@ function replaceThisContext(
const replacer = new ReplaceSupers({
methodPath: path,
constantSuper,
superRef,
file,
refToPreserve: ref,
getSuperRef,
getObjectRef() {
state.needsClassRef = true;
return isStaticBlock || path.node.static
Expand All @@ -710,11 +710,20 @@ export function buildFieldsInitNodes(
constantSuper,
) {
let needsClassRef = false;
let injectSuperRef;
const staticNodes = [];
const instanceNodes = [];
// These nodes are pure and can be moved to the closest statement position
const pureStaticNodes = [];

const getSuperRef = t.isIdentifier(superRef)
? () => superRef
: () => {
injectSuperRef ??=
props[0].scope.generateUidIdentifierBasedOnNode(superRef);
return injectSuperRef;
};

for (const prop of props) {
ts.assertFieldTransformed(prop);

Expand All @@ -730,7 +739,7 @@ export function buildFieldsInitNodes(
const replaced = replaceThisContext(
prop,
ref,
superRef,
getSuperRef,
state,
isStaticBlock,
constantSuper,
Expand Down Expand Up @@ -865,6 +874,14 @@ export function buildFieldsInitNodes(
prop.remove();
}

if (injectSuperRef) {
path.scope.push({ id: t.cloneNode(injectSuperRef) });
path.set(
"superClass",
t.assignmentExpression("=", injectSuperRef, path.node.superClass),
);
}

if (!needsClassRef) return path;

if (path.isClassExpression()) {
Expand Down
45 changes: 23 additions & 22 deletions packages/babel-helper-replace-supers/src/index.ts
Expand Up @@ -206,22 +206,20 @@ const looseHandlers = {
},

get(superMember) {
const { isStatic, superRef } = this;
const { isStatic, getSuperRef } = this;
const { computed } = superMember.node;
const prop = this.prop(superMember);

let object;
if (isStatic) {
object = superRef
? t.cloneNode(superRef)
: t.memberExpression(
t.identifier("Function"),
t.identifier("prototype"),
);
object =
getSuperRef() ??
t.memberExpression(t.identifier("Function"), t.identifier("prototype"));
} else {
object = superRef
? t.memberExpression(t.cloneNode(superRef), t.identifier("prototype"))
: t.memberExpression(t.identifier("Object"), t.identifier("prototype"));
object = t.memberExpression(
getSuperRef() ?? t.identifier("Object"),
t.identifier("prototype"),
);
}

return t.memberExpression(object, prop, computed);
Expand Down Expand Up @@ -264,15 +262,15 @@ type ReplaceSupersOptionsBase = {
refToPreserve?: t.Identifier;
};

type ReplaceSupersOptions =
| ({
objectRef?: undefined;
getObjectRef: () => t.Node;
} & ReplaceSupersOptionsBase)
| ({
objectRef: t.Node;
getObjectRef?: () => t.Node;
} & ReplaceSupersOptionsBase);
type ReplaceSupersOptions = ReplaceSupersOptionsBase &
(
| { objectRef?: undefined; getObjectRef: () => t.Node }
| { objectRef: t.Node; getObjectRef?: undefined }
) &
(
| { superRef?: undefined; getSuperRef: () => t.Node }
| { superRef: t.Node; getSuperRef?: undefined }
);

export default class ReplaceSupers {
constructor(opts: ReplaceSupersOptions) {
Expand All @@ -286,7 +284,6 @@ export default class ReplaceSupers {
this.isPrivateMethod = path.isPrivate() && path.isMethod();

this.file = opts.file;
this.superRef = opts.superRef;
this.constantSuper = process.env.BABEL_8_BREAKING
? opts.constantSuper
: // Fallback to isLoose for backward compatibility
Expand All @@ -301,12 +298,16 @@ export default class ReplaceSupers {
declare isStatic: boolean;
declare methodPath: NodePath;
declare opts: ReplaceSupersOptions;
declare superRef: any;

getObjectRef() {
return t.cloneNode(this.opts.objectRef || this.opts.getObjectRef());
}

getSuperRef() {
if (this.opts.superRef) return t.cloneNode(this.opts.superRef);
if (this.opts.getSuperRef) return t.cloneNode(this.opts.getSuperRef());
}

replace() {
// https://github.com/babel/babel/issues/11994
if (this.opts.refToPreserve) {
Expand All @@ -324,7 +325,7 @@ export default class ReplaceSupers {
isStatic: this.isStatic,
isPrivateMethod: this.isPrivateMethod,
getObjectRef: this.getObjectRef.bind(this),
superRef: this.superRef,
getSuperRef: this.getSuperRef.bind(this),
...handler,
});
}
Expand Down
@@ -0,0 +1,3 @@
class A extends class B {} {
static x = super.x;
}
@@ -0,0 +1,5 @@
var _B;

class A extends (_B = class B {}) {}

babelHelpers.defineProperty(A, "x", _B.x);
@@ -0,0 +1,3 @@
class A extends B {
foo = super.bar;
}
@@ -0,0 +1,7 @@
class A extends B {
constructor(...args) {
super(...args);
babelHelpers.defineProperty(this, "foo", super.bar);
}

}
@@ -0,0 +1,6 @@
{
"assumptions": {
"constantSuper": true
},
"plugins": ["proposal-class-properties"]
}
@@ -0,0 +1,3 @@
class A extends B {
static foo = super.bar;
}
@@ -0,0 +1,3 @@
class A extends B {}

babelHelpers.defineProperty(A, "foo", B.bar);
@@ -1,17 +1,13 @@
var _class, _temp;
var _ref, _class, _temp;

class Foo extends (_temp = _class = class {}, (() => {
class Foo extends (_ref = (_temp = _class = class _ref {}, (() => {
_class.bar = 42;
})(), _temp) {}
})(), _temp)) {}

Foo.bar = 21;

(() => {
var _class2, _temp2;

Foo.foo = (_temp2 = _class2 = class {}, (() => {
_class2.bar = 42;
})(), _temp2).bar;
Foo.foo = _ref.bar;
})();

expect(Foo.foo).toBe(42);

0 comments on commit f52b06b

Please sign in to comment.