CtrlK
BlogDocsLog inGet started
Tessl Logo

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

Helper function to remap async functions to generators

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-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)
        });
      }
    }
  };
}

docs

index.md

tile.json