or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

component-detection.mdindex.mdplugin-configuration.mdtransform-interface.md
tile.json

component-detection.mddocs/

Component Detection

Rules and patterns for detecting React components that will be transformed by babel-plugin-react-transform.

Capabilities

Component Detection Rules

The plugin identifies React components using multiple detection strategies.

/**
 * Component detection configuration
 */
interface ComponentDetectionConfig {
  /** Patterns for detecting factory method calls like React.createClass */
  factoryMethods: string[];
  /** Patterns for detecting class inheritance from React components */
  superClasses: string[];
}

/**
 * Component visitor object that traverses AST to find React components
 */
const componentVisitor = {
  /** Processes class declarations/expressions that extend React components */
  Class(path: ASTPath): void;
  /** Processes React.createClass and similar factory method calls */
  CallExpression(path: ASTPath): void;
};

Class Component Detection

Detects ES6 classes that extend React component classes and have a render method.

/**
 * Detects React-like class components
 * @param node - AST node representing a class
 * @returns Boolean indicating if class is a React component
 */
function isReactLikeClass(node: ClassNode): boolean;

Detection Criteria:

  • Class extends one of the configured superclass patterns
  • Class has a render method (ClassMethod with key name 'render')
  • Default superclass patterns: ['React.Component', 'React.PureComponent', 'Component', 'PureComponent']

Examples Detected:

// Standard React components
class MyComponent extends React.Component {
  render() {
    return <div>Hello</div>;
  }
}

class PureComponent extends React.PureComponent {
  render() {
    return <div>Pure</div>;
  }
}

// Imported Component classes
import { Component } from 'react';
class ImportedComponent extends Component {
  render() {
    return <div>Imported</div>;
  }
}

// Custom superclass patterns (if configured)
class CustomComponent extends BaseComponent {
  render() {
    return <div>Custom</div>;
  }
}

Examples NOT Detected:

// No render method
class NotComponent extends React.Component {
  doSomething() {}
}

// Doesn't extend React class
class RegularClass {
  render() {
    return "not a component";
  }
}

Factory Method Detection

Detects function calls to component factory methods like React.createClass.

/**
 * Detects React-like component objects created via factory methods
 * @param node - AST node representing an object expression
 * @returns Boolean indicating if object is a React component
 */
function isReactLikeComponentObject(node: ObjectNode): boolean;

Detection Criteria:

  • Call expression matches one of the configured factory method patterns
  • First argument is an object with a render method or property
  • Default factory patterns: ['React.createClass']

Examples Detected:

// Standard createClass usage
const MyComponent = React.createClass({
  render: function() {
    return <div>CreateClass</div>;
  }
});

// Object method syntax
const ModernComponent = React.createClass({
  render() {
    return <div>Modern</div>;
  }
});

// String key render method
const StringKeyComponent = React.createClass({
  'render': function() {
    return <div>String key</div>;
  }
});

// Custom factory methods (if configured)
const CustomComponent = createComponent({
  render() {
    return <div>Custom factory</div>;
  }
});

Pattern Matching

How the plugin matches AST nodes against configured patterns.

/**
 * Matches AST path against array of patterns
 * @param path - Babel AST path to check
 * @param patterns - Array of string patterns to match against
 * @returns Boolean indicating if path matches any pattern
 */
function matchesPatterns(path: ASTPath, patterns: string[]): boolean;

Pattern Types:

  • Identifier matching: pattern matches nodes with name property equal to pattern
  • Member expression matching: path.matchesPattern(pattern) for dotted patterns like React.Component

Pattern Examples:

// Simple identifier patterns
["Component"] // matches: Component
["createClass"] // matches: createClass

// Member expression patterns  
["React.Component"] // matches: React.Component
["React.createClass"] // matches: React.createClass
["MyLib.createComponent"] // matches: MyLib.createComponent

Component Metadata Extraction

Information extracted from detected components.

/**
 * Extracts display name from createClass calls
 * @param node - Call expression node for createClass
 * @returns Display name string or undefined
 */
function getDisplayName(node: CallExpressionNode): string | undefined;

/**
 * Checks if component is defined inside a function scope
 * @param path - AST path of the component
 * @returns Boolean indicating if component is in function
 */
function hasParentFunction(path: ASTPath): boolean;

Display Name Extraction:

// From class name
class MyComponent extends React.Component {
  // displayName: "MyComponent"
}

// From createClass displayName property
const ComponentWithName = React.createClass({
  displayName: 'CustomName',
  render() {}
});
// displayName: "CustomName"

// Anonymous components get generated IDs
export default class extends React.Component {
  // displayName: undefined, gets unique ID
}

Function Scope Detection:

// Component NOT in function
class TopLevel extends React.Component {
  // isInFunction: false
}

// Component IN function
function createComponent() {
  class InFunction extends React.Component {
    // isInFunction: true
  }
  return InFunction;
}

// Nested function example
function outer() {
  function inner() {
    const Nested = React.createClass({
      // isInFunction: true
    });
  }
}

Detection Configuration Examples

Default Configuration

{
  "factoryMethods": ["React.createClass"],
  "superClasses": ["React.Component", "React.PureComponent", "Component", "PureComponent"]
}

Extended Configuration

{
  "factoryMethods": [
    "React.createClass",
    "createClass", 
    "createReactClass",
    "MyFramework.createComponent"
  ],
  "superClasses": [
    "React.Component",
    "React.PureComponent", 
    "Component",
    "PureComponent",
    "BaseComponent",
    "CustomFramework.Component"
  ]
}

Framework-Specific Configuration

{
  "factoryMethods": [
    "Preact.createClass",
    "createPreactComponent",
    "InfernoComponent.create"
  ],
  "superClasses": [
    "Preact.Component",
    "InfernoComponent",
    "CustomBaseClass"
  ]
}

Component Transformation Process

How detected components are processed and wrapped.

/**
 * Component information collected during detection
 */
interface DetectedComponent {
  /** Unique identifier for the component within the file */
  id: string;
  /** Display name if available */
  name?: string;
  /** Whether component is defined inside a function */
  isInFunction: boolean;
}

Detection and Transformation Flow:

  1. AST Traversal: Plugin visits Class and CallExpression nodes
  2. Pattern Matching: Checks if nodes match configured patterns
  3. Component Validation: Ensures components have render methods
  4. Metadata Extraction: Collects displayName and scope information
  5. Wrapper Generation: Creates wrapper function calls around components
  6. AST Replacement: Replaces original component with wrapped version

Generated Component Metadata:

// Example metadata for detected components
{
  "component1": {
    "displayName": "MyComponent",
    "isInFunction": false
  },
  "component2": {
    "displayName": "NestedComponent", 
    "isInFunction": true
  },
  "_component3": {
    // No displayName for anonymous component
    "isInFunction": false
  }
}