[decorators] Correctly insert _initialize(this) after super(). (#8970)
* [decorators] Correctly insert `_initialize(this)` after `super()`. This commit fixes to problem: 1) After `super();` statements, `_initialize(this)` was inserted without a trailing semicolon. 2) `(0, super())` causes an infinite recursion. * Fix tests * Add test
This commit is contained in:
parent
5d5cd8612f
commit
b706e34fc8
@ -113,6 +113,10 @@ const bareSupersVisitor = {
|
||||
CallExpression(path, { initializeInstanceElements }) {
|
||||
if (path.get("callee").isSuper()) {
|
||||
path.insertAfter(t.cloneNode(initializeInstanceElements));
|
||||
|
||||
// Sometimes this path gets requeued (e.g. in (super(), foo)), and
|
||||
// it leads to infinite recursion.
|
||||
path.skip();
|
||||
}
|
||||
},
|
||||
Function(path) {
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
@decorator(parameter)
|
||||
class Sub extends Super {
|
||||
constructor() {
|
||||
super().method();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
let Sub = babelHelpers.decorate([decorator(parameter)], function (_initialize, _Super) {
|
||||
"use strict";
|
||||
|
||||
class Sub extends _Super {
|
||||
constructor() {
|
||||
var _temp;
|
||||
|
||||
(_temp = super(), _initialize(this), _temp).method();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
F: Sub,
|
||||
d: []
|
||||
};
|
||||
}, Super);
|
||||
@ -0,0 +1,7 @@
|
||||
@dec
|
||||
class B extends A {
|
||||
constructor() {
|
||||
super();
|
||||
[];
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
let B = babelHelpers.decorate([dec], function (_initialize, _A) {
|
||||
"use strict";
|
||||
|
||||
class B extends _A {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
_initialize(this);
|
||||
|
||||
[];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
F: B,
|
||||
d: []
|
||||
};
|
||||
}, A);
|
||||
@ -0,0 +1,6 @@
|
||||
@dec
|
||||
class B extends A {
|
||||
constructor() {
|
||||
(0, super());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
let B = babelHelpers.decorate([dec], function (_initialize, _A) {
|
||||
"use strict";
|
||||
|
||||
class B extends _A {
|
||||
constructor() {
|
||||
var _temp;
|
||||
|
||||
0, (_temp = super(), _initialize(this), _temp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
F: B,
|
||||
d: []
|
||||
};
|
||||
}, A);
|
||||
@ -0,0 +1,14 @@
|
||||
@dec
|
||||
class B extends A {
|
||||
constructor() {
|
||||
const foo = () => { super(); };
|
||||
|
||||
if (a) { super(); }
|
||||
else { foo(); }
|
||||
|
||||
while (0) { super(); }
|
||||
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,37 @@
|
||||
let B = babelHelpers.decorate([dec], function (_initialize, _A) {
|
||||
"use strict";
|
||||
|
||||
class B extends _A {
|
||||
constructor() {
|
||||
const foo = () => {
|
||||
super();
|
||||
|
||||
_initialize(this);
|
||||
};
|
||||
|
||||
if (a) {
|
||||
super();
|
||||
|
||||
_initialize(this);
|
||||
} else {
|
||||
foo();
|
||||
}
|
||||
|
||||
while (0) {
|
||||
super();
|
||||
|
||||
_initialize(this);
|
||||
}
|
||||
|
||||
super();
|
||||
|
||||
_initialize(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
F: B,
|
||||
d: []
|
||||
};
|
||||
}, A);
|
||||
@ -0,0 +1,6 @@
|
||||
@dec
|
||||
class B extends A {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
let B = babelHelpers.decorate([dec], function (_initialize, _A) {
|
||||
"use strict";
|
||||
|
||||
class B extends _A {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
_initialize(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
F: B,
|
||||
d: []
|
||||
};
|
||||
}, A);
|
||||
@ -105,7 +105,17 @@ export function insertAfter(nodes) {
|
||||
parentPath.isExportNamedDeclaration() ||
|
||||
(parentPath.isExportDefaultDeclaration() && this.isDeclaration())
|
||||
) {
|
||||
return parentPath.insertAfter(nodes);
|
||||
return parentPath.insertAfter(
|
||||
nodes.map(node => {
|
||||
// Usually after an expression we can safely insert another expression:
|
||||
// A.insertAfter(B)
|
||||
// foo = A; -> foo = (A, B);
|
||||
// If A is an expression statement, it isn't safe anymore so we need to
|
||||
// convert B to an expression statement
|
||||
// A; -> A; B // No semicolon! It could break if followed by [!
|
||||
return t.isExpression(node) ? t.expressionStatement(node) : node;
|
||||
}),
|
||||
);
|
||||
} else if (
|
||||
(this.isNodeType("Expression") && !this.isJSXElement()) ||
|
||||
(parentPath.isForStatement() && this.key === "init")
|
||||
|
||||
@ -235,7 +235,9 @@ describe("modification", function() {
|
||||
fnPath.insertAfter(t.identifier("x"));
|
||||
|
||||
expect(bodyPath.get("body")).toHaveLength(2);
|
||||
expect(bodyPath.get("body.1").node).toEqual(t.identifier("x"));
|
||||
expect(bodyPath.get("body.1").node).toEqual(
|
||||
t.expressionStatement(t.identifier("x")),
|
||||
);
|
||||
});
|
||||
|
||||
it("the ExportDefaultDeclaration, if a declaration is exported", function() {
|
||||
@ -246,7 +248,9 @@ describe("modification", function() {
|
||||
fnPath.insertAfter(t.identifier("x"));
|
||||
|
||||
expect(bodyPath.get("body")).toHaveLength(2);
|
||||
expect(bodyPath.get("body.1").node).toEqual(t.identifier("x"));
|
||||
expect(bodyPath.get("body.1").node).toEqual(
|
||||
t.expressionStatement(t.identifier("x")),
|
||||
);
|
||||
});
|
||||
|
||||
it("the exported expression", function() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user