How to Harness AST for JavaScript, JSX, and ESLint Transformations

This article explains what an Abstract Syntax Tree (AST) is, outlines its parse‑transform‑generate workflow, and demonstrates practical AST‑based code transformations using Babel, custom ESLint rules, and a JSX‑to‑object Babel plugin, complete with example code and visual illustrations.

Alibaba Terminal Technology
Alibaba Terminal Technology
Alibaba Terminal Technology
How to Harness AST for JavaScript, JSX, and ESLint Transformations

What is AST?

AST (Abstract Syntax Tree) is a tree representation of source code that enables tools such as JavaScript transpilers, CSS preprocessors, ESLint, Prettier, and others to analyze and transform code without executing it.

AST Workflow

The typical workflow consists of three steps: parse – converting source code into an AST; transform – visiting and modifying AST nodes (the bulk of business logic); and generator – turning the transformed AST back into source code.

Simple Requirement Example

Goal: rename the parameter num to n in a square function and update all references, while leaving unrelated strings untouched.

Solution 1: Direct replace (unsafe)

const sourceText = `function square(num) {
  return num * num;
}`;
sourceText.replace(/num/g, 'n');

This naïve approach also changes occurrences inside strings and other identifiers, leading to bugs.

// before
function square(num) {
  return num * num;
}
console.log('param 2 result num is ' + square(2));

// after
function square(n) {
  return n * n;
}
console.log('param 2 result n is ' + square(2));

Solution 2: Using Babel for AST transformation

module.exports = () => {
  return {
    visitor: {
      Identifier(path) {
        if (path.node.name === 'num') {
          path.node.name = 'n';
        }
      }
    }
  };
};

This visitor changes every identifier named num, but also rewrites window.num, causing errors.

// before
function square(num) {
  return num * num;
}
console.log('global num is ' + window.num);

// after (incorrect)
function square(n) {
  return n * n;
}
console.log('global num is ' + window.n); // error

Solution 2 Upgrade: Precise reference handling

module.exports = () => {
  return {
    visitor: {
      Identifier(path) {
        if (path.node.name !== 'num') return;
        if (path.parent.type !== 'FunctionDeclaration') return;
        if (path.parent.id.name !== 'square') return;
        const referencePaths = path.scope.bindings['num'].referencePaths;
        referencePaths.forEach(p => p.node.name = 'n');
        path.node.name = 'n';
      }
    }
  };
};

This version limits the rename to the square function’s parameter and its references, leaving other num usages untouched.

Babel in AST

Babel provides three core packages for AST work: @babel/parser – parses source code into an AST. @babel/traverse – walks the AST and runs visitor callbacks. @babel/generator – generates source code from an AST.

Additional helpers include @babel/types for node creation and checks, and @babel/template for building nodes from code snippets.

const parser = require('@babel/parser').parse;
const traverse = require('@babel/traverse').default;
const generate = require('@babel/generator').default;
const types = require('@babel/types');
const template = require('@babel/template').default;

ESLint in AST

Custom ESLint rules can be written by visiting AST nodes. Example rule that warns when a variable name is a single character:

module.exports.rules = {
  "var-length": context => ({
    VariableDeclarator(node) {
      if (node.id.name.length <= 1) {
        context.report(node, 'Variable name length must be greater than 1');
      }
    }
  })
};

Configuration in .eslintrc.js enables the rule.

module.exports = {
  root: true,
  parserOptions: { ecmaVersion: 6 },
  plugins: ["my-eslint-plugin"],
  rules: { "my-eslint-plugin/var-length": "warn" }
};

Getting JSX Interpretation Rights

JSX is a JavaScript syntax extension used by React but not limited to it. By writing a Babel plugin we can transform JSX into a generic object representation that can be consumed by different runtimes (Web, mini‑programs, etc.).

// JSX source
<view visible onTap={e => console.log('clicked')}>ABC<button>login</button></view>

Desired output:

{
  type: 'view',
  visible: true,
  children: [
    'ABC',
    { type: 'button', children: ['login'] }
  ]
}

JSX Babel Plugin

const { declare } = require('@babel/helper-plugin-utils');
const jsx = require('@babel/plugin-syntax-jsx').default;
const core = require('@babel/core');
const t = core.types;

const handleJSXElement = node => {
  const tag = node.openingElement;
  const type = tag.name.name;
  const properties = [t.objectProperty(t.identifier('type'), t.stringLiteral(type))];
  const attributes = tag.attributes || [];
  attributes.forEach(attr => {
    if (attr.type === 'JSXAttribute') {
      const key = t.identifier(attr.name.name);
      const convert = n => {
        if (t.isJSXExpressionContainer(n)) return n.expression;
        if (n === null) return t.booleanLiteral(true);
        return n;
      };
      const value = convert(attr.value);
      properties.push(t.objectProperty(key, value));
    }
  });
  const children = node.children.map(e => {
    if (e.type === 'JSXElement') return handleJSXElement(e);
    if (e.type === 'JSXText') return t.stringLiteral(e.value);
    return e;
  });
  properties.push(t.objectProperty(t.identifier('children'), t.arrayExpression(children)));
  return t.objectExpression(properties);
};

module.exports = declare((api, options) => ({
  inherits: jsx,
  visitor: {
    JSXElement(path) {
      path.replaceWith(handleJSXElement(path.node));
    }
  }
}));

Conclusion

We introduced what AST is, its workflow, and demonstrated powerful transformations using Babel, ESLint, and custom JSX plugins. AST can serve as a strong weapon for code automation, visual programming, and custom linting scenarios.

All example code and tests are available at https://github.com/chvin/learn_ast .

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaScriptfrontend developmentASTbabelJSXcode transformationESLint
Alibaba Terminal Technology
Written by

Alibaba Terminal Technology

Official public account of Alibaba Terminal

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.