or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-babel--helper-builder-react-jsx

Helper function to build React JSX elements within Babel transformation workflows

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/@babel/helper-builder-react-jsx@7.27.x

To install, run

npx @tessl/cli install tessl/npm-babel--helper-builder-react-jsx@7.27.0

index.mddocs/

Babel Helper: Builder React JSX

A Babel helper function that creates visitors for transforming JSX elements and fragments into function calls. This package provides the core transformation logic used by React JSX Babel plugins to convert JSX syntax into JavaScript function calls with configurable options for different React patterns and optimization strategies.

Package Information

  • Package Name: @babel/helper-builder-react-jsx
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install @babel/helper-builder-react-jsx

Core Imports

import builderReactJsx from "@babel/helper-builder-react-jsx";
import type { Options } from "@babel/helper-builder-react-jsx";
import type { PluginPass, Visitor } from "@babel/core";
import * as t from "@babel/types";

For CommonJS:

const builderReactJsx = require("@babel/helper-builder-react-jsx");

Basic Usage

import builderReactJsx from "@babel/helper-builder-react-jsx";
import type { PluginPass, Visitor } from "@babel/core";
import * as t from "@babel/types";

// Create a basic JSX transformation visitor
const visitor: Visitor = builderReactJsx({
  throwIfNamespace: true,
  useSpread: false,
  useBuiltIns: false
});

// Use in a Babel plugin (following test patterns)
export default function myJsxPlugin() {
  return {
    visitor: {
      ...builderReactJsx({
        // Transform JSX elements with custom pre/post processing
        pre(state, pass) {
          // Called before JSX element transformation
          console.log(`Transforming ${state.tagName}`);
        },
        post(state, pass) {
          // Called after JSX element transformation
          if (state.pure) {
            console.log("Element marked as pure");
          }
        }
      }),
      Program(path, state) {
        // Set up plugin state as shown in tests
        state.set("jsxIdentifier", () => t.identifier("React.createElement"));
      }
    }
  };
}

Architecture

The helper follows Babel's visitor pattern architecture:

  • Visitor Factory: The main function returns a Babel visitor object configured with options
  • AST Transformation: Visitors transform JSX AST nodes (JSXElement, JSXFragment) into standard JavaScript calls
  • Hook System: Pre/post hooks allow custom processing during transformation
  • State Management: ElementState objects track transformation context and allow customization
  • Error Handling: Built-in validation for JSX syntax compliance and option conflicts

The transformation process follows this flow:

  1. Filter Phase: Optional filtering determines which nodes to transform
  2. Pre-processing: Pre hooks modify state before transformation
  3. Core Transformation: JSX syntax converted to function calls with proper attributes
  4. Post-processing: Post hooks can modify the final call expression
  5. Pure Annotation: Optional optimization markers added based on state

Capabilities

JSX Visitor Factory Function

Creates a Babel visitor object that handles JSX element and fragment transformations.

/**
 * Creates a Babel visitor for transforming JSX elements and fragments into function calls
 * @param opts - Configuration options for JSX transformation behavior
 * @returns Babel visitor object with JSX transformation methods
 */
export default function builderReactJsx(opts: Options): Visitor<PluginPass<Options>>;

Usage Example:

import builderReactJsx from "@babel/helper-builder-react-jsx";

// Basic transformation
const visitor = builderReactJsx({
  throwIfNamespace: true,
  useSpread: false
});

// Advanced transformation with hooks
const advancedVisitor = builderReactJsx({
  filter: (node, pass) => {
    // Only transform JSX elements with specific attributes
    return node.type === "JSXElement" && 
           node.openingElement.attributes.length > 0;
  },
  pre(state, pass) {
    // Mark React components as pure for optimization
    if (state.tagName && /^[A-Z]/.test(state.tagName)) {
      state.pure = true;
    }
  },
  useSpread: true,
  throwIfNamespace: false
});

Options Configuration

Configuration interface for customizing JSX transformation behavior.

