or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-babel--plugin-transform-optional-chaining

Transform optional chaining operators into a series of nil checks for backward compatibility

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/@babel/plugin-transform-optional-chaining@7.27.x

To install, run

npx @tessl/cli install tessl/npm-babel--plugin-transform-optional-chaining@7.27.0

index.mddocs/

@babel/plugin-transform-optional-chaining

@babel/plugin-transform-optional-chaining is a Babel plugin that transforms JavaScript optional chaining operators (?.) into backward-compatible series of nil checks, enabling the use of modern optional chaining syntax in environments that don't natively support it. The plugin handles both optional member expressions (obj?.prop) and optional call expressions (func?.()) by converting them into conditional logic that safely checks for null or undefined values.

Package Information

  • Package Name: @babel/plugin-transform-optional-chaining
  • Package Type: npm (Babel Plugin)
  • Language: TypeScript
  • Installation: npm install --save-dev @babel/plugin-transform-optional-chaining

Core Imports

import pluginTransformOptionalChaining from "@babel/plugin-transform-optional-chaining";

For CommonJS:

const pluginTransformOptionalChaining = require("@babel/plugin-transform-optional-chaining");

Named imports for transformation functions and types:

import { transform, transformOptionalChain, type Options } from "@babel/plugin-transform-optional-chaining";
import type { NodePath, types as t } from "@babel/core";

Basic Usage

Babel Configuration

// babel.config.js
module.exports = {
  plugins: [
    ["@babel/plugin-transform-optional-chaining", { loose: false }]
  ]
};

Plugin Options

// With TypeScript configuration
import type { Options } from "@babel/plugin-transform-optional-chaining";

const options: Options = {
  loose: true  // Enable loose transformation mode
};

Transformation Examples

Input code:

// Optional member expressions
const name = obj?.user?.name;

// Optional call expressions  
const result = func?.();

// Chained optional calls
const data = api?.getUser?.()?.profile?.data;

Output (strict mode):

var _obj$user, _func;

// Optional member expressions
const name = (_obj$user = obj == null ? void 0 : obj.user) == null ? void 0 : _obj$user.name;

// Optional call expressions
const result = (_func = func) == null ? void 0 : _func();

// Chained optional calls  
var _api$getUser, _api$getUser2, _api$getUser2$profil;
const data = (_api$getUser = api == null ? void 0 : api.getUser) == null ? void 0 : (_api$getUser2 = _api$getUser.call(api)) == null ? void 0 : (_api$getUser2$profil = _api$getUser2.profile) == null ? void 0 : _api$getUser2$profil.data;

Capabilities

Plugin Factory Function (Default Export)

Creates a Babel plugin configuration with specified options.

/**
 * Main plugin factory function that returns a Babel plugin configuration
 * @param api - Babel API object providing version checking and assumptions
 * @param options - Plugin configuration options
 * @returns Babel plugin configuration object
 */
export default function(api: any, options: Options): BabelPlugin;

interface BabelPlugin {
  name: string;
  manipulateOptions?: (opts: any, parser: any) => void;
  visitor: {
    "OptionalCallExpression|OptionalMemberExpression"(
      path: NodePath<t.OptionalCallExpression | t.OptionalMemberExpression>
    ): void;
  };
}

Transform Function

Main transformation function for optional chaining expressions that determines the appropriate nullish value and wrapping logic.

/**
 * Main transformation function for optional chaining expressions
 * @param path - AST path to the optional chaining expression
 * @param assumptions - Configuration object containing pureGetters and noDocumentAll boolean properties
 */
export function transform(
  path: NodePath<t.OptionalCallExpression | t.OptionalMemberExpression>,
  assumptions: { pureGetters: boolean; noDocumentAll: boolean }
): void;

Core Transformation Function

The core transformation logic that converts optional chaining into conditional checks.

/**
 * Core transformation logic for optional chaining with configurable assumptions
 * @param path - AST path to the optional chaining expression
 * @param assumptions - Configuration object containing pureGetters and noDocumentAll boolean properties
 * @param replacementPath - Path where the transformed expression should be placed
 * @param ifNullish - Expression to use when the chain is nullish
 * @param wrapLast - Optional function to wrap the final expression
 */
export function transformOptionalChain(
  path: NodePath<t.OptionalCallExpression | t.OptionalMemberExpression>,
  assumptions: { pureGetters: boolean; noDocumentAll: boolean },
  replacementPath: NodePath<t.Expression>,
  ifNullish: t.Expression,
  wrapLast?: (value: t.Expression) => t.Expression
): void;

Configuration Types

Plugin Options

/**
 * Configuration options for the optional chaining transformation plugin
 */
export interface Options {
  /** Enable loose transformation mode for more compact output */
  loose?: boolean;
}

Babel Core Types

These types are required from @babel/core when using the transformation functions:

import type { NodePath, types as t } from "@babel/core";

// Key types used in the API signatures
type OptionalCallExpression = t.OptionalCallExpression;
type OptionalMemberExpression = t.OptionalMemberExpression;
type Expression = t.Expression;

Plugin Behavior

Transformation Modes

Strict Mode (default):

  • Uses explicit null and undefined checks (=== null || === void 0)
  • Handles document.all edge case properly
  • More verbose but safer output

Loose Mode (loose: true):

  • Uses loose equality checks (== null)
  • Ignores document.all edge case
  • More compact output

Assumption Handling

The plugin respects Babel's assumption system:

  • noDocumentAll: Derived from api.assumption("noDocumentAll") ?? loose
  • pureGetters: Derived from api.assumption("pureGetters") ?? loose

When pureGetters is true, the plugin avoids using Function#call for method invocations on simple member expressions.

AST Node Processing

The plugin visitor targets:

  • OptionalCallExpression: Expressions like func?.()
  • OptionalMemberExpression: Expressions like obj?.prop

For each matched node, it:

  1. Converts optional syntax to regular syntax
  2. Generates appropriate nullish checks
  3. Handles method context preservation for calls
  4. Manages temporary variable creation for complex expressions

Edge Cases

  • Eval calls: eval?.() becomes (0,eval)() for indirect evaluation
  • Method calls: Preserves proper this context using .call() or .bind()
  • Delete operations: delete obj?.prop becomes conditional with true fallback
  • Nested chains: Handles deeply nested optional chains with proper memoization
  • Transparent wrappers: Works correctly with TypeScript type assertions and parentheses