diff --git a/src/builders.ts b/src/builders.ts index 8bc124b..0b1bbb0 100644 --- a/src/builders.ts +++ b/src/builders.ts @@ -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"; @@ -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. */ diff --git a/src/proxy/new-expression.ts b/src/proxy/new-expression.ts new file mode 100644 index 0000000..97908b5 --- /dev/null +++ b/src/proxy/new-expression.ts @@ -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( + node: ASTNode, + mod?: ProxifiedModule +): ProxifiedNewExpression { + 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(node, node.arguments, mod); + + return createProxy( + node, + { + $type: "new-expression", + $callee: stringifyExpression(node.callee as any), + $args: argumentsProxy, + }, + {} + ) as ProxifiedNewExpression; +} diff --git a/src/proxy/proxify.ts b/src/proxy/proxify.ts index bb8a57f..88a3fc7 100644 --- a/src/proxy/proxify.ts +++ b/src/proxy/proxify.ts @@ -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"; @@ -34,6 +35,10 @@ export function proxify(node: ASTNode, mod?: ProxifiedModule): Proxified { proxy = proxifyFunctionCall(node, mod); break; } + case "NewExpression": { + proxy = proxifyNewExpression(node, mod); + break; + } default: throw new MagicastError(`Casting "${node.type}" is not supported`, { ast: node, diff --git a/src/proxy/types.ts b/src/proxy/types.ts index 9317828..ae4ec99 100644 --- a/src/proxy/types.ts +++ b/src/proxy/types.ts @@ -23,6 +23,13 @@ export type ProxifiedFunctionCall = $callee: string; }; +export type ProxifiedNewExpression = + ProxyBase & { + $type: "new-expression"; + $args: ProxifiedArray; + $callee: string; + }; + export type ProxifiedObject = { [K in keyof T]: Proxified; } & ProxyBase & { @@ -86,6 +93,7 @@ export interface ImportItemInput { export type ProxifiedValue = | ProxifiedArray | ProxifiedFunctionCall + | ProxifiedNewExpression | ProxifiedObject | ProxifiedModule | ProxifiedImportsMap diff --git a/test/builders.test.ts b/test/builders.test.ts index 29932fc..850fbf8 100644 --- a/test/builders.test.ts +++ b/test/builders.test.ts @@ -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");