export interface Options {
  /** Optional filter function to determine which JSX nodes to transform */
  filter?: (node: t.Node, pass: PluginPass) => boolean;
  
  /** Optional pre-processing hook called before JSX element transformation */
  pre?: (state: ElementState, pass: PluginPass) => void;
  
  /** Optional post-processing hook called after JSX element transformation */
  post?: (state: ElementState, pass: PluginPass) => void;
  
  /** Enable React DOM compatibility mode for legacy JSX patterns */
  compat?: boolean;
  
  /** Optional pure annotation string for optimization markers */
  pure?: string;
  
  /** Whether to throw error on JSX namespace tags (default: undefined, allows namespaces) */
  throwIfNamespace?: boolean;
  
  /** Use spread operator for attributes instead of Object.assign */
  useSpread?: boolean;
  
  /** Use native Object.assign instead of Babel helper */
  useBuiltIns?: boolean;
}

Configuration Examples:

// React compatibility mode (legacy)
const compatVisitor = builderReactJsx({
  compat: true,  // Disables JSX fragments
  throwIfNamespace: true
});

// Modern React with optimization
const modernVisitor = builderReactJsx({
  useSpread: true,  // Use {...props} instead of Object.assign
  pre(state, pass) {
    // Mark functional components as pure
    if (state.tagName && /^[A-Z]/.test(state.tagName)) {
      state.pure = true;
    }
  }
});

// Custom filtering
const filteredVisitor = builderReactJsx({
  filter: (node, pass) => {
    // Only transform JSX elements, skip fragments
    return node.type === "JSXElement";
  },
  useBuiltIns: true  // Use native Object.assign
});

Element State Interface

State object passed to pre and post hooks during JSX element transformation.

interface ElementState {
  /** The transformed tag expression (e.g., React.createElement first argument) */
  tagExpr: t.Expression;
  
  /** Raw string tag name extracted from JSX element */
  tagName: string | undefined | null;
  
  /** Array of call arguments for the transformed function call */
  args: Array<any>;
  
  /** Optional call property to override the generated call expression */
  call?: any;
  
  /** Whether the element can be marked with pure annotation for optimization */
  pure: boolean;
  
  /** Optional custom callee to use for the call expression */
  callee?: any;
}

interface PluginPass<T = any> {
  /** Get a value from plugin state */
  get(key: string): any;
  
  /** Set a value in plugin state */  
  set(key: string, value: any): void;
  
  /** Plugin options */
  opts: T;
  
  /** Add a helper function to the program */
  addHelper(name: string): t.Expression;
}

interface Visitor<T = PluginPass> {
  /** Visitor method for JSX elements */
  JSXElement?: {
    exit?(path: NodePath<t.JSXElement>, state: T): void;
  };
  
  /** Visitor method for JSX fragments */
  JSXFragment?: {
    exit?(path: NodePath<t.JSXFragment>, state: T): void;
  };
  
  /** Visitor method for JSX namespaced names */
  JSXNamespacedName?(path: NodePath<t.JSXNamespacedName>, state: T): void;
  
  /** Visitor method for JSX spread children */
  JSXSpreadChild?(path: NodePath<t.JSXSpreadChild>, state: T): void;
  
  /** Additional visitor methods */
  [key: string]: any;
}

interface NodePath<T = t.Node> {
  /** The AST node */
  node: T;
  
  /** Replace this node with another */
  replaceWith(node: t.Node): void;
  
  /** Build a code frame error */
  buildCodeFrameError(message: string): Error;
  
  /** Get a child path */
  get(key: string): NodePath;
}

State Usage Example:

const visitor = builderReactJsx({
  pre(state, pass) {
    // Log transformation details
    console.log(`Transforming: ${state.tagName}`);
    console.log(`Arguments: ${state.args.length}`);
    
    // Mark components as pure for optimization
    if (state.tagName && /^[A-Z]/.test(state.tagName)) {
      state.pure = true;
    }
    
    // Override call expression for custom JSX handling
    if (state.tagName === "Fragment") {
      state.callee = t.memberExpression(
        t.identifier("React"),
        t.identifier("Fragment")
      );
    }
  },
  post(state, pass) {
    // Post-process the generated call
    if (state.call && state.pure) {
      console.log("Pure component transformed");
    }
  }
});

