In this tutorial, we will do some basic transforms to some source code, using Babel. Many people find the idea of transforming code scary, and unapproachable, but utilising the power of AST’s (abstract syntax trees), and a set of tools provided to us by Babel, most of the heavy lifting is done for us. : The examples in the article will include code specific to , , and , but familiarity with these libraries is not necessary for this tutorial. Note react redux react-redux AST Explorer There is a website called , that we can paste our code into and get an AST representation in many formats. This website will be useful for quickly viewing code in AST format, and will be useful when ascertaining which nodes we need to target. AST explorer Basic insertion Below, we have a file with a couple of imports, and a default export. reducers.js For our first transformation, lets add a new import and export to . We’ll add . To do this we need to: reducers.js mice Parse the code to AST format. Traverse the AST and find nodes adjacent to the nodes we want to add. Insert the new nodes. Generate the new code from our AST. Here’s how we achieve this: Let’s break this down. First of all, we call the parser on our code which transforms it from a string to an AST. const ast = parser(file, {sourceType: 'module'}); Note, since we are using ES6 modules, we need to let the parser know with . {sourceType: ‘module’} Next, we use to find our relevant nodes. How did we know we needed and ? This is where comes in handy. Below we’ve pasted our code in on the left panel, and on the right we can view the AST representation of our code. traverse ExportDefaultDeclaration ObjectExpression AST explorer We have 2 ’s, so will help us iterate over them and save the last one into a variable called . We then use to insert the new import after the last import. ImportDeclaration traverse lastImport insertAfter // this file is made up of snippets from transform.js let lastImport; traverse(ast, {ImportDeclaration(path) {lastImport = path;} const importCode = `import ${reducerName} from './${reducerName}'`;lastImport.insertAfter(parser(importCode, {sourceType: 'module'})); To add a property to the default exported object, we will use to iterate over ‘s. We only expect there to be one, so we will save its properties using . We can then push our new identifier into the array. traverse ObjectExpression properties = path.parent.declaration.properties mice properties // this file is made up of snippets from transform.js traverse(ast, {ObjectExpression(path) {properties = path.parent.declaration.properties}}) const id = t.identifier(REDUCER_NAME)properties.push(t.objectProperty(id, id, false, true)) You might be wondering what is? Good question. Since the alone does not have enough context, we cannot just call on a string of code like in the last example. Babel would parse it as an instead of a , leading to issues when re-generating the code. To solve this, we use the package to help the parser understand what we have added to the AST. t.objectProperty(id, id, false, true) mice parser Identifier Property @babel/types Now that we have updated our AST, we can call on it. This will transform the code from an AST back into code in string format. We run prettier on the string, and we end up with code like below: generate Wrapping a variable in a function Next up, we will learn how to use to wrap an identifier in a high order component. replaceWith Essentially, we want to go from: export default Sports; to: const mapStateToProps = ({ volleyball, soccer }) => ({volleyball,soccer}); export default connect(mapStateToProps)(Sports); This consists of two steps. Get the name of the default export (identifier). Replace it with a wrapped version of itself, and the function. mapStateToProps Here’s the file we will operate on: And this is the code to transform it: First thing to note, since we are parsing JSX this time, we need to let the parser know: const ast = parser(file, {sourceType: 'module', plugins: ['jsx']}); This time we use to iterate over the AST and find the . Once we’ve found it, we store the name of the variable being exported. traverse ExportDefaultDeclaration const declarationName = exportDefaultPath.node.declaration.name; Since we know the name of the exported variable, we can now replace the entire default export with new code: exportDefaultPath.replaceWith(// new code...) Having transformed the AST, we can run and on it, and write the file to disk. We end up with: generate prettier Summing up Learning how to manipulate AST’s will open up many new possibilities to you. With AST’s you could write: Linting plugins Babel plugins Codemods I hope this tutorial will set you on your way to exploring the world of AST’s!