CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-babel--helper-create-class-features-plugin

Babel helper plugin that provides essential functionality for transforming modern JavaScript class features to ES6-compatible code

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

field-transformation.mddocs/

Field Transformation

Comprehensive private and public field transformation including private name mapping, field initialization, and usage transformation.

Capabilities

Build Private Names Map

Creates a mapping of private names to their metadata for transformation.

/**
 * Builds mapping of private names to metadata
 * @param className - Name of the class being transformed
 * @param privateFieldsAsSymbolsOrProperties - Whether to use symbols/properties instead of WeakMap
 * @param props - Array of class property paths
 * @param file - Babel file instance
 * @returns Map of private names to their metadata
 */
function buildPrivateNamesMap(
  className: string,
  privateFieldsAsSymbolsOrProperties: boolean,
  props: PropPath[],
  file: File
): PrivateNamesMap;

type PrivateNamesMap = Map<string, PrivateNameMetadata>;

interface PrivateNameMetadata {
  id: t.Identifier;
  static: boolean;
  method: boolean;
  getId?: t.Identifier;
  setId?: t.Identifier;
  methodId?: t.Identifier;
  initAdded?: boolean;
  getterDeclared?: boolean;
  setterDeclared?: boolean;
}

Usage Examples:

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

// Build private names map for a class
const privateNamesMap = buildPrivateNamesMap(
  "MyClass",
  loose, // Use symbols instead of WeakMap
  props, // Class property paths
  file
);

// Access metadata for a private field
const fieldMetadata = privateNamesMap.get("privateField");
if (fieldMetadata) {
  console.log(fieldMetadata.id.name); // Generated identifier
  console.log(fieldMetadata.static);  // Is static field
  console.log(fieldMetadata.method);  // Is method
}

Build Private Names Nodes

Creates AST nodes for private name declarations.

/**
 * Creates AST nodes for private name declarations
 * @param privateNamesMap - Map of private names to metadata
 * @param privateFieldsAsProperties - Use properties instead of WeakMap
 * @param privateFieldsAsSymbols - Use symbols instead of WeakMap
 * @param file - Babel file instance
 * @returns Array of AST statement nodes
 */
function buildPrivateNamesNodes(
  privateNamesMap: PrivateNamesMap,
  privateFieldsAsProperties: boolean,
  privateFieldsAsSymbols: boolean,
  file: File
): t.Statement[];

Build Fields Init Nodes

Builds comprehensive field initialization nodes for classes.

/**
 * Builds field initialization nodes for classes
 * @param ref - Class reference identifier (null for class expressions)
 * @param superRef - Super class expression (undefined if no inheritance)
 * @param props - Array of class property paths
 * @param privateNamesMap - Map of private names to metadata
 * @param file - Babel file instance
 * @param setPublicClassFields - Whether to set public fields as assignments
 * @param privateFieldsAsSymbolsOrProperties - Use symbols/properties for private fields
 * @param noUninitializedPrivateFieldAccess - Skip uninitialized access checks
 * @param constantSuper - Assume super class is constant
 * @param innerBindingRef - Inner class binding identifier
 * @returns Object containing initialization nodes and utilities
 */
function buildFieldsInitNodes(
  ref: t.Identifier | null,
  superRef: t.Expression | undefined,
  props: PropPath[],
  privateNamesMap: PrivateNamesMap,
  file: File,
  setPublicClassFields: boolean,
  privateFieldsAsSymbolsOrProperties: boolean,
  noUninitializedPrivateFieldAccess: boolean,
  constantSuper: boolean,
  innerBindingRef: t.Identifier | null
): FieldsInitResult;

interface FieldsInitResult {
  staticNodes: t.Statement[];
  pureStaticNodes: t.FunctionDeclaration[];
  instanceNodes: t.ExpressionStatement[];
  lastInstanceNodeReturnsThis: boolean;
  classBindingNode: t.Statement | null;
  wrapClass: (path: NodePath<t.Class>) => NodePath;
}

Usage Examples:

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

// Build field initialization for a class
const {
  staticNodes,
  pureStaticNodes,
  instanceNodes,
  lastInstanceNodeReturnsThis,
  classBindingNode,
  wrapClass
} = buildFieldsInitNodes(
  ref,
  path.node.superClass,
  props,
  privateNamesMap,
  file,
  setPublicClassFields ?? loose,
  privateFieldsAsSymbolsOrProperties ?? loose,
  noUninitializedPrivateFieldAccess,
  constantSuper ?? loose,
  innerBinding
);

// Apply transformations
const wrappedPath = wrapClass(path);
wrappedPath.insertBefore(staticNodes);
wrappedPath.insertAfter(pureStaticNodes);

Transform Private Names Usage

Transforms all private name usage throughout the class.

/**
 * Transforms private name usage throughout the class
 * @param classRefForDefine - Class reference for private field definitions
 * @param path - Class path to transform
 * @param privateNamesMap - Map of private names to metadata
 * @param options - Transformation options
 * @param file - Babel file instance
 */
function transformPrivateNamesUsage(
  classRefForDefine: t.Identifier,
  path: NodePath<t.Class>,
  privateNamesMap: PrivateNamesMap,
  options: {
    privateFieldsAsProperties: boolean;
    noUninitializedPrivateFieldAccess: boolean;
    noDocumentAll: boolean;
    innerBinding: t.Identifier | null;
  },
  file: File
): void;

Build Check In RHS

Builds checks for right-hand side private property access (#prop in obj).

/**
 * Builds private property access checks for 'in' expressions
 * @param privateNamesMap - Map of private names to metadata
 * @param loose - Whether to use loose mode checks
 * @param privateFieldsAsSymbols - Whether private fields use symbols
 * @returns Expression for checking private property access
 */
function buildCheckInRHS(
  privateNamesMap: PrivateNamesMap,
  loose: boolean,
  privateFieldsAsSymbols: boolean
): t.Expression;

Usage Examples:

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

// Build check for private property 'in' expressions
const checkExpression = buildCheckInRHS(
  privateNamesMap,
  loose,
  privateFieldsAsSymbols
);

// Used to transform: #privateField in obj
// Into appropriate runtime check

Private Name Visitor Factory

Creates visitors for traversing and transforming private name usage.

/**
 * Factory for creating private name visitors
 * @param visitor - Base visitor configuration
 * @returns Configured visitor for private name transformation
 */
function privateNameVisitorFactory<S, V>(
  visitor: PrivateNameVisitor<S, V>
): PrivateNameVisitor<S, V>;

interface PrivateNameVisitorState<V> {
  privateNamesMap: PrivateNamesMapGeneric<V>;
  redeclared?: string[];
}

interface PrivateNameVisitor<S, V> {
  ClassExpression?(path: NodePath<t.ClassExpression>, state: S): void;
  ClassDeclaration?(path: NodePath<t.ClassDeclaration>, state: S): void;
  PrivateName?(path: NodePath<t.PrivateName>, state: S): void;
}

Property Path Types

Defines the types of class properties that can be transformed.

/**
 * Union type for all class property node types
 */
type PropNode = 
  | t.ClassProperty 
  | t.ClassPrivateProperty 
  | t.ClassPrivateMethod 
  | t.StaticBlock;

/**
 * NodePath for class property nodes
 */
type PropPath = NodePath<PropNode>;

Field Initialization Patterns

The system supports various field initialization patterns:

// Instance fields
class Example {
  publicField = "value";     // Becomes assignment in constructor
  #privateField = "value";   // Uses WeakMap or symbol storage
}

// Static fields  
class Example {
  static publicStatic = "value";    // Becomes class.prop = value
  static #privateStatic = "value";  // Uses WeakMap or symbol storage
}

// Computed fields
class Example {
  [computedKey] = "value";          // Key extracted and memoized
  #[computedPrivate] = "value";     // Not supported - syntax error
}

Loose Mode vs Strict Mode

The transformation behavior changes based on loose mode:

Strict Mode (default):

  • Private fields use WeakMap for storage
  • Full spec compliance with runtime checks
  • Proper handling of uninitialized field access

Loose Mode:

  • Private fields use symbols or direct properties
  • Faster execution, less spec compliant
  • Minimal runtime checks

docs

decorator-support.md

feature-management.md

field-transformation.md

index.md

plugin-creation.md

utilities.md

tile.json