Skip to content

Commit b112424

Browse files
authored
feat: add await expression support (#157)
Add `builders.awaitExpression()` and corresponding proxy/type definitions to allow programmatic creation and parsing of `await` expressions. Closes #114
1 parent 12917c0 commit b112424

5 files changed

Lines changed: 84 additions & 0 deletions

File tree

src/builders.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { literalToAst } from "./proxy/_utils";
55
import type { Proxified } from "./types";
66
import { parseExpression } from "./code";
77
import { proxifyBinaryExpression } from "./proxy/binary-expression";
8+
import { proxifyAwaitExpression } from "./proxy/await-expression";
89

910
const b = recast.types.builders;
1011

@@ -66,6 +67,15 @@ export const builders = {
6667
);
6768
return proxifyBinaryExpression(node as any);
6869
},
70+
/**
71+
* Create an await expression node.
72+
*/
73+
awaitExpression(argument: any): Proxified {
74+
75+
const argAst = argument?.$ast || literalToAst(argument);
76+
const node = b.awaitExpression(argAst as any);
77+
return proxifyAwaitExpression(node as any);
78+
},
6979
/**
7080
* Create a proxified version of a literal value.
7181
*/

src/proxy/await-expression.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import type { AwaitExpression } from "@babel/types";
2+
import type { ProxifiedAwaitExpression, ProxifiedModule } from "./types";
3+
import { MagicastError } from "../error";
4+
import { proxify } from "./proxify";
5+
import { createProxy } from "./_utils";
6+
7+
export function proxifyAwaitExpression(
8+
node: AwaitExpression,
9+
mod?: ProxifiedModule,
10+
): ProxifiedAwaitExpression {
11+
if (node.type !== "AwaitExpression") {
12+
throw new MagicastError("Not an await expression");
13+
}
14+
return createProxy(
15+
node,
16+
{
17+
$type: "await-expression",
18+
$argument: proxify(node.argument, mod),
19+
},
20+
{},
21+
) as ProxifiedAwaitExpression;
22+
}

src/proxy/proxify.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { proxifyBinaryExpression } from "./binary-expression";
1313
import { proxifyBlockStatement } from "./block-statement";
1414
import { proxifyFunctionExpression } from "./function-expression";
1515
import { LITERALS_AST, LITERALS_TYPEOF } from "./_utils";
16+
import { proxifyAwaitExpression } from "./await-expression";
1617

1718
const _cache = new WeakMap<ASTNode, any>();
1819

@@ -81,6 +82,10 @@ export function proxify<T>(node: ASTNode, mod?: ProxifiedModule): Proxified<T> {
8182
proxy = proxifyBinaryExpression(node, mod);
8283
break;
8384
}
85+
case "AwaitExpression":{
86+
proxy = proxifyAwaitExpression(node, mod);
87+
break;
88+
}
8489
case "BlockStatement": {
8590
proxy = proxifyBlockStatement(node, mod);
8691
break;

src/proxy/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,11 @@ export type ProxifiedBinaryExpression = ProxyBase & {
9595
$operator: BinaryOperator;
9696
};
9797

98+
export type ProxifiedAwaitExpression = ProxyBase & {
99+
$type: "await-expression";
100+
$argument: Proxified;
101+
}
102+
98103
export type ProxifiedBlockStatement = ProxyBase & {
99104
$type: "blockStatement";
100105
$body: ProxifiedArray;
@@ -171,6 +176,7 @@ export type ProxifiedValue =
171176
| ProxifiedArrowFunctionExpression
172177
| ProxifiedFunctionExpression
173178
| ProxifiedBinaryExpression
179+
| ProxifiedAwaitExpression
174180
| ProxifiedBlockStatement;
175181

176182
export type ProxyType = ProxifiedValue["$type"];
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { describe, expect, it } from "vitest";
2+
import { builders, parseModule } from "magicast";
3+
import { generate } from "../_utils";
4+
5+
describe("builders/awaitExpression", () => {
6+
it("basic await expression", async () => {
7+
const expr = builders.awaitExpression(
8+
builders.functionCall("fetch", "https://example.com"),
9+
);
10+
expect(expr.$type).toBe("await-expression");
11+
12+
const mod = parseModule("");
13+
mod.exports.a = expr;
14+
15+
expect(await generate(mod)).toMatchInlineSnapshot(`
16+
"export const a = await fetch("https://example.com");"
17+
`);
18+
});
19+
20+
it("await with raw expression", async () => {
21+
const expr = builders.awaitExpression(
22+
builders.raw('import("./module")'),
23+
);
24+
expect(expr.$type).toBe("await-expression");
25+
26+
const mod = parseModule("");
27+
mod.exports.a = expr;
28+
29+
expect(await generate(mod)).toMatchInlineSnapshot(`
30+
"export const a = await import("./module");"
31+
`);
32+
});
33+
34+
it("parse existing await expression", async () => {
35+
const mod = parseModule('export const a = await fetch("https://example.com");');
36+
const a = mod.exports.a;
37+
expect(a.$type).toBe("await-expression");
38+
expect(a.$argument.$type).toBe("function-call");
39+
expect(a.$argument.$callee).toBe("fetch");
40+
});
41+
});

0 commit comments

Comments
 (0)