or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-babel--plugin-proposal-nullish-coalescing-operator

Babel plugin that transforms nullish coalescing operator (??) syntax into equivalent conditional expressions compatible with older JavaScript environments

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/@babel/plugin-proposal-nullish-coalescing-operator@7.18.x

To install, run

npx @tessl/cli install tessl/npm-babel--plugin-proposal-nullish-coalescing-operator@7.18.0

index.mddocs/

@babel/plugin-proposal-nullish-coalescing-operator

@babel/plugin-proposal-nullish-coalescing-operator is a Babel plugin that transforms nullish coalescing operator (??) syntax into equivalent conditional expressions compatible with older JavaScript environments. It converts expressions like a ?? b into a !== null && a !== void 0 ? a : b, handling edge cases like the document.all quirk in browsers.

Package Information

  • Package Name: @babel/plugin-proposal-nullish-coalescing-operator
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install --save-dev @babel/plugin-proposal-nullish-coalescing-operator

Core Imports

This plugin is used in Babel configuration and not imported directly in code:

// babel.config.js
module.exports = {
  plugins: ["@babel/plugin-proposal-nullish-coalescing-operator"]
};

With options:

// babel.config.js
module.exports = {
  plugins: [
    ["@babel/plugin-proposal-nullish-coalescing-operator", { loose: true }]
  ]
};

Using Babel assumptions:

// babel.config.js  
module.exports = {
  plugins: ["@babel/plugin-proposal-nullish-coalescing-operator"],
  assumptions: {
    noDocumentAll: true
  }
};

Plugin Implementation Imports

For plugin development or understanding the implementation:

import { declare } from "@babel/helper-plugin-utils";
import syntaxNullishCoalescingOperator from "@babel/plugin-syntax-nullish-coalescing-operator";
import { types as t, template } from "@babel/core";

Basic Usage

Input code with nullish coalescing operator:

const result = a ?? b;
const nested = obj.prop ?? defaultValue;
const chained = first ?? second ?? third;

Output after transformation (strict mode):

const result = a !== null && a !== void 0 ? a : b;
const nested = (_obj$prop = obj.prop) !== null && _obj$prop !== void 0 ? _obj$prop : defaultValue;
const chained = (_first = first) !== null && _first !== void 0 ? _first : (_second = second) !== null && _second !== void 0 ? _second : third;

Output after transformation (loose mode):

const result = a != null ? a : b;
const nested = (_obj$prop = obj.prop) != null ? _obj$prop : defaultValue;
const chained = (_first = first) != null ? _first : (_second = second) != null ? _second : third;

Capabilities

Plugin Function

Main Babel plugin function that provides nullish coalescing operator transformation.

/**
 * Babel plugin for transforming nullish coalescing operator
 * Uses the declare function from @babel/helper-plugin-utils
 */
const plugin = declare((api: any, options: Options) => {
  api.assertVersion(7);
  const noDocumentAll = api.assumption("noDocumentAll") ?? options.loose;

  return {
    name: "proposal-nullish-coalescing-operator",
    inherits: syntaxNullishCoalescingOperator.default,
    visitor: {
      LogicalExpression(path: any): void;
    }
  };
});

export default plugin;

Plugin Options

Configuration options for the nullish coalescing operator transformation.

/**
 * Plugin configuration options
 */
interface Options {
  /** 
   * Use loose transformation (a != null instead of a !== null && a !== void 0)
   * Can also be controlled via noDocumentAll assumption
   */
  loose?: boolean;
}

export { Options };

/** Required dependencies for plugin implementation */
declare module \"@babel/helper-plugin-utils\" {
  export function declare(builder: (api: any, options: any) => any): any;
}

declare module \"@babel/plugin-syntax-nullish-coalescing-operator\" {
  const plugin: { default: any };
  export default plugin;
}

/** Babel visitor interface for LogicalExpression nodes */
interface PluginVisitor {
  LogicalExpression(path: {
    node: {
      operator: string;
      left: any;
      right: any;
    };
    scope: {
      isStatic(node: any): boolean;
      path: { isPattern(): boolean };
      generateUidIdentifierBasedOnNode(node: any): any;
      push(options: { id: any }): void;
      buildUndefinedNode(): any;
    };
    replaceWith(node: any): void;
  }): void;
}

Transformation Modes

The plugin supports two transformation modes:

Strict Mode (default):

  • Uses separate null and undefined checks: a !== null && a !== void 0
  • Handles the document.all edge case correctly (document.all == null but is not nullish)
  • Fully compliant with ECMAScript specification

Loose Mode:

  • Uses single null check: a != null
  • Simpler output but may not handle document.all edge case
  • Activated with loose: true option or noDocumentAll: true assumption
  • The plugin checks api.assumption("noDocumentAll") ?? loose to determine mode

Scope Analysis

The plugin includes sophisticated scope analysis to avoid variable name conflicts:

  • Static References: When the left operand is static (scope.isStatic(node.left)), no temporary variable is created
  • Dynamic References: For complex expressions, generates unique temporary variables using scope.generateUidIdentifierBasedOnNode(node.left) and pushes them to scope
  • Pattern Context: When in pattern context (scope.path.isPattern()), wraps the expression in an IIFE to ensure proper scoping: (() => ${path.node})()

Transformation Algorithm

The plugin transforms nullish coalescing expressions using this logic:

  1. Operator Check: Only processes LogicalExpression nodes with ?? operator
  2. Reference Handling:
    • Static references (literals, identifiers): Uses reference directly
    • Pattern context: Wraps in IIFE for proper scoping
    • Dynamic expressions: Creates temporary variable with unique identifier
  3. Conditional Replacement: Replaces a ?? b with t.conditionalExpression() based on mode:
    • Strict: Uses t.logicalExpression("&&", ...) with separate null and undefined checks
    • Loose: Uses t.binaryExpression("!=", ...) with single null check
    • Creates t.assignmentExpression("=", ref, node.left) for dynamic references

Supported Contexts

The plugin handles nullish coalescing in various contexts:

  • Simple expressions: a ?? b
  • Object property access: obj.prop ?? default
  • Function calls: fn() ?? backup
  • Function parameter defaults: function(x = a ?? b) {}
  • Destructuring defaults: const { prop = a ?? b } = obj
  • Nested expressions: (a ?? b) ?? c

Configuration Examples

Basic Configuration

{
  "plugins": ["@babel/plugin-proposal-nullish-coalescing-operator"]
}

With Loose Mode

{
  "plugins": [
    ["@babel/plugin-proposal-nullish-coalescing-operator", { "loose": true }]
  ]
}

Using Babel Assumptions

{
  "plugins": ["@babel/plugin-proposal-nullish-coalescing-operator"],
  "assumptions": {
    "noDocumentAll": true
  }
}

Plugin Dependencies

This plugin automatically inherits @babel/plugin-syntax-nullish-coalescing-operator and doesn't require it to be explicitly included:

{
  "plugins": [
    "@babel/plugin-proposal-nullish-coalescing-operator"
  ]
}

Inherited Syntax Plugin: @babel/plugin-syntax-nullish-coalescing-operator is automatically inherited via the inherits property, enabling parsing of the nullish coalescing operator syntax.

Integration with Other Plugins

The plugin works seamlessly with other Babel plugins and presets. No additional syntax plugins are required.