wrapSuperCall(bareSuper, superRef, thisRef, body) { let bareSuperNode = bareSuper.node; if (this.isLoose) { bareSuperNode.arguments.unshift(t.thisExpression()); if (bareSuperNode.arguments.length === 2 && t.isSpreadElement(bareSuperNode.arguments[1]) && t.isIdentifier(bareSuperNode.arguments[1].argument, { name: "arguments" })) { // special case single arguments spread bareSuperNode.arguments[1] = bareSuperNode.arguments[1].argument; bareSuperNode.callee = t.memberExpression(superRef, t.identifier("apply")); } else { bareSuperNode.callee = t.memberExpression(superRef, t.identifier("call")); } } else { bareSuperNode = optimiseCall( t.callExpression( t.memberExpression(t.identifier("Object"), t.identifier("getPrototypeOf")), [this.classRef] ), t.thisExpression(), bareSuperNode.arguments ); } let call = t.callExpression( this.file.addHelper("possibleConstructorReturn"), [t.thisExpression(), bareSuperNode] ); let bareSuperAfter = this.bareSuperAfter.map((fn) => fn(thisRef)); if (bareSuper.parentPath.isExpressionStatement() && bareSuper.parentPath.container === body.node.body && body.node.body.length - 1 === bareSuper.parentPath.key) { // this super call is the last statement in the body so we can just straight up // turn it into a return if (this.superThises.length || bareSuperAfter.length) { bareSuper.scope.push({ id: thisRef }); call = t.assignmentExpression("=", thisRef, call); } if (bareSuperAfter.length) { call = t.toSequenceExpression([call, ...bareSuperAfter, thisRef]); } bareSuper.parentPath.replaceWith(t.returnStatement(call)); } else { bareSuper.replaceWithMultiple([ t.variableDeclaration("var", [ t.variableDeclarator(thisRef, call) ]), ...bareSuperAfter, t.expressionStatement(thisRef) ]); } }
export function replaceExpressionWithStatements(nodes: Array<Object>) { this.resync(); let toSequenceExpression = t.toSequenceExpression(nodes, this.scope); if (t.isSequenceExpression(toSequenceExpression)) { let 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) { this.replaceWith(toSequenceExpression); } else { let container = t.functionExpression(null, [], t.blockStatement(nodes)); container.shadow = true; this.replaceWith(t.callExpression(container, [])); this.traverse(hoistVariablesVisitor); // add implicit returns to all ending expression statements let completionRecords: Array<NodePath> = this.get("callee").getCompletionRecords(); for (let path of completionRecords) { if (!path.isExpressionStatement()) continue; let loop = path.findParent((path) => path.isLoop()); if (loop) { let callee = this.get("callee"); let uid = callee.scope.generateDeclaredUidIdentifier("ret"); callee.get("body").pushContainer("body", t.returnStatement(uid)); path.get("expression").replaceWith( t.assignmentExpression("=", uid, path.node.expression) ); } else { path.replaceWith(t.returnStatement(path.node.expression)); } } return this.node; } }