or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

builders.mdcloning.mdcomments.mdconstants.mdconverters.mdindex.mdmodifications.mdreact.mdretrievers.mdtraversal.mdvalidators.md
tile.json

react.mddocs/

React Utilities

Specialized utilities for working with React components and JSX syntax. These functions help identify React-specific patterns and manipulate JSX elements during AST transformations.

Capabilities

React Component Detection

Is React Component

Checks if a node represents a reference to React.Component for class component inheritance.

/**
 * Check if node represents React.Component reference
 * @param node - Node to check
 * @returns Whether the node is React.Component member expression
 */
function isReactComponent(node: t.Node | null | undefined): boolean;

JSX Tag Analysis

Is Compatible Tag

Checks if a tag name is a valid HTML/DOM-compatible tag name.

/**
 * Check if tag name is HTML/DOM compatible
 * @param tagName - Tag name to validate
 * @returns Whether the tag name is a standard HTML element
 */
function isCompatTag(tagName: string): boolean;

JSX Children Processing

Build Children

Processes JSX element children, filtering and transforming them appropriately.

/**
 * Build processed children array from JSX element
 * @param node - JSX element to extract children from
 * @returns Array of processed child nodes
 */
function buildChildren(node: t.JSXElement): t.Node[];

React Utilities Namespace

All React utilities are available under the react namespace:

const react: {
  isReactComponent: (node: t.Node | null | undefined) => boolean;
  isCompatTag: (tagName: string) => boolean;
  buildChildren: (node: t.JSXElement) => t.Node[];
};

Usage Examples

React Component Class Detection

import * as t from "@babel/types";

// Class extending React.Component
const reactClass = t.classDeclaration(
  t.identifier("MyComponent"),
  t.memberExpression(t.identifier("React"), t.identifier("Component")),
  t.classBody([])
);

// Check if extends React.Component
if (reactClass.superClass && t.react.isReactComponent(reactClass.superClass)) {
  console.log("This is a React class component");
}

// Other inheritance patterns
const customBase = t.memberExpression(
  t.identifier("MyLib"), 
  t.identifier("Component")
);

console.log(t.react.isReactComponent(customBase)); // false - not React.Component

// Direct React.Component reference
const reactComponent = t.memberExpression(
  t.identifier("React"),
  t.identifier("Component")
);

console.log(t.react.isReactComponent(reactComponent)); // true

HTML Tag Validation

// Standard HTML tags
console.log(t.react.isCompatTag("div")); // true
console.log(t.react.isCompatTag("span")); // true
console.log(t.react.isCompatTag("button")); // true
console.log(t.react.isCompatTag("input")); // true
console.log(t.react.isCompatTag("img")); // true

// Custom components (capitalized)
console.log(t.react.isCompatTag("MyComponent")); // false
console.log(t.react.isCompatTag("Button")); // false
console.log(t.react.isCompatTag("CustomDiv")); // false

// Invalid/non-standard tags
console.log(t.react.isCompatTag("invalid-tag")); // false
console.log(t.react.isCompatTag("customElement")); // false

// Edge cases
console.log(t.react.isCompatTag("")); // false
console.log(t.react.isCompatTag("123")); // false

JSX Element Analysis

// JSX element with mixed children
const jsxElement = t.jsxElement(
  t.jsxOpeningElement(t.jsxIdentifier("div"), []),
  t.jsxClosingElement(t.jsxIdentifier("div")),
  [
    t.jsxText("Hello "),
    t.jsxExpressionContainer(t.identifier("name")),
    t.jsxText("!"),
    t.jsxElement(
      t.jsxOpeningElement(t.jsxIdentifier("span"), []),
      t.jsxClosingElement(t.jsxIdentifier("span")),
      [t.jsxText("nested")]
    )
  ]
);

// Process children
const children = t.react.buildChildren(jsxElement);
console.log(children.length); // Processed children count
console.log(children.map(child => child.type)); // Types of processed children

React Component Transformation

// Transform class component to functional component
function transformToFunctional(classDecl: t.ClassDeclaration): t.FunctionDeclaration | null {
  // Check if it's a React component
  if (!classDecl.superClass || !t.react.isReactComponent(classDecl.superClass)) {
    return null; // Not a React component
  }
  
  // Find render method
  const renderMethod = classDecl.body.body.find(
    (member): member is t.ClassMethod =>
      t.isClassMethod(member) && 
      t.isIdentifier(member.key) && 
      member.key.name === "render"
  );
  
  if (!renderMethod) return null;
  
  // Create functional component
  return t.functionDeclaration(
    classDecl.id,
    [], // No props for this simple example
    renderMethod.body
  );
}

// Usage
const ReactComponent = t.classDeclaration(
  t.identifier("Welcome"),
  t.memberExpression(t.identifier("React"), t.identifier("Component")),
  t.classBody([
    t.classMethod(
      "method",
      t.identifier("render"),
      [],
      t.blockStatement([
        t.returnStatement(
          t.jsxElement(
            t.jsxOpeningElement(t.jsxIdentifier("h1"), []),
            t.jsxClosingElement(t.jsxIdentifier("h1")),
            [t.jsxText("Hello World")]
          )
        )
      ])
    )
  ])
);