Visitor Methods

The returned visitor object contains these methods for handling different JSX constructs:

JSXElement.exit

Transforms JSX elements (<div>, <Component>) into function calls.

visitor.JSXElement = {
  exit(path: NodePath<t.JSXElement>, state: PluginPass<Options>): void;
}

JSXFragment.exit

Transforms JSX fragments (<>...</>) into function calls. Throws error in compatibility mode.

visitor.JSXFragment = {
  exit(path: NodePath<t.JSXFragment>, state: PluginPass<Options>): void;
}

JSXNamespacedName

Handles JSX namespace tags (<ns:tag>). Throws error if throwIfNamespace option is true.

visitor.JSXNamespacedName = function(path: NodePath<t.JSXNamespacedName>, state: PluginPass<Options>): void;

JSXSpreadChild

Handles JSX spread children syntax. Always throws error as React doesn't support spread children.

visitor.JSXSpreadChild = function(path: NodePath<t.JSXSpreadChild>, state: PluginPass<Options>): void;

Error Handling

The package throws errors in these cases:

  • JSX Namespace Tags: When throwIfNamespace: true and namespace tags like <ns:tag> are encountered
  • JSX Spread Children: Always forbidden as React doesn't support {...children} syntax
  • JSX Fragments in Compatibility Mode: When compat: true and JSX fragments <>...</> are used
  • Invalid Option Combinations: When useSpread: true and useBuiltIns: true are both set
  • Invalid Option Types: When boolean options receive non-boolean values
// Error examples
builderReactJsx({ throwIfNamespace: true }); // Throws on <ns:tag>
builderReactJsx({ compat: true }); // Throws on <></>
builderReactJsx({ useSpread: true, useBuiltIns: true }); // Throws on conflicting options

Advanced Usage Patterns

Custom JSX Element Processing

const visitor = builderReactJsx({
  filter(node, pass) {
    // Only transform JSX elements with className
    return node.type === "JSXElement" && 
           node.openingElement.attributes.some(attr => 
             attr.type === "JSXAttribute" && 
             attr.name.name === "className"
           );
  },
  pre(state, pass) {
    // Add development mode warnings
    if (process.env.NODE_ENV === "development") {
      state.args.push(
        t.objectExpression([
          t.objectProperty(
            t.identifier("__source"), 
            t.objectExpression([])
          )
        ])
      );
    }
  }
});

React Optimization Integration

const optimizedVisitor = builderReactJsx({
  pre(state, pass) {
    // Mark functional components as pure for better performance
    const isComponent = state.tagName && /^[A-Z]/.test(state.tagName);
    const hasSimpleProps = state.args.length <= 2;
    
    if (isComponent && hasSimpleProps) {
      state.pure = true;
    }
  },
  useSpread: true, // Modern attribute handling
  throwIfNamespace: true // Strict JSX compliance
});

Legacy React Support

const legacyVisitor = builderReactJsx({
  compat: true, // Disable fragments for React < 16
  useBuiltIns: false, // Use Babel helpers for broader compatibility
  post(state, pass) {
    // Add displayName for debugging in legacy environments
    if (state.tagName && /^[A-Z]/.test(state.tagName)) {
      // Custom post-processing for legacy React patterns
      console.log(`Legacy transform: ${state.tagName}`);
    }
  }
});

Dependencies

External Dependencies

  • @babel/types - AST node types and utilities for JavaScript transformations
  • @babel/helper-annotate-as-pure - Helper for adding pure annotations to function calls
  • @babel/core - Core Babel types including PluginPass, NodePath, and Visitor interfaces

Babel Types Integration

The package integrates deeply with Babel's AST manipulation:

// Used internally for AST construction
import {
  callExpression,
  identifier,
  memberExpression,
  objectExpression,
  stringLiteral,
  // ... other AST node constructors
} from "@babel/types";