or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

index.mddocs/

Babel Plugin Transform Logical Assignment Operators

This Babel plugin transforms logical assignment operators (&&=, ||=, ??=) into equivalent short-circuited assignment expressions for JavaScript environments that don't natively support these ES2021 operators. The plugin provides comprehensive transformation logic with proper memoization to handle complex assignment targets safely.

Package Information

  • Package Name: @babel/plugin-transform-logical-assignment-operators
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install @babel/plugin-transform-logical-assignment-operators

Core Imports

This is a Babel plugin used through Babel configuration. It is not imported directly in user code:

{
  "plugins": ["@babel/plugin-transform-logical-assignment-operators"]
}

Basic Usage

Add the plugin to your Babel configuration to transform logical assignment operators:

{
  "plugins": ["@babel/plugin-transform-logical-assignment-operators"]
}

Input:

// Logical OR assignment
obj.x ||= 1;
arr[0] ||= "default";

// Logical AND assignment
user.preferences &&= { theme: "dark" };

// Nullish coalescing assignment
config.apiUrl ??= "https://api.example.com";

Output:

// Logical OR assignment
obj.x || (obj.x = 1);
arr[0] || (arr[0] = "default");

// Logical AND assignment
user.preferences && (user.preferences = { theme: "dark" });

// Nullish coalescing assignment
config.apiUrl ?? (config.apiUrl = "https://api.example.com");

Architecture

This plugin follows Babel's standard plugin architecture:

  • Build-time Transformation: Transforms source code at compile time, not runtime
  • Zero Configuration: No options or configuration required
  • Safe Operation: Preserves the original semantics of logical assignment operators
  • Memoization: Prevents side effects by evaluating complex expressions only once

Capabilities

Plugin Factory Function

The plugin exports a default function created using declare() from @babel/helper-plugin-utils that returns a Babel plugin object.

declare function PluginFactory(api: PluginAPI): PluginObject;
export default PluginFactory;

interface PluginAPI {
  assertVersion(version: number): void;
}

interface PluginObject {
  name: "transform-logical-assignment-operators";
  manipulateOptions?: (opts: any, parser: { plugins: string[] }) => void;
  visitor: {
    AssignmentExpression(path: NodePath<AssignmentExpression>): void;
  };
}

Plugin Configuration

This plugin accepts no configuration options and operates with fixed transformation behavior.

// Plugin options interface (empty)
interface PluginOptions {}

Usage Examples:

{
  "plugins": [
    "@babel/plugin-transform-logical-assignment-operators"
  ]
}

Transformation Logic

The plugin transforms three types of logical assignment operators into equivalent expressions that preserve evaluation semantics.

Logical OR Assignment (||=)

Transforms logical OR assignment operators into conditional assignment expressions.

Input: x ||= y
Output: x || (x = y)

// Handles expressions like:
// obj.prop ||= value
// arr[index] ||= value
// computed[key] ||= value

Logical AND Assignment (&&=)

Transforms logical AND assignment operators into conditional assignment expressions.

Input: x &&= y
Output: x && (x = y)

// Handles expressions like:
// obj.prop &&= value
// arr[index] &&= value  
// computed[key] &&= value

Nullish Coalescing Assignment (??=)

Transforms nullish coalescing assignment operators into logical expressions using the nullish coalescing operator with conditional assignment.

Input: x ??= y
Output: x ?? (x = y)

// Handles expressions like:
// obj.prop ??= value → obj.prop ?? (obj.prop = value)
// arr[index] ??= value → arr[index] ?? (arr[index] = value)
// computed[key] ??= value → computed[key] ?? (computed[key] = value)

Safe Memoization

The plugin uses Babel's scope.maybeGenerateMemoised() to intelligently determine when memoization is needed for complex member expressions, preventing side effects during property access.

// The plugin memoizes complex object expressions and computed properties separately
// Uses t.assignmentExpression("=", memo, originalExpression) for memoization

Memoization Examples:

// Simple properties don't need memoization
// Input: obj.x ||= 1
// Output: obj.x || (obj.x = 1)

// Complex objects are memoized
// Input: deep.obj.x ||= 1
// Output: (_deep$obj = deep.obj).x || (_deep$obj.x = 1)

// Computed properties with side effects are memoized
// Input: obj[++key] ||= 1
// Output: obj[_key = ++key] || (obj[_key] = 1)

// Both object and property memoization when needed
// Input: deep.obj[++key] ||= 1  
// Output: (_deep$obj = deep.obj)[_key = ++key] || (_deep$obj[_key] = 1)

Parser Plugin Integration

Conditionally adds parser support for logical assignment operators based on Babel version. The behavior differs between Babel 7 and Babel 8.

// Babel version-specific conditional logic
manipulateOptions: process.env.BABEL_8_BREAKING
  ? undefined
  : (_, parser) => parser.plugins.push("logicalAssignment");

Babel Version Behavior:

  • Babel 7: Adds "logicalAssignment" parser plugin to enable syntax parsing
  • Babel 8: undefined - logical assignment syntax is built-in to the parser

Implementation Details:

  • Uses process.env.BABEL_8_BREAKING environment variable for version detection
  • Only modifies parser plugins when running under Babel 7
  • The logicalAssignment parser plugin enables recognition of ||=, &&=, and ??= operators

Error Handling

The plugin handles transformation errors gracefully within Babel's error reporting system. It does not throw custom exceptions but relies on Babel's built-in AST validation and error handling.

Version Requirements

// Plugin version requirements
interface VersionRequirements {
  babel: "^7.0.0-0";  // Peer dependency
  node: ">=6.9.0";    // Minimum Node.js version
}

TypeScript Support

The plugin is written in TypeScript and provides full type definitions:

  • Source: src/index.ts
  • Compiled Output: lib/index.js
  • Type Definitions: lib/index.d.ts
  • Type Safety: Full AST type annotations using @babel/types

Implementation Details

AST Node Types

The plugin works with these Babel AST node types and validates operators using t.LOGICAL_OPERATORS:

interface AssignmentExpression {
  type: "AssignmentExpression";
  operator: string; // "||=", "&&=", or "??="
  left: LVal;
  right: Expression;
}

// The plugin extracts logical operator using operator.slice(0, -1)
// Then validates against t.LOGICAL_OPERATORS: ["||", "&&", "??"]

type LVal = 
  | Identifier
  | MemberExpression
  | ArrayPattern
  | ObjectPattern
  | RestElement
  | TSParameterProperty;

// Key AST utilities used:
// - t.cloneNode() for safe node duplication
// - t.logicalExpression() for creating logical expressions
// - t.assignmentExpression() for creating assignment expressions
// - scope.maybeGenerateMemoised() for intelligent memoization

Visitor Method

The core transformation logic is implemented in the AssignmentExpression visitor:

interface Visitor {
  AssignmentExpression(path: NodePath<AssignmentExpression>): void;
}

interface NodePath<T> {
  node: T;
  replaceWith(node: Expression): void;
  // ... other NodePath methods
}

The visitor method implementation:

  1. Operator Validation: Uses operator.slice(0, -1) to extract logical part, validates with t.LOGICAL_OPERATORS.includes(operatorTrunc)
  2. Node Cloning: Creates safe copies using t.cloneNode(left) to avoid mutation issues
  3. Memoization Logic:
    • For MemberExpression: Uses scope.maybeGenerateMemoised(object) for object memoization
    • For computed properties: Uses scope.maybeGenerateMemoised(property) for property memoization
    • Generates assignment expressions to store memoized values
  4. Transformation: Creates t.logicalExpression() with original operator and assignment expression
  5. Replacement: Uses path.replaceWith() to substitute the transformed expression

Special Handling:

  • Super Objects: Includes special logic to handle Super objects in memoization
  • TypeScript Casts: Uses specific type assertions for complex member expression handling
  • Property Types: Handles both regular properties and PrivateName properties with type guards