Performing a code audit
Create a custom script to audit a codebase
As you look through the codebase, you'll notice several usages of a button
element. Since this specific codebase is React, a common pattern is to create a single Button
component that can be reused in all these places. This makes it easier to change the internal implementation in one place.
Let's walk through using AST-based tooling to make this change.
Understanding the existing codebase#
To create this new component, we need some information about the current button usages:
what kind of styles (variants) need to be supported?
what kind of props (options) need to be supported?
While it might be tempting to manually look through and read all the files, let's try using AST-based tools to answer these questions.
Creating a custom script#
AST-based tooling uses many of the same steps as you would if you were manually auditing the codebase to answer these questions. If doing this code audit manually, the first step would be to locate the relevant files. Then, you would need to find any button
elements. Finally, you would look at the props (options) and styles to discover what the Button
component needs to support. A custom script using an AST can follow these same steps, but automate it.
Let's start by creating a new project.
# Create a new directory for the audit script
# Note: the paths below assume `flash-cards` is a sibling directory
mkdir audit
# Change into the new audit directory
cd audit
# Initialize a new package.json file
npm init -y
# Add the necessary dependencies (these will be covered shortly)
npm i @babel/parser @babel/traverse glob ts-node typescript
npm i -D @types/babel__traverse @types/glob
Search for relevant files#
Then, create a new file named audit.ts
. The first step is to find all relevant files. For this codebase, that's all the files in src/components
.
import * as fs from "fs";
import * as glob from "glob";
// First, find all files relevant files. This glob pattern
// assumes this project is a sibling to the sample codebase.
const files = glob.sync("../flash-cards/src/components/**/*.js");
files.forEach((file) => {
// Next, read the contents of each individual file.
const contents = fs.readFileSync(file).toString();
console.log(contents);
});
This script is using the glob
package which allows using glob patterns (eg: *
and **
) to find files. Here, glob.sync
is used to synchronously find all files that match the pattern (the default is asynchronous). The result is an array of strings which are file paths matching the glob pattern.
Then, for each of these files, Node's built-in fs
file system package can be used to read the file's contents.
Running this current script will print the file contents of the relevant files.
npx ts-node ./audit.ts
Search for relevant elements#
This completes the first step of finding the relevant files. The next step is to find the button
elements. This is where an AST becomes helpful. The previous parsing and traversal script can be adapted for this.
We first need to know which node(s) to traverse in the AST. This is where AST Explorer comes in handy. Copy and paste the following relevant code snippet into AST Explorer.
<button
type="button"
className="button button--primary"
onClick={handleStartOver}
>
<span role="img">♻</span> Start over
</button>;
Note that we chose a small piece of code instead of the entire file. This makes it easier to explore. While we chose this specific snippet, any of the button uses could have been chosen.
Clicking directly on the opening button element tag in the AST Explorer's editor should highlight the JSXIdentifier
node which contains the element's name: button
. Its parent is a JSXOpeningElement
with an attributes
property. This property contains an array of all the attributes (props) associated with this element.

The JSXAttribute
nodes will all appear similar, but inspect the name
and value
properties of each. These will contain nodes that represent the name of the prop and the value.
This page is a preview of Practical Abstract Syntax Trees