export function replaceWith(replacement) { this.resync(); if (this.removed) { throw new Error("You can't replace this node, we've already removed it"); } if (replacement instanceof NodePath) { replacement = replacement.node; } if (!replacement) { throw new Error("You passed `path.replaceWith()` a falsy node, use `path.remove()` instead"); } if (this.node === replacement) { return; } if (this.isProgram() && !t.isProgram(replacement)) { throw new Error("You can only replace a Program root node with another Program node"); } if (Array.isArray(replacement)) { throw new Error("Don't use `path.replaceWith()` with an array of nodes, use `path.replaceWithMultiple()`"); } if (typeof replacement === "string") { throw new Error("Don't use `path.replaceWith()` with a source string, use `path.replaceWithSourceString()`"); } // replacing a statement with an expression so wrap it in an expression statement if (this.isNodeType("Statement") && t.isExpression(replacement) && !this.canHaveVariableDeclarationOrExpression()) { replacement = t.expressionStatement(replacement); } // replacing an expression with a statement so let's explode it if (this.isNodeType("Expression") && t.isStatement(replacement)) { return this.replaceExpressionWithStatements([replacement]); } let oldNode = this.node; if (oldNode) { t.inheritsComments(replacement, oldNode); t.removeComments(oldNode); } // replace the node this._replaceWith(replacement); this.type = replacement.type; // potentially create new scope this.setScope(); // requeue for visiting this.requeue(); }
function ExportDeclaration(node: Object) { if (node.declaration) { const declar = node.declaration; this.print(declar, node); if (!t.isStatement(declar)) this.semicolon(); } else { if (node.exportKind === "type") { this.word("type"); this.space(); } const specifiers = node.specifiers.slice(0); // print "special" specifiers first let hasSpecial = false; while (true) { const first = specifiers[0]; if (t.isExportDefaultSpecifier(first) || t.isExportNamespaceSpecifier(first)) { hasSpecial = true; this.print(specifiers.shift(), node); if (specifiers.length) { this.token(","); this.space(); } } else { break; } } if (specifiers.length || (!specifiers.length && !hasSpecial)) { this.token("{"); if (specifiers.length) { this.space(); this.printList(specifiers, node); this.space(); } this.token("}"); } if (node.source) { this.space(); this.word("from"); this.space(); this.print(node.source, node); } this.semicolon(); } }
function ExportDeclaration(node: Object) { if (node.declaration) { let declar = node.declaration; this.print(declar, node); if (t.isStatement(declar) || t.isFunction(declar) || t.isClass(declar)) return; } else { if (node.exportKind === "type") { this.push("type "); } let specifiers = node.specifiers.slice(0); // print "special" specifiers first let hasSpecial = false; while (true) { let first = specifiers[0]; if (t.isExportDefaultSpecifier(first) || t.isExportNamespaceSpecifier(first)) { hasSpecial = true; this.print(specifiers.shift(), node); if (specifiers.length) { this.push(", "); } } else { break; } } if (specifiers.length || (!specifiers.length && !hasSpecial)) { this.push("{"); if (specifiers.length) { this.space(); this.printJoin(specifiers, node, { separator: ", " }); this.space(); } this.push("}"); } if (node.source) { this.push(" from "); this.print(node.source, node); } } this.ensureSemicolon(); }
Ep.explode = function(path, ignoreResult) { let node = path.node; let self = this; t.assertNode(node); if (t.isDeclaration(node)) throw getDeclError(node); if (t.isStatement(node)) return self.explodeStatement(path); if (t.isExpression(node)) return self.explodeExpression(path, ignoreResult); switch (node.type) { case "Program": return path.get("body").map( self.explodeStatement, self ); case "VariableDeclarator": throw getDeclError(node); // These node types should be handled by their parent nodes // (ObjectExpression, SwitchStatement, and TryStatement, respectively). case "Property": case "SwitchCase": case "CatchClause": throw new Error( node.type + " nodes should be handled by their parents"); default: throw new Error( "unknown Node of type " + JSON.stringify(node.type)); } };
return function (path, scope) { const cloned = t.cloneDeep(node); const uid = scope.generateUidIdentifier(camelCase(name)); const labelUid = scope.generateUidIdentifier('_' + name.toUpperCase()); var argsMacros = {}; const [params, seen] = cloned.params.reduce(([params, seen], id, index) => { const argument = path.get('arguments.' + index); if (argument && argument.isFunction()) { argsMacros[id.name] = new Macro({name: id.name, macroBody: argument.node, scope: argument.scope}); } else { params[id.name] = { id: id, replacement: path.node.arguments[index] || t.identifier('undefined'), reference: null }; seen[id.name] = false; } return [params, seen]; }, [{}, {}]); traverse(cloned, processMacros, scope, argsMacros, path.parentPath); let hasMultipleReturn = checkMultipleReturn(cloned, scope); traverse(cloned, { Identifier(subPath) { const {node: child, parent} = subPath; if (parent.type !== "MemberExpression" || parent.object === child || parent.computed && parent.property === child) { if (params[child.name]) { const param = params[child.name]; if ( param.replacement.type === 'Identifier' || param.replacement.type === 'Literal' || paramReferenceCounts[child.name] === 1 && param.replacement.type === 'MemberExpression' ) { subPath.replaceWith(param.replacement); seen[child.name] = param.replacement; } else { if (!seen[child.name]) { seen[child.name] = scope.generateUidIdentifier(child.name); getParentBlock(path).insertBefore([ t.variableDeclaration('const', [ t.variableDeclarator(seen[child.name], param.replacement) ]) ]); } subPath.replaceWith(seen[child.name]); } } else if (references[child.name]) { if (!seen[child.name]) { seen[child.name] = scope.generateUidIdentifier(child.name); } subPath.replaceWith(seen[child.name]) } } }, ReturnStatement(subPath) { const {node: child} = subPath; const isLast = child === cloned.body.body[cloned.body.body.length - 1]; subPath.replaceWith(t.expressionStatement(t.assignmentExpression('=', uid, child.argument || t.identifier('undefined')))); if (hasMultipleReturn && !isLast) { subPath.insertAfter(t.breakStatement(labelUid)); } }, FunctionDeclaration() { // @todo need correct rename. now renames only usages, but not function throw new Error('FunctionDeclaration in macros are not supported temporarily'); }, Function(subPath) { subPath.skip(); } }, scope); if (t.isStatement(cloned.body)) { const parentBlock = getParentBlock(path); parentBlock.insertBefore([ t.variableDeclaration('let', [ t.variableDeclarator(uid) ]) ]); if (hasMultipleReturn) { parentBlock.insertBefore(t.labeledStatement(labelUid, cloned.body)); } else { parentBlock.insertBefore(cloned.body.body); } path.replaceWith(uid); } else { path.replaceWith(cloned.body); } };
checkPath({ node, parent }) { return t.isMemberExpression(node) && t.isReferenced(node, parent); } }; export let BindingIdentifier = { types: ["Identifier"], checkPath({ node, parent }: NodePath): boolean { return t.isIdentifier(node) && t.isBinding(node, parent); } }; export let Statement = { types: ["Statement"], checkPath({ node, parent }: NodePath): boolean { if (t.isStatement(node)) { if (t.isVariableDeclaration(node)) { if (t.isForXStatement(parent, { left: node })) return false; if (t.isForStatement(parent, { init: node })) return false; } return true; } else { return false; } } }; export let Expression = { types: ["Expression"], checkPath(path: NodePath): boolean {