const functionalComponent = transformToFunctional(ReactComponent);
if (functionalComponent) {
  console.log("Transformed to functional component");
}

JSX Tag Transformation

// Transform JSX elements based on tag type
function transformJSXElement(element: t.JSXElement): t.JSXElement {
  const openingElement = element.openingElement;
  
  if (t.isJSXIdentifier(openingElement.name)) {
    const tagName = openingElement.name.name;
    
    if (t.react.isCompatTag(tagName)) {
      // It's a DOM element - might add HTML-specific attributes
      console.log(`Processing DOM element: ${tagName}`);
      
      // Add data attributes for DOM elements
      const dataAttr = t.jsxAttribute(
        t.jsxIdentifier("data-component"),
        t.stringLiteral("dom-element")
      );
      
      if (!openingElement.attributes.some(attr => 
        t.isJSXAttribute(attr) && 
        t.isJSXIdentifier(attr.name) && 
        attr.name.name === "data-component"
      )) {
        openingElement.attributes.push(dataAttr);
      }
    } else {
      // It's a custom component
      console.log(`Processing custom component: ${tagName}`);
      
      // Add component tracking
      const componentAttr = t.jsxAttribute(
        t.jsxIdentifier("data-custom"),
        t.stringLiteral("true")
      );
      
      openingElement.attributes.push(componentAttr);
    }
  }
  
  return element;
}

JSX Children Processing

// Process JSX children for transformation
function processJSXChildren(element: t.JSXElement) {
  const processedChildren = t.react.buildChildren(element);
  
  processedChildren.forEach((child, index) => {
    if (t.isJSXText(child)) {
      console.log(`Text node ${index}: "${child.value}"`);
    } else if (t.isJSXExpressionContainer(child)) {
      console.log(`Expression ${index}:`, child.expression.type);
    } else if (t.isJSXElement(child)) {
      console.log(`Nested element ${index}:`, child.openingElement.name);
      // Recursively process nested elements
      processJSXChildren(child);
    }
  });
}

// Example usage
const complexJSX = t.jsxElement(
  t.jsxOpeningElement(t.jsxIdentifier("div"), []),
  t.jsxClosingElement(t.jsxIdentifier("div")),
  [
    t.jsxText("Start "),
    t.jsxExpressionContainer(
      t.conditionalExpression(
        t.identifier("condition"),
        t.stringLiteral("true"),
        t.stringLiteral("false")
      )
    ),
    t.jsxText(" end"),
    t.jsxElement(
      t.jsxOpeningElement(t.jsxIdentifier("Button"), []),
      t.jsxClosingElement(t.jsxIdentifier("Button")),
      [t.jsxText("Click me")]
    )
  ]
);

processJSXChildren(complexJSX);

React Pattern Detection

// Detect various React patterns
function analyzeReactCode(node: t.Node) {
  const patterns = {
    classComponents: 0,
    jsxElements: 0,
    domElements: 0,
    customComponents: 0
  };
  
  t.traverse(node, {
    ClassDeclaration(path) {
      if (path.node.superClass && t.react.isReactComponent(path.node.superClass)) {
        patterns.classComponents++;
      }
    },
    
    JSXElement(path) {
      patterns.jsxElements++;
      
      const openingElement = path.node.openingElement;
      if (t.isJSXIdentifier(openingElement.name)) {
        if (t.react.isCompatTag(openingElement.name.name)) {
          patterns.domElements++;
        } else {
          patterns.customComponents++;
        }
      }
    }
  });
  
  return patterns;
}

// Usage with a React component file
const reactCode = t.program([
  // Class component
  t.classDeclaration(
    t.identifier("App"),
    t.memberExpression(t.identifier("React"), t.identifier("Component")),
    t.classBody([
      t.classMethod(
        "method",
        t.identifier("render"),
        [],
        t.blockStatement([
          t.returnStatement(
            t.jsxElement(
              t.jsxOpeningElement(t.jsxIdentifier("div"), []),
              t.jsxClosingElement(t.jsxIdentifier("div")),
              [
                t.jsxElement(
                  t.jsxOpeningElement(t.jsxIdentifier("Header"), []),
                  t.jsxClosingElement(t.jsxIdentifier("Header")),
                  []
                ),
                t.jsxElement(
                  t.jsxOpeningElement(t.jsxIdentifier("p"), []),
                  t.jsxClosingElement(t.jsxIdentifier("p")),
                  [t.jsxText("Content")]
                )
              ]
            )
          )
        ])
      )
    ])
  )
]);

const analysis = analyzeReactCode(reactCode);
console.log(analysis);
// { classComponents: 1, jsxElements: 3, domElements: 2, customComponents: 1 }

JSX Optimization

// Optimize JSX elements by processing children
function optimizeJSXElement(element: t.JSXElement): t.JSXElement {
  // Process children to remove empty text nodes and optimize
  const optimizedChildren = t.react.buildChildren(element);
  
  // Filter out empty text nodes
  const filteredChildren = optimizedChildren.filter(child => {
    if (t.isJSXText(child)) {
      return child.value.trim().length > 0;
    }
    return true;
  });
  
  // Update element with optimized children
  const optimized = t.cloneDeep(element);
  optimized.children = filteredChildren;
  
  return optimized;
}