Skip to content

Commit

Permalink
[decorators] Correctly insert _initialize(this) after super(). (#…
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
nicolo-ribaudo authored and danez committed Nov 7, 2018
1 parent 5d5cd86 commit b706e34
Show file tree
Hide file tree
Showing 13 changed files with 167 additions and 3 deletions.
4 changes: 4 additions & 0 deletions packages/babel-plugin-proposal-decorators/src/transformer.js
Expand Up @@ -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) {
Expand Down
@@ -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);
12 changes: 11 additions & 1 deletion packages/babel-traverse/src/path/modification.js
Expand Up @@ -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")
Expand Down
8 changes: 6 additions & 2 deletions packages/babel-traverse/test/modification.js
Expand Up @@ -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() {
Expand All @@ -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() {
Expand Down

0 comments on commit b706e34

Please sign in to comment.