or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-babel-helper-remap-async-to-generator

Helper function to remap async functions to generators

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/babel-helper-remap-async-to-generator@6.24.x

To install, run

npx @tessl/cli install tessl/npm-babel-helper-remap-async-to-generator@6.24.0

index.mddocs/

babel-helper-remap-async-to-generator

babel-helper-remap-async-to-generator is a Babel helper utility that transforms async/await syntax into generator functions, enabling async/await functionality to work in environments that support generators but not native async/await. It handles the complex transformation of async functions, await expressions, and for-await loops into their generator-based equivalents, including proper error handling and iterator management.

Package Information

  • Package Name: babel-helper-remap-async-to-generator
  • Package Type: npm
  • Language: JavaScript (used with Babel transform plugins)
  • Installation: npm install babel-helper-remap-async-to-generator
  • Version: 6.24.1

Core Imports

import remapAsyncToGenerator from "babel-helper-remap-async-to-generator";

For CommonJS:

const remapAsyncToGenerator = require("babel-helper-remap-async-to-generator");

Basic Usage

This helper is typically used within Babel transform plugins to convert async functions to generators:

import remapAsyncToGenerator from "babel-helper-remap-async-to-generator";

export default function() {
  return {
    visitor: {
      Function(path, state) {
        if (!path.node.async || path.node.generator) return;
        
        // Transform async function to generator using the helper
        remapAsyncToGenerator(path, state.file, {
          wrapAsync: state.addHelper("asyncToGenerator")
        });
      }
    }
  };
}

Architecture

The helper is designed around several key components:

  • Main Transformation Function: The default export that orchestrates the complete transformation
  • AST Visitor Pattern: Uses Babel's visitor pattern to traverse and transform await expressions and for-await loops
  • Template System: Uses Babel templates to generate consistent transformed code structures
  • Scope Management: Handles variable naming conflicts and maintains proper lexical scoping
  • Error Handling Preservation: Maintains the semantics of try/catch blocks and error propagation

Capabilities

Main Transformation Function

Transforms an async function node into a generator-based equivalent.

/**
 * Transform an async function to generator-based implementation
 * @param {NodePath} path - Babel traverse NodePath representing the async function
 * @param {Object} file - Babel file object (can be null for backward compatibility)
 * @param {Object} helpers - Helper functions object
 * @param {Function} helpers.wrapAsync - Function identifier for async wrapper
 * @param {Function} [helpers.wrapAwait] - Optional function identifier for await wrapper
 */
function remapAsyncToGenerator(path, file, helpers);

Parameters:

  • path (NodePath): Babel traverse NodePath representing the async function to transform
  • file (Object): Babel file object containing metadata and helper registration (can be null for Babel <=6.15 compatibility)
  • helpers (Object): Configuration object containing helper function identifiers
    • wrapAsync (Function): Function identifier used to wrap the transformed generator
    • wrapAwait (Function, optional): Function identifier used to wrap await expressions

Usage Examples:

// Basic usage in a Babel plugin
remapAsyncToGenerator(path, state.file, {
  wrapAsync: state.addHelper("asyncToGenerator")
});

// With custom await wrapper
remapAsyncToGenerator(path, state.file, {
  wrapAsync: state.addHelper("asyncToGenerator"),
  wrapAwait: state.addHelper("awaitWrapper")
});

// Legacy usage (Babel <=6.15 compatibility)
remapAsyncToGenerator(path, state.addHelper("asyncToGenerator"));

Async Function Type Support

The helper supports transformation of various async function types:

Arrow Functions

Transforms async arrow functions to generators with proper scope handling.

// Input
const asyncArrow = async (x) => await x;

// Transformed (conceptual output)
const asyncArrow = (() => {
  var _ref = _asyncToGenerator(function* (x) {
    return yield x;
  });
  return function(x) {
    return _ref.apply(this, arguments);
  };
})();

Function Declarations

Transforms async function declarations to generator-based implementations.

// Input
async function myFunction(a, b) {
  return await someAsyncOperation(a, b);
}

// Transformed (conceptual output)
let myFunction = (() => {
  var _ref = _asyncToGenerator(function* (a, b) {
    return yield someAsyncOperation(a, b);
  });
  return function myFunction(a, b) {
    return _ref.apply(this, arguments);
  };
})();

Class Methods

Transforms async class methods while preserving method semantics.

// Input
class MyClass {
  async myMethod(x) {
    return await this.process(x);
  }
}

// Transformed (conceptual output)
class MyClass {
  myMethod(x) {
    return _asyncToGenerator(function* () {
      return yield this.process(x);
    }).call(this);
  }
}

Object Methods

Transforms async object methods with proper this binding.

// Input
const obj = {
  async process(data) {
    return await this.transform(data);
  }
};

// Transformed (conceptual output)
const obj = {
  process(data) {
    return _asyncToGenerator(function* () {
      return yield this.transform(data);
    }).call(this);
  }
};

Await Expression Transformation

Converts await expressions to yield expressions within the generated function body.

// Internal visitor - transforms await expressions
AwaitExpression: {
  enter(path, state) {
    // Converts: await expression
    // To: yield expression (optionally wrapped)
  }
}

Transformation Details:

  • Converts await expr to yield expr
  • Optionally wraps the expression if wrapAwait helper is provided
  • Maintains expression precedence and evaluation order

For-Await Loop Support

Transforms for-await-of loops into generator-based iteration with proper async iterator protocol.

// Internal visitor - transforms for-await statements
ForAwaitStatement: {
  enter(path, state) {
    // Converts: for await (item of asyncIterable)
    // To: Complex generator-based iteration with error handling
  }
}

For-Await Transformation Features:

  • Implements proper async iterator protocol
  • Handles iterator cleanup (return() method)
  • Preserves error handling semantics
  • Supports destructuring patterns in loop variables
  • Maintains proper scoping for loop variables

Example transformation:

// Input
for await (const item of asyncIterable) {
  console.log(item);
}

// Transformed (simplified conceptual output)
var _iteratorCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
  for (var _iterator = getAsyncIterator(asyncIterable), _step, _value;
       (_step = yield awaitWrapper(_iterator.next()),
        _iteratorCompletion = _step.done,
        _value = yield awaitWrapper(_step.value),
        !_iteratorCompletion);
       _iteratorCompletion = true) {
    const item = _value;
    console.log(item);
  }
} catch (err) {
  _didIteratorError = true;
  _iteratorError = err;
} finally {
  try {
    if (!_iteratorCompletion && _iterator.return) {
      yield awaitWrapper(_iterator.return());
    }
  } finally {
    if (_didIteratorError) {
      throw _iteratorError;
    }
  }
}

Template System

The helper uses Babel templates for consistent code generation:

// Internal templates for code generation
const buildWrapper = template(`
  (() => {
    var REF = FUNCTION;
    return function NAME(PARAMS) {
      return REF.apply(this, arguments);
    };
  })
`);

const namedBuildWrapper = template(`
  (() => {
    var REF = FUNCTION;
    function NAME(PARAMS) {
      return REF.apply(this, arguments);
    }
    return NAME;
  })
`);

Error Handling Preservation

The transformation maintains proper error handling semantics:

  • Try/catch blocks are preserved around transformed code
  • Error propagation works correctly through yield expressions
  • Finally blocks execute at appropriate times
  • Iterator cleanup happens even when errors occur

Type Definitions

// Babel traverse types
interface NodePath {
  node: Node;
  scope: Scope;
  parent: Node;
  parentPath: NodePath;
  isArrowFunctionExpression(): boolean;
  isFunctionDeclaration(): boolean;
  isClassMethod(): boolean;
  isObjectMethod(): boolean;
  traverse(visitor: Object, state?: Object): void;
  replaceWith(node: Node): void;
  replaceWithMultiple(nodes: Node[]): void;
  skip(): void;
  remove(): void;
}

interface Scope {
  generateUidIdentifier(name: string): Identifier;
}

// Helper configuration
interface Helpers {
  wrapAsync: Function;
  wrapAwait?: Function;
}

// Babel file object (can be null for backward compatibility)
interface File {
  addHelper(name: string): Function;
}

Dependencies

The helper relies on several Babel packages:

  • babel-runtime: Runtime helpers for generated code
  • babel-template: Template string parsing for code generation
  • babel-types: AST node creation and manipulation utilities
  • babel-traverse: AST traversal utilities
  • babel-helper-function-name: Function naming utilities for anonymous functions

Error Conditions

The helper handles several edge cases and error conditions:

  • Invalid NodePath: If the provided path doesn't represent a function, the transformation is skipped
  • Missing Helpers: If required helper functions aren't provided, the transformation may fail
  • Nested Async Functions: Inner async functions are properly handled and transformed recursively
  • Complex Scoping: Variable name conflicts are resolved using Babel's scope management

Integration Examples

With babel-plugin-transform-async-to-generator

import remapAsyncToGenerator from "babel-helper-remap-async-to-generator";

export default function() {
  return {
    inherits: require("babel-plugin-syntax-async-functions"),
    visitor: {
      Function(path, state) {
        if (!path.node.async || path.node.generator) return;
        
        remapAsyncToGenerator(path, state.file, {
          wrapAsync: state.addHelper("asyncToGenerator")
        });
      }
    }
  };
}

With babel-plugin-transform-async-to-module-method

import remapAsyncToGenerator from "babel-helper-remap-async-to-generator";

export default function() {
  return {
    inherits: require("babel-plugin-syntax-async-functions"),
    visitor: {
      Function(path, state) {
        if (!path.node.async || path.node.generator) return;
        
        remapAsyncToGenerator(path, state.file, {
          wrapAsync: state.addImport(state.opts.module, state.opts.method)
        });
      }
    }
  };
}