Skip to content

Commit

Permalink
feat: support builder.newExpression
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Apr 5, 2023
1 parent 4983f47 commit cf5ad6d
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 0 deletions.
11 changes: 11 additions & 0 deletions src/builders.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as recast from "recast";
import { proxifyFunctionCall } from "./proxy/function-call";
import { proxifyNewExpression } from "./proxy/new-expression";
import { literalToAst } from "./proxy/_utils";
import { Proxified } from "./types";
import { parseExpression } from "./code";
Expand All @@ -17,6 +18,16 @@ export const builders = {
);
return proxifyFunctionCall(node as any);
},
/**
* Create a new expression node.
*/
newExpression(callee: string, ...args: any[]): Proxified {
const node = b.newExpression(
b.identifier(callee),
args.map((i) => literalToAst(i) as any)
);
return proxifyNewExpression(node as any);
},
/**
* Create a proxified version of a literal value.
*/
Expand Down
38 changes: 38 additions & 0 deletions src/proxy/new-expression.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { ASTNode } from "../types";
import { MagicastError } from "../error";
import { createProxy } from "./_utils";
import { proxifyArrayElements } from "./array";
import { ProxifiedModule, ProxifiedNewExpression } from "./types";

export function proxifyNewExpression<T extends []>(
node: ASTNode,
mod?: ProxifiedModule
): ProxifiedNewExpression<T> {
if (node.type !== "NewExpression") {
throw new MagicastError("Not a new expression");
}

function stringifyExpression(node: ASTNode): string {
if (node.type === "Identifier") {
return node.name;
}
if (node.type === "MemberExpression") {
return `${stringifyExpression(node.object)}.${stringifyExpression(
node.property
)}`;
}
throw new MagicastError("Not implemented");
}

const argumentsProxy = proxifyArrayElements<T>(node, node.arguments, mod);

return createProxy(
node,
{
$type: "new-expression",
$callee: stringifyExpression(node.callee as any),
$args: argumentsProxy,
},
{}
) as ProxifiedNewExpression<T>;
}
5 changes: 5 additions & 0 deletions src/proxy/proxify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ASTNode } from "../types";
import { proxifyArray } from "./array";
import { proxifyFunctionCall } from "./function-call";
import { proxifyObject } from "./object";
import { proxifyNewExpression } from "./new-expression";
import { Proxified, ProxifiedModule, ProxifiedValue } from "./types";
import { LITERALS_AST, LITERALS_TYPEOF } from "./_utils";

Expand Down Expand Up @@ -34,6 +35,10 @@ export function proxify<T>(node: ASTNode, mod?: ProxifiedModule): Proxified<T> {
proxy = proxifyFunctionCall(node, mod);
break;
}
case "NewExpression": {
proxy = proxifyNewExpression(node, mod);
break;
}
default:
throw new MagicastError(`Casting "${node.type}" is not supported`, {
ast: node,
Expand Down
8 changes: 8 additions & 0 deletions src/proxy/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ export type ProxifiedFunctionCall<Args extends any[] = unknown[]> =
$callee: string;
};

export type ProxifiedNewExpression<Args extends any[] = unknown[]> =
ProxyBase & {
$type: "new-expression";
$args: ProxifiedArray<Args>;
$callee: string;
};

export type ProxifiedObject<T extends object = object> = {
[K in keyof T]: Proxified<T[K]>;
} & ProxyBase & {
Expand Down Expand Up @@ -86,6 +93,7 @@ export interface ImportItemInput {
export type ProxifiedValue =
| ProxifiedArray
| ProxifiedFunctionCall
| ProxifiedNewExpression
| ProxifiedObject
| ProxifiedModule
| ProxifiedImportsMap
Expand Down
26 changes: 26 additions & 0 deletions test/builders.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,32 @@ describe("builders", () => {
`);
});

it("new expression", () => {
const call = builders.newExpression("Foo", 1, "bar", {
foo: "bar",
});
expect(call.$type).toBe("new-expression");
expect(call.$callee).toBe("Foo");
expect(call.$args).toMatchInlineSnapshot(`
[
1,
"bar",
{
"foo": "bar",
},
]
`);

const mod = parseModule("");
mod.exports.a = call;

expect(generate(mod)).toMatchInlineSnapshot(`
"export const a = new Foo(1, \\"bar\\", {
foo: \\"bar\\",
});"
`);
});

it("raw", () => {
const expression = builders.raw("{ foo: 1 }");
expect(expression.$type).toBe("object");
Expand Down

0 comments on commit cf5ad6d

Please sign in to comment.