Helper function to remap async functions to generators
npx @tessl/cli install tessl/npm-babel-helper-remap-async-to-generator@6.24.0babel-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.
npm install babel-helper-remap-async-to-generatorimport remapAsyncToGenerator from "babel-helper-remap-async-to-generator";For CommonJS:
const remapAsyncToGenerator = require("babel-helper-remap-async-to-generator");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")
});
}
}
};
}The helper is designed around several key components:
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 transformfile (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 generatorwrapAwait (Function, optional): Function identifier used to wrap await expressionsUsage 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"));The helper supports transformation of various async function types:
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);
};
})();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);
};
})();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);
}
}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);
}
};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:
await expr to yield exprwrapAwait helper is providedTransforms 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:
return() method)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;
}
}
}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;
})
`);The transformation maintains proper error handling semantics:
// 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;
}The helper relies on several Babel packages:
The helper handles several edge cases and error conditions:
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")
});
}
}
};
}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)
});
}
}
};
}