diff --git a/packages/babel-core/test/fixtures/transformation/misc/regression-4855/expected.js b/packages/babel-core/test/fixtures/transformation/misc/regression-4855/expected.js index b1457077f2..01617b80fe 100644 --- a/packages/babel-core/test/fixtures/transformation/misc/regression-4855/expected.js +++ b/packages/babel-core/test/fixtures/transformation/misc/regression-4855/expected.js @@ -3,4 +3,5 @@ var _values = values; value = _values[fieldName]; rest = babelHelpers.objectWithoutProperties(_values, [fieldName]); -var error = void 0; \ No newline at end of file +_values; +var error = void 0; diff --git a/packages/babel-plugin-transform-object-rest-spread/test/fixtures/object-rest/assignment-expression/expected.js b/packages/babel-plugin-transform-object-rest-spread/test/fixtures/object-rest/assignment-expression/expected.js index 214508c2b8..4547757a20 100644 --- a/packages/babel-plugin-transform-object-rest-spread/test/fixtures/object-rest/assignment-expression/expected.js +++ b/packages/babel-plugin-transform-object-rest-spread/test/fixtures/object-rest/assignment-expression/expected.js @@ -8,6 +8,7 @@ var _c = c2; a2 } = _c); b2 = babelHelpers.objectWithoutProperties(_c, ["a2"]); +_c; console.log((_c2 = c3, ({ a3 -} = _c2), b3 = babelHelpers.objectWithoutProperties(_c2, ["a3"]), _c2)); \ No newline at end of file +} = _c2), b3 = babelHelpers.objectWithoutProperties(_c2, ["a3"]), _c2)); diff --git a/packages/babel-traverse/src/path/context.js b/packages/babel-traverse/src/path/context.js index 50c5364685..0145b1d90f 100644 --- a/packages/babel-traverse/src/path/context.js +++ b/packages/babel-traverse/src/path/context.js @@ -239,6 +239,7 @@ export function _getQueueContexts() { let contexts = this.contexts; while (!contexts.length) { path = path.parentPath; + if (!path) break; contexts = path.contexts; } return contexts; diff --git a/packages/babel-traverse/src/path/modification.js b/packages/babel-traverse/src/path/modification.js index 5b7ed5678e..104ed99aa7 100644 --- a/packages/babel-traverse/src/path/modification.js +++ b/packages/babel-traverse/src/path/modification.js @@ -20,24 +20,21 @@ export function insertBefore(nodes) { ) { return this.parentPath.insertBefore(nodes); } else if ( - this.isNodeType("Expression") || + (this.isNodeType("Expression") && this.listKey !== "params") || (this.parentPath.isForStatement() && this.key === "init") ) { if (this.node) nodes.push(this.node); this.replaceExpressionWithStatements(nodes); + } else if (Array.isArray(this.container)) { + return this._containerInsertBefore(nodes); + } else if (this.isStatementOrBlock()) { + if (this.node) nodes.push(this.node); + this._replaceWith(t.blockStatement(nodes)); } else { - this._maybePopFromStatements(nodes); - if (Array.isArray(this.container)) { - return this._containerInsertBefore(nodes); - } else if (this.isStatementOrBlock()) { - if (this.node) nodes.push(this.node); - this._replaceWith(t.blockStatement(nodes)); - } else { - throw new Error( - "We don't know what to do with this node type. " + - "We were previously a Statement but we can't fit in here?", - ); - } + throw new Error( + "We don't know what to do with this node type. " + + "We were previously a Statement but we can't fit in here?", + ); } return [this]; @@ -101,17 +98,6 @@ export function _containerInsertAfter(nodes) { return this._containerInsert(this.key + 1, nodes); } -export function _maybePopFromStatements(nodes) { - const last = nodes[nodes.length - 1]; - const isIdentifier = - t.isIdentifier(last) || - (t.isExpressionStatement(last) && t.isIdentifier(last.expression)); - - if (isIdentifier && !this.isCompletionRecord()) { - nodes.pop(); - } -} - /** * Insert the provided nodes after the current one. When inserting nodes after an * expression, ensure that the completion record is correct by pushing the current node. @@ -139,25 +125,22 @@ export function insertAfter(nodes) { nodes.push(t.expressionStatement(temp)); } this.replaceExpressionWithStatements(nodes); - } else { - this._maybePopFromStatements(nodes); - if (Array.isArray(this.container)) { - return this._containerInsertAfter(nodes); - } else if (this.isStatementOrBlock()) { - // Unshift current node if it's not an empty expression - if ( - this.node && - (!this.isExpressionStatement() || this.node.expression != null) - ) { - nodes.unshift(this.node); - } - this._replaceWith(t.blockStatement(nodes)); - } else { - throw new Error( - "We don't know what to do with this node type. " + - "We were previously a Statement but we can't fit in here?", - ); + } else if (Array.isArray(this.container)) { + return this._containerInsertAfter(nodes); + } else if (this.isStatementOrBlock()) { + // Unshift current node if it's not an empty expression + if ( + this.node && + (!this.isExpressionStatement() || this.node.expression != null) + ) { + nodes.unshift(this.node); } + this._replaceWith(t.blockStatement(nodes)); + } else { + throw new Error( + "We don't know what to do with this node type. " + + "We were previously a Statement but we can't fit in here?", + ); } return [this]; diff --git a/packages/babel-traverse/src/path/replacement.js b/packages/babel-traverse/src/path/replacement.js index 1f80d960e4..390cf3e167 100644 --- a/packages/babel-traverse/src/path/replacement.js +++ b/packages/babel-traverse/src/path/replacement.js @@ -205,20 +205,7 @@ export function replaceExpressionWithStatements(nodes: Array) { const toSequenceExpression = t.toSequenceExpression(nodes, this.scope); - if (t.isSequenceExpression(toSequenceExpression)) { - const exprs = toSequenceExpression.expressions; - - if (exprs.length >= 2 && this.parentPath.isExpressionStatement()) { - this._maybePopFromStatements(exprs); - } - - // could be just one element due to the previous maybe popping - if (exprs.length === 1) { - this.replaceWith(exprs[0]); - } else { - this.replaceWith(toSequenceExpression); - } - } else if (toSequenceExpression) { + if (toSequenceExpression) { this.replaceWith(toSequenceExpression); } else { const container = t.arrowFunctionExpression([], t.blockStatement(nodes)); diff --git a/packages/babel-traverse/test/modification.js b/packages/babel-traverse/test/modification.js new file mode 100644 index 0000000000..e3fa8a9f9c --- /dev/null +++ b/packages/babel-traverse/test/modification.js @@ -0,0 +1,59 @@ +import traverse from "../lib"; +import assert from "assert"; +import { parse } from "babylon"; +import generate from "babel-generator"; +import * as t from "babel-types"; + +function getPath(code) { + const ast = parse(code); + let path; + traverse(ast, { + Program: function(_path) { + path = _path; + _path.stop(); + }, + }); + + return path; +} + +function generateCode(path) { + return generate(path.node).code; +} + +describe("modification", function() { + describe("pushContainer", function() { + it("pushes identifier into params", function() { + const rootPath = getPath("function test(a) {}"); + const path = rootPath.get("body.0"); + path.pushContainer("params", t.identifier("b")); + + assert.equal(generateCode(rootPath), "function test(a, b) {}"); + }); + + it("pushes identifier into block", function() { + const rootPath = getPath("function test(a) {}"); + const path = rootPath.get("body.0.body"); + path.pushContainer("body", t.expressionStatement(t.identifier("b"))); + + assert.equal(generateCode(rootPath), "function test(a) {\n b;\n}"); + }); + }); + describe("unshiftContainer", function() { + it("unshifts identifier into params", function() { + const rootPath = getPath("function test(a) {}"); + const path = rootPath.get("body.0"); + path.unshiftContainer("params", t.identifier("b")); + + assert.equal(generateCode(rootPath), "function test(b, a) {}"); + }); + + it("unshifts identifier into block", function() { + const rootPath = getPath("function test(a) {}"); + const path = rootPath.get("body.0.body"); + path.unshiftContainer("body", t.expressionStatement(t.identifier("b"))); + + assert.equal(generateCode(rootPath), "function test(a) {\n b;\n}"); + }); + }); +});