or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

decorator-support.mdfeature-management.mdfield-transformation.mdindex.mdplugin-creation.mdutilities.md
tile.json

utilities.mddocs/

Utilities

Helper utilities for class initialization, computed key extraction, and AST manipulation.

Capabilities

Inject Initialization

Injects initialization code into class constructors.

/**
 * Injects initialization code into a class constructor
 * Creates constructor if none exists, or augments existing constructor
 * @param path - Class path to modify
 * @param constructor - Existing constructor path (undefined if none)
 * @param instanceNodes - Initialization expressions to inject
 * @param referenceVisitor - Callback for handling property references
 * @param lastInstanceNodeReturnsThis - Whether last node returns 'this'
 */
function injectInitialization(
  path: NodePath<t.Class>,
  constructor: NodePath<t.ClassMethod> | undefined,
  instanceNodes: t.ExpressionStatement[],
  referenceVisitor: (visitor: Visitor, state: any) => void,
  lastInstanceNodeReturnsThis: boolean
): void;

type Visitor = {
  [key: string]: (path: NodePath, state: any) => void;
};

Usage Examples:

import { injectInitialization } from "@babel/helper-create-class-features-plugin";

// Inject field initialization into constructor
injectInitialization(
  classPath,
  constructorPath, // may be undefined
  [
    t.expressionStatement(
      t.assignmentExpression("=", 
        t.memberExpression(t.thisExpression(), t.identifier("field")),
        t.stringLiteral("value")
      )
    )
  ],
  (referenceVisitor, state) => {
    // Handle property references during injection
    for (const prop of props) {
      if (!prop.node.static) {
        prop.traverse(referenceVisitor, state);
      }
    }
  },
  false // last node doesn't return this
);

Extract Computed Keys

Extracts and memoizes computed property keys from class members.

/**
 * Extracts computed keys from class methods and properties
 * Hoists computed key expressions to avoid re-evaluation
 * @param path - Class path containing computed keys
 * @param computedPaths - Paths with computed keys to extract  
 * @param file - Babel file instance
 * @returns Array of statement nodes for hoisted key variables
 */
function extractComputedKeys(
  path: NodePath<t.Class>,
  computedPaths: NodePath<t.ClassProperty | t.ClassMethod>[],
  file: File
): t.Statement[];

Usage Examples:

import { extractComputedKeys } from "@babel/helper-create-class-features-plugin";

// Find computed properties
const computedPaths: NodePath<t.ClassProperty | t.ClassMethod>[] = [];
for (const memberPath of classPath.get("body.body")) {
  if ((memberPath.isClassProperty() || memberPath.isClassMethod()) && 
      memberPath.node.computed) {
    computedPaths.push(memberPath);
  }
}

// Extract computed keys
const keyNodes = extractComputedKeys(classPath, computedPaths, file);

// Insert hoisted key variables before class
classPath.insertBefore(keyNodes);

Build Check In RHS

Builds a right-hand side expression for private property 'in' checks with proper validation.

/**
 * Builds a right-hand side expression for private property 'in' checks
 * Wraps expressions with helper when available for proper validation
 * @param rhs - The right-hand side expression to check
 * @param file - Babel file instance for helper access
 * @param inRHSIsObject - Whether RHS is known to be an object
 * @returns Enhanced expression with proper validation
 */
function buildCheckInRHS(
  rhs: t.Expression,
  file: File,
  inRHSIsObject?: boolean
): t.Expression;

Usage Examples:

import { buildCheckInRHS } from "@babel/helper-create-class-features-plugin";

// Build RHS check for private 'in' operation
const rhs = t.identifier("obj");
const checkedRHS = buildCheckInRHS(rhs, file);

// Use in private property 'in' check
const privateInCheck = t.binaryExpression(
  "in",
  privateNameId,
  checkedRHS
);

// With known object type (skips validation)
const checkedRHSOptimized = buildCheckInRHS(rhs, file, true);

Initialization Patterns

Constructor Creation

When no constructor exists, one is created:

// Before transformation
class Example {
  field = "value";
}

// After initialization injection
class Example {
  constructor() {
    this.field = "value";
  }
}

Constructor Augmentation

When constructor exists, initialization is injected:

// Before transformation  
class Example {
  field = "value";
  
  constructor(param) {
    console.log("constructor");
  }
}

// After initialization injection
class Example {
  constructor(param) {
    this.field = "value";
    console.log("constructor");
  }
}

Super Call Handling

Initialization respects super call requirements:

// Before transformation
class Child extends Parent {
  field = "value";
  
  constructor() {
    super();
    console.log("after super");
  }
}

// After initialization injection
class Child extends Parent {
  constructor() {
    super();
    this.field = "value";
    console.log("after super");
  }
}

Computed Key Patterns

Simple Computed Keys

// Before extraction
class Example {
  [computeKey()] = "value";
  [expensive.calculation] = "value2";
}

// After extraction
const _computeKey = computeKey();
const _expensive$calculation = expensive.calculation;
class Example {
  [_computeKey] = "value";
  [_expensive$calculation] = "value2";
}

Complex Expressions

// Before extraction
class Example {
  [prefix + Math.random()] = "value";
  [getKey() + suffix] = "value2";
}

// After extraction  
const _prefix$Math$random = prefix + Math.random();
const _getKey$suffix = getKey() + suffix;
class Example {
  [_prefix$Math$random] = "value";
  [_getKey$suffix] = "value2";
}

Reference Visitor Pattern

The reference visitor pattern handles property references during initialization:

const referenceVisitor: Visitor = {
  ThisExpression(path) {
    // Handle 'this' references in initializers
  },
  
  Super(path) {
    // Handle 'super' references in initializers
  },
  
  PrivateName(path) {
    // Handle private name references
  }
};

// Used in injectInitialization callback
(visitor, state) => {
  for (const prop of instanceProps) {
    prop.traverse(visitor, state);
  }
}

Scope and Binding Management

Utilities properly handle scope and binding:

  • Generate unique identifiers for memoized keys
  • Preserve binding references during transformation
  • Handle closure captures in initializer expressions
  • Maintain proper execution order for side effects