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

converters.mddocs/

Type Converters

Functions to convert between different AST node types and representations. These utilities help transform nodes while maintaining semantic correctness and proper AST structure.

Capabilities

Expression Converters

To Expression

Converts statements to expressions where possible.

/**
 * Convert a statement or expression to an expression
 * @param node - Statement or expression to convert
 * @returns Expression node
 * @throws Error if statement cannot be converted to expression
 */
function toExpression(node: t.Statement | t.Expression): t.Expression;

To Statement

Converts expressions to statements by wrapping in expression statements.

/**
 * Convert an expression or statement to a statement
 * @param node - Expression or statement to convert
 * @returns Statement node (wraps expressions in ExpressionStatement)
 */
function toStatement(node: t.Statement | t.Expression): t.Statement;

Block and Control Flow Converters

Ensure Block

Ensures a statement is wrapped in a block statement.

/**
 * Ensure a statement is wrapped in a block statement
 * @param node - Statement to wrap
 * @returns BlockStatement containing the node
 */
function ensureBlock(node: t.Statement): t.BlockStatement;

To Block

Converts a statement to a block statement.

/**
 * Convert a statement to a block statement
 * @param node - Statement to convert
 * @returns BlockStatement (wraps non-block statements)
 */
function toBlock(node: t.Statement): t.BlockStatement;

Identifier and Key Converters

To Identifier

Converts strings or existing identifiers to identifier nodes.

/**
 * Convert string or identifier to identifier node
 * @param name - String name or existing identifier
 * @returns Identifier node with valid name
 */
function toIdentifier(name: string | t.Identifier): t.Identifier;

To Binding Identifier Name

Converts a string to a valid binding identifier name.

/**
 * Convert string to valid binding identifier name
 * @param name - String to convert
 * @returns Valid identifier name for variable bindings
 */
function toBindingIdentifierName(name: string): string;

To Key Alias

Converts property keys to string aliases for object property access.

/**
 * Convert object property key to string alias
 * @param key - Property key node
 * @returns String representation of the key
 */
function toKeyAlias(key: t.Expression): string;

To Computed Key

Converts property keys to computed property format when needed.

/**
 * Convert property key to computed key format if needed
 * @param key - Property key node
 * @returns Key in computed format or original if not needed
 */
function toComputedKey(key: t.Expression): t.Expression;

Value Converters

Value to Node

Converts JavaScript values to appropriate AST literal nodes.

/**
 * Convert JavaScript value to appropriate AST literal node
 * @param value - JavaScript value to convert
 * @returns Appropriate literal node or complex structure for objects/arrays
 */
function valueToNode(value: any): t.Expression;

Legacy Converters

To Sequence Expression (Legacy)

Legacy function for creating sequence expressions (conditionally available).

/**
 * Convert array of expressions to sequence expression (legacy)
 * @param expressions - Array of expressions
 * @returns SequenceExpression or single expression if array has one element
 * @deprecated Available only in non-breaking builds
 */
function toSequenceExpression(expressions: t.Expression[]): t.Expression;

Usage Examples

Expression and Statement Conversion

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

// Convert statement to expression
const returnStmt = t.returnStatement(t.numericLiteral(42));
try {
  const expr = t.toExpression(returnStmt);
  console.log(expr); // NumericLiteral(42) - return statement stripped
} catch (error) {
  console.log("Cannot convert to expression");
}

// Convert expression to statement
const expr = t.binaryExpression("+", t.identifier("a"), t.identifier("b"));
const stmt = t.toStatement(expr);
console.log(stmt.type); // "ExpressionStatement"
console.log((stmt as t.ExpressionStatement).expression === expr); // true

Block Statement Conversion

// Ensure statement is in block
const ifStmt = t.ifStatement(
  t.identifier("condition"),
  t.expressionStatement(t.callExpression(t.identifier("fn"), []))
);

const blockStmt = t.ensureBlock(ifStmt.consequent);
console.log(blockStmt.type); // "BlockStatement"
console.log(blockStmt.body.length); // 1

// Convert single statement to block
const singleStmt = t.returnStatement(t.identifier("value"));
const block = t.toBlock(singleStmt);
console.log(block.body.length); // 1
console.log(block.body[0] === singleStmt); // true

// Already a block - returns as-is
const existingBlock = t.blockStatement([singleStmt]);
const unchangedBlock = t.toBlock(existingBlock);
console.log(unchangedBlock === existingBlock); // true

Identifier Conversion

// String to identifier
const id1 = t.toIdentifier("myVariable");
console.log(id1.type); // "Identifier"
console.log(id1.name); // "myVariable"

// Already identifier - returns as-is
const existingId = t.identifier("existing");
const id2 = t.toIdentifier(existingId);
console.log(id2 === existingId); // true

// Invalid identifier names are cleaned
const cleanId = t.toIdentifier("123invalid-name!");
console.log(cleanId.name); // Valid identifier name

Binding Identifier Names

// Clean names for variable bindings
const validName1 = t.toBindingIdentifierName("valid_name");
console.log(validName1); // "valid_name"

const validName2 = t.toBindingIdentifierName("123-invalid");
console.log(validName2); // Cleaned to valid identifier

const validName3 = t.toBindingIdentifierName("class");
console.log(validName3); // Escaped reserved word

Object Key Conversion

// Property key to alias
const stringKey = t.stringLiteral("myProperty");
const alias1 = t.toKeyAlias(stringKey);
console.log(alias1); // "myProperty"

const identifierKey = t.identifier("propertyName");
const alias2 = t.toKeyAlias(identifierKey);
console.log(alias2); // "propertyName"

const numericKey = t.numericLiteral(42);
const alias3 = t.toKeyAlias(numericKey);
console.log(alias3); // "42"

// Computed key conversion
const simpleKey = t.identifier("simple");
const computed1 = t.toComputedKey(simpleKey);
console.log(computed1 === simpleKey); // true - doesn't need computation

const complexKey = t.binaryExpression("+", t.stringLiteral("prefix"), t.identifier("suffix"));
const computed2 = t.toComputedKey(complexKey);
console.log(computed2 === complexKey); // true - already computed expression

Value to Node Conversion

// Primitive values
const stringNode = t.valueToNode("hello world");
console.log(stringNode.type); // "StringLiteral"
console.log((stringNode as t.StringLiteral).value); // "hello world"

const numberNode = t.valueToNode(42);
console.log(numberNode.type); // "NumericLiteral"

const booleanNode = t.valueToNode(true);
console.log(booleanNode.type); // "BooleanLiteral"

const nullNode = t.valueToNode(null);
console.log(nullNode.type); // "NullLiteral"

const undefinedNode = t.valueToNode(undefined);
console.log(undefinedNode.type); // "Identifier" with name "undefined"

// Array conversion
const arrayNode = t.valueToNode([1, "two", true]);
console.log(arrayNode.type); // "ArrayExpression"
const arrayExpr = arrayNode as t.ArrayExpression;
console.log(arrayExpr.elements.length); // 3
console.log((arrayExpr.elements[0] as t.NumericLiteral).value); // 1
console.log((arrayExpr.elements[1] as t.StringLiteral).value); // "two"

// Object conversion
const objectNode = t.valueToNode({ 
  name: "John", 
  age: 30, 
  active: true 
});
console.log(objectNode.type); // "ObjectExpression"
const objExpr = objectNode as t.ObjectExpression;
console.log(objExpr.properties.length); // 3

// Nested structures
const nestedNode = t.valueToNode({
  users: [
    { id: 1, name: "Alice" },
    { id: 2, name: "Bob" }
  ],
  config: {
    debug: true,
    version: "1.0.0"
  }
});
console.log(nestedNode.type); // "ObjectExpression" with nested structures

Control Flow Conversions

// Ensure if statements have block bodies
const ifStmt = t.ifStatement(
  t.identifier("condition"),
  t.expressionStatement(t.callExpression(t.identifier("action"), []))
);

// Convert consequent to block
const blockConsequent = t.ensureBlock(ifStmt.consequent);
ifStmt.consequent = blockConsequent;

// Now safe to add multiple statements
blockConsequent.body.push(
  t.expressionStatement(t.callExpression(t.identifier("cleanup"), []))
);

// Ensure else clause is also a block
if (ifStmt.alternate) {
  ifStmt.alternate = t.ensureBlock(ifStmt.alternate);
}

Function Body Conversion

// Convert expression to function body
const arrowFunction = t.arrowFunctionExpression(
  [t.identifier("x")],
  t.binaryExpression("*", t.identifier("x"), t.numericLiteral(2))
);

// Convert to regular function with block body
const functionExpr = t.functionExpression(
  null,
  arrowFunction.params,
  t.toBlock(t.returnStatement(arrowFunction.body as t.Expression))
);

console.log(functionExpr.body.type); // "BlockStatement"
console.log(functionExpr.body.body.length); // 1 - return statement

Switch Statement Case Conversion

// Ensure switch cases have block statements
const switchStmt = t.switchStatement(
  t.identifier("value"),
  [
    t.switchCase(
      t.stringLiteral("case1"),
      [t.expressionStatement(t.callExpression(t.identifier("handle1"), []))]
    ),
    t.switchCase(
      t.stringLiteral("case2"),
      [t.expressionStatement(t.callExpression(t.identifier("handle2"), []))]
    )
  ]
);

// Convert each case to have block statements
switchStmt.cases.forEach(caseNode => {
  if (caseNode.consequent.length === 1 && !t.isBlockStatement(caseNode.consequent[0])) {
    const block = t.toBlock(caseNode.consequent[0]);
    caseNode.consequent = [block];
  }
});

Template Generation with Converters

// Generate code with proper conversions
function createGetter(propertyName: string, returnType: "expression" | "statement") {
  const propertyAccess = t.memberExpression(
    t.thisExpression(),
    t.toIdentifier(propertyName)
  );
  
  const returnNode = t.returnStatement(propertyAccess);
  
  if (returnType === "expression") {
    return t.toExpression(returnNode); // Just the property access
  } else {
    return t.toStatement(returnNode); // Return statement
  }
}

function createMethod(methodName: string, body: t.Statement[]) {
  return t.objectMethod(
    "method",
    t.toIdentifier(methodName),
    [],
    t.blockStatement(body.map(stmt => t.toStatement(stmt)))
  );
}