diff --git a/packages/babel-plugin-proposal-decorators/src/transformer.js b/packages/babel-plugin-proposal-decorators/src/transformer.js index 22a493183a1c..9ed8cd942117 100644 --- a/packages/babel-plugin-proposal-decorators/src/transformer.js +++ b/packages/babel-plugin-proposal-decorators/src/transformer.js @@ -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) { diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initiailzer-after-super-bug-8808/input.js b/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initiailzer-after-super-bug-8808/input.js new file mode 100644 index 000000000000..d664cd62ffe8 --- /dev/null +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initiailzer-after-super-bug-8808/input.js @@ -0,0 +1,6 @@ +@decorator(parameter) +class Sub extends Super { + constructor() { + super().method(); + } +} \ No newline at end of file diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initiailzer-after-super-bug-8808/output.js b/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initiailzer-after-super-bug-8808/output.js new file mode 100644 index 000000000000..b7707bd53987 --- /dev/null +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initiailzer-after-super-bug-8808/output.js @@ -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); diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initialize-after-super-bug-8931/input.js b/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initialize-after-super-bug-8931/input.js new file mode 100644 index 000000000000..77e15bfd1190 --- /dev/null +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initialize-after-super-bug-8931/input.js @@ -0,0 +1,7 @@ +@dec +class B extends A { + constructor() { + super(); + []; + } +} diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initialize-after-super-bug-8931/output.js b/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initialize-after-super-bug-8931/output.js new file mode 100644 index 000000000000..0de044306931 --- /dev/null +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initialize-after-super-bug-8931/output.js @@ -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); diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initialize-after-super-expression/input.js b/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initialize-after-super-expression/input.js new file mode 100644 index 000000000000..aa9941aeaff7 --- /dev/null +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initialize-after-super-expression/input.js @@ -0,0 +1,6 @@ +@dec +class B extends A { + constructor() { + (0, super()); + } +} diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initialize-after-super-expression/output.js b/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initialize-after-super-expression/output.js new file mode 100644 index 000000000000..1c46c7388322 --- /dev/null +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initialize-after-super-expression/output.js @@ -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); diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initialize-after-super-multiple/input.js b/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initialize-after-super-multiple/input.js new file mode 100644 index 000000000000..33b0fce036d2 --- /dev/null +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initialize-after-super-multiple/input.js @@ -0,0 +1,14 @@ +@dec +class B extends A { + constructor() { + const foo = () => { super(); }; + + if (a) { super(); } + else { foo(); } + + while (0) { super(); } + + super(); + } +} + diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initialize-after-super-multiple/output.js b/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initialize-after-super-multiple/output.js new file mode 100644 index 000000000000..9f6f173fa645 --- /dev/null +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initialize-after-super-multiple/output.js @@ -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); diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initialize-after-super-statement/input.js b/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initialize-after-super-statement/input.js new file mode 100644 index 000000000000..1aac9e28d2a0 --- /dev/null +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initialize-after-super-statement/input.js @@ -0,0 +1,6 @@ +@dec +class B extends A { + constructor() { + super(); + } +} diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initialize-after-super-statement/output.js b/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initialize-after-super-statement/output.js new file mode 100644 index 000000000000..3c90f9c34448 --- /dev/null +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/transformation/initialize-after-super-statement/output.js @@ -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); diff --git a/packages/babel-traverse/src/path/modification.js b/packages/babel-traverse/src/path/modification.js index b69f527eed6e..add972ee4327 100644 --- a/packages/babel-traverse/src/path/modification.js +++ b/packages/babel-traverse/src/path/modification.js @@ -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") diff --git a/packages/babel-traverse/test/modification.js b/packages/babel-traverse/test/modification.js index 6b08efa0a684..ad5d40c69a8a 100644 --- a/packages/babel-traverse/test/modification.js +++ b/packages/babel-traverse/test/modification.js @@ -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() {