CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-babel--plugin-transform-class-static-block

Babel plugin that transforms ES2022 class static blocks into compatible code for older JavaScript environments

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

index.mddocs/

@babel/plugin-transform-class-static-block

A Babel plugin that transforms ES2022 class static blocks into compatible code for older JavaScript environments. The plugin handles complex transformations while maintaining proper initialization order and scoping semantics.

Package Information

  • Package Name: @babel/plugin-transform-class-static-block
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install --save-dev @babel/plugin-transform-class-static-block
  • Main Export: ./lib/index.js
  • Type Definitions: ./lib/index.d.ts
  • Module Type: ESM (with CommonJS support)

Core Imports

// CommonJS - default plugin export
const plugin = require("@babel/plugin-transform-class-static-block");

// ESM - default plugin export
import plugin from "@babel/plugin-transform-class-static-block";

// Plugin internal imports (from source)
import { declare } from "@babel/helper-plugin-utils";
import type { NodePath, Scope, types as t } from "@babel/core";
import {
  buildNamedEvaluationVisitor,
  enableFeature,
  FEATURES,
} from "@babel/helper-create-class-features-plugin";

Basic Usage

Add the plugin to your Babel configuration:

// babel.config.js
module.exports = {
  plugins: ["@babel/plugin-transform-class-static-block"]
};

// or with explicit plugin import
module.exports = {
  plugins: [require("@babel/plugin-transform-class-static-block")]
};

Example transformation:

// Input (ES2022 class static block)
class Foo {
  static bar = 42;
  static {
    this.foo = this.bar;
  }
}

// Output (transformed for older environments)
var _Foo;
class Foo {}
_Foo = Foo;
babelHelpers.defineProperty(Foo, "bar", 42);
_Foo.foo = _Foo.bar;

Capabilities

Babel Plugin Function

The main export is the plugin function that integrates with Babel's transformation pipeline.

/**
 * Babel plugin that transforms class static blocks
 * Uses declare() from @babel/helper-plugin-utils to create the plugin
 * @param api - Babel API object containing types, template, traverse, and assertVersion
 * @returns Babel plugin configuration object
 */
declare function plugin(api: {
  types: typeof t;
  template: any;
  traverse: any;
  assertVersion: (version: string) => void;
}): BabelPlugin;

export default plugin;

interface BabelPlugin {
  /** Plugin identifier */
  name: "transform-class-static-block";
  /** Parser configuration function (Babel 7 only) */
  manipulateOptions?: (opts: any, parser: { plugins: string[] }) => void;
  /** Pre-transformation lifecycle method */
  pre?(): void;
  /** AST visitor configuration */
  visitor: {
    ClassBody(path: NodePath<t.ClassBody>): void;
  };
}

Transformation Features

The plugin provides comprehensive transformation of class static blocks:

  • Static Block Conversion: Transforms static { ... } blocks into immediately invoked function expressions or inlined expressions
  • Initialization Order: Maintains proper execution order of static initialization relative to static properties
  • Class Expression Support: Handles both class declarations and class expressions
  • Named Evaluation: Supports proper named evaluation for anonymous class expressions using buildNamedEvaluationVisitor
  • Integration: Works seamlessly with other Babel class feature plugins via @babel/helper-create-class-features-plugin
  • Private Property Integration: Creates synthetic private properties when no static properties exist to hold transformation logic
  • Sequence Expression Optimization: Uses sequence expressions for single-expression static blocks to avoid unnecessary IIFEs

Multiple Static Blocks:

// Input
class Foo {
  static #bar = 21;
  static {
    this.foo = this.#bar;
    this.qux1 = this.qux;
  }
  static qux = 21;
  static {
    this.qux2 = this.qux;
  }
}

// Output (when using private fields plugin)
var _Foo;
class Foo {}
_Foo = Foo;
var _bar = {
  _: 21
};
(() => {
  _Foo.foo = babelHelpers.assertClassBrand(_Foo, _Foo, _bar)._;
  _Foo.qux1 = _Foo.qux;
})();
babelHelpers.defineProperty(Foo, "qux", 21);
_Foo.qux2 = _Foo.qux;

Static Block without Static Properties:

// Input
class Foo {
  static {
    this.foo = 42;
  }
}

// Output - creates private property to hold the static block
var _staticBlock;
class Foo {
  static #_ = _staticBlock = () => this.foo = 42;
}
_staticBlock();

Advanced Transformation Patterns

The plugin handles several complex scenarios:

Class Expressions with Named Evaluation:

// Input - anonymous class expression
const MyClass = class {
  static {
    this.name = "MyClass";
  }
};

// Output - adds named evaluation support
const MyClass = class {
  static {
    setFunctionName(this, "MyClass");
    this.name = "MyClass";
  }
};

Integration with Class Features Plugin:

/**
 * Enables static block support in the class features plugin system
 * This allows coordination with other class transformation plugins
 */
enableFeature(file: any, feature: FEATURES.staticBlocks, loose: boolean): void;

/**
 * Builds visitor for handling named evaluation of anonymous class expressions
 * @param predicate - Function to determine if named evaluation is needed
 * @param visitor - Function to perform the named evaluation transformation
 */
buildNamedEvaluationVisitor(
  predicate: (path: NodePath) => boolean,
  visitor: (classPath: NodePath<t.ClassExpression>, state: any, name: string | t.Expression) => void
): TraversalVisitor;

Private Property Generation:

/**
 * Generates unique identifier names avoiding conflicts with existing private properties
 * @param scope - Babel scope for generating unique identifiers
 * @param denyList - Set of existing private property names to avoid
 * @returns Unique identifier name
 */
function generateUid(scope: Scope, denyList: Set<string>): string;

Transformation Algorithm:

The plugin follows this transformation algorithm:

  1. Collection Phase: Iterates through class body collecting static blocks and identifying static properties
  2. Block Processing: Converts static block bodies to expressions, optimizing single expressions to avoid IIFEs
  3. Insertion Strategy:
    • If static properties exist: Prepends block expressions to the next static property initializer
    • If no static properties exist: Creates a synthetic private property to hold the transformation
  4. Execution: Generates function calls after the class declaration/expression to execute remaining static blocks
/**
 * Converts static block AST nodes to executable expressions
 * Optimizes single expression blocks to avoid unnecessary IIFEs
 */
const blocksToExpressions = (blocks: Array<t.StaticBlock>) => t.Expression[];

/**
 * Prepends expressions to a static property initializer using sequence expressions
 */
const prependToInitializer = (
  prop: t.ClassProperty | t.ClassPrivateProperty,
  expressions: t.Expression[]
) => void;

/**
 * Creates a sequence expression or returns single expression if only one
 */
const maybeSequenceExpression = (expressions: t.Expression[]) => t.Expression;

Plugin Configuration

/**
 * Core Babel types and utilities used by the plugin
 */
import type { NodePath, Scope, types as t } from "@babel/core";
import { declare } from "@babel/helper-plugin-utils";
import {
  buildNamedEvaluationVisitor,
  enableFeature,
  FEATURES,
} from "@babel/helper-create-class-features-plugin";

interface PluginConfiguration {
  /** Plugin name identifier */
  name: "transform-class-static-block";
  
  /** Parser plugin registration (Babel 7 only) */
  manipulateOptions?: (opts: any, parser: { plugins: string[] }) => void;
  
  /** Enable static block features in class features plugin */
  pre(): void;
  
  /** AST transformation visitor */
  visitor: {
    ClassBody(path: NodePath<t.ClassBody>): void;
  };
}

Dependencies

Peer Dependencies:

  • @babel/core (^7.12.0) - Required Babel transformation core

Runtime Dependencies:

  • @babel/helper-create-class-features-plugin - Class feature transformation utilities
  • @babel/helper-plugin-utils - Plugin declaration utilities

Browser and Environment Support

  • Node.js: >=6.9.0 (Babel 8: ^20.19.0 || >=22.12.0)
  • Babel: >=7.12.0 (enforced by assertVersion)
  • Target: Transforms ES2022 class static blocks for older JavaScript environments
  • Integration: Works with Babel's class features plugin system
  • Parser Support: Automatically registers classStaticBlock parser plugin (Babel 7 only)

Usage Examples

Basic Babel Configuration:

// babel.config.js
module.exports = {
  presets: ["@babel/preset-env"],
  plugins: ["@babel/plugin-transform-class-static-block"]
};

With Class Properties Plugin:

module.exports = {
  plugins: [
    "@babel/plugin-transform-class-properties",
    "@babel/plugin-transform-class-static-block"
  ]
};

Programmatic Usage:

const babel = require("@babel/core");
const plugin = require("@babel/plugin-transform-class-static-block");

const result = babel.transformSync(code, {
  plugins: [plugin]
});

Types

/**
 * Babel AST node types used by the plugin
 */
interface t {
  isStaticBlock(node: any): node is t.StaticBlock;
  isClassProperty(node: any): node is t.ClassProperty;
  isClassPrivateProperty(node: any): node is t.ClassPrivateProperty;
  isExpressionStatement(node: any): node is t.ExpressionStatement;
  staticBlock(body: t.Statement[]): t.StaticBlock;
  privateName(id: t.Identifier): t.PrivateName;
  classPrivateProperty(
    key: t.PrivateName,
    value: t.Expression | null,
    decorators: any[],
    static: boolean
  ): t.ClassPrivateProperty;
  sequenceExpression(expressions: t.Expression[]): t.SequenceExpression;
  unaryExpression(operator: string, argument: t.Expression): t.UnaryExpression;
  callExpression(callee: t.Expression, arguments: t.Expression[]): t.CallExpression;
  thisExpression(): t.ThisExpression;
  returnStatement(argument: t.Expression | null): t.ReturnStatement;
  blockStatement(body: t.Statement[]): t.BlockStatement;
  inheritsComments<T extends t.Node>(child: T, parent: t.Node): T;
  cloneNode<T extends t.Node>(node: T): T;
}

interface NodePath<T = t.Node> {
  node: T;
  parent: t.Node;
  parentPath: NodePath;
  scope: Scope;
  get(key: string): NodePath;
  isClassExpression(): boolean;
  isStaticBlock(): boolean;
  isClassProperty(opts?: { static?: boolean }): boolean;
  isClassPrivateProperty(opts?: { static?: boolean }): boolean;
  isPrivate(): boolean;
  isExpression(): boolean;
  isStatement(): boolean;
  remove(): void;
  replaceWith(node: t.Node): void;
  insertAfter(nodes: t.Node | t.Node[]): void;
  unshiftContainer(key: string, nodes: t.Node | t.Node[]): void;
  pushContainer(key: string, nodes: t.Node | t.Node[]): void;
}

interface Scope {
  generateDeclaredUidIdentifier(name?: string): t.Identifier;
}

interface t.StaticBlock {
  type: "StaticBlock";
  body: t.Statement[];
}

interface t.ClassBody {
  type: "ClassBody";
  body: Array<t.ClassMethod | t.ClassProperty | t.ClassPrivateProperty | t.StaticBlock>;
}

docs

index.md

tile.json