[BUG] `$$escape` does not transform code as expected
Describe the bug
I'm using ts-macros to transform synchronous functions into asynchronous functions. However, the $$escape macro is not working as expected. Instead of directly modifying the function to be escaped, it is wrapping the function in an IIFE, which is not the desired output.
Code to reproduce
import * as ts from "typescript"
import { $$escape, $$raw, RawContext } from "ts-macros"
function $asyncify(fn: Function) {
return $$escape!(() => {
return $$raw!((ctx: RawContext, fnAst: ts.FunctionDeclaration) => {
if (ctx.ts.isFunctionDeclaration(fnAst) || ctx.ts.isArrowFunction(fnAst) || ctx.ts.isFunctionExpression(fnAst)) {
let asyncFnAst = ctx.factory.updateFunctionDeclaration(
fnAst,
[ctx.factory.createModifier(ctx.ts.SyntaxKind.AsyncKeyword)],
fnAst.asteriskToken,
fnAst.name,
fnAst.typeParameters,
fnAst.parameters,
fnAst.type,
fnAst.body
);
return asyncFnAst;
}
})
})
}
$asyncify!(function foo() {
return console.log(1);
})
const foo2 = $asyncify!(() => {
return console.log(2);
})
const foo3 = $asyncify!(function () {
return console.log(3);
})
The current output is:
(() => {
async function foo() {
return console.log(1);
}
})();
const foo2 = (() => {
async function () {
return console.log(2);
}
})();
const foo3 = (() => {
async function () {
return console.log(3);
}
})();
Expected behavior
However, my expected output is:
async function foo() {
return console.log(1);
}
const foo2 = async () => {
return console.log(2);
};
const foo3 = async function () {
return console.log(3);
};
Hello! The fnAst argument is actually a ts.FunctionExpression and not a ts.FunctionDeclaration, you have to call updateFunctionExpression instead and then call createExpressionStatement:
function $asyncify(fn: Function) {
return $$raw!((ctx: RawContext, fnAst: ts.FunctionExpression) => {
if (
ctx.ts.isArrowFunction(fnAst) ||
ctx.ts.isFunctionExpression(fnAst)
) {
let asyncFnAst = ctx.factory.updateFunctionExpression(
fnAst,
[ctx.factory.createModifier(ctx.ts.SyntaxKind.AsyncKeyword)],
fnAst.asteriskToken,
fnAst.name,
fnAst.typeParameters,
fnAst.parameters,
fnAst.type,
fnAst.body || ts.factory.createBlock([])
) as unknown as ts.Expression;
return ctx.factory.createExpressionStatement(asyncFnAst);
}
});
}
This fixes it for the second and third example, but ts-macros does seem to be adding unnecessary parenthesis around the function declaration for some reason, I'll look into that!