/* eslint-disable @typescript-eslint/no-unused-vars */ import { assert, Equals } from "../test/type_testing.js"; import { describe, test } from "vitest"; import { makeFunctionReference, PaginationOptions, PaginationResult, QueryBuilder, } from "./index.js"; import { FunctionReference, justActions, justInternal, justMutations, justQueries, justPaginatedQueries, PartialApi, ConvertReturnType, } from "./api.js"; test("PartialApi", () => { const api = { foo: { a: makeFunctionReference<"query", { a: string }>("a"), b: makeFunctionReference<"query">("b"), }, bar: { c: makeFunctionReference<"query">("c"), baz: { d: makeFunctionReference<"query">("d"), e: makeFunctionReference<"query">("e"), }, }, } as const; type API = typeof api; const subset = { foo: { b: makeFunctionReference<"query">("b"), }, bar: { baz: { e: makeFunctionReference<"query">("e"), }, }, } as const; type SubsetAPI = typeof subset; assert ? true : false>; const notASubset = { foo: { c: makeFunctionReference<"query">("c"), }, } as const; assert ? false : true>; const wrongSignature = { foo: { a: makeFunctionReference<"query", { a: number }>("a"), }, } as const; assert ? false : true>; const correctSignature = { foo: { a: makeFunctionReference<"query", { a: string }>("a"), }, } as const; assert ? true : false>; }); import { actionGeneric, mutationGeneric, queryGeneric, internalQueryGeneric, internalActionGeneric, internalMutationGeneric, } from "../server/index.js"; import { ApiFromModules, ArgsAndOptions, OptionalRestArgs } from "./index.js"; import { DefaultFunctionArgs, EmptyObject } from "./registration.js"; describe("JustPaginatedQueries", () => { test("selects correct queries", () => { const query = queryGeneric as QueryBuilder; const modules = { filename: { simplePaginated: query( ( _ctx, _args: { paginationOpts: PaginationOptions; }, ) => null as unknown as PaginationResult, ), paginatedWithArg: query( ( _ctx, _args: { property: string; paginationOpts: PaginationOptions; }, ) => null as unknown as PaginationResult, ), missingArg: query( (_ctx) => null as unknown as PaginationResult, ), emptyArg: query(() => null as unknown as PaginationResult), wrongReturn: query( (_ctx, _args: { paginationOpts: PaginationOptions }) => null as unknown as string, ), }, } as const; type API = ApiFromModules; type Expected = { filename: { simplePaginated: FunctionReference< "query", "public", { paginationOpts: PaginationOptions }, PaginationResult >; paginatedWithArg: FunctionReference< "query", "public", { paginationOpts: PaginationOptions; property: string }, PaginationResult >; }; }; const paginatedApi = justPaginatedQueries(null as unknown as API); type Actual = typeof paginatedApi; assert< Equals< Actual["filename"]["paginatedWithArg"], Expected["filename"]["paginatedWithArg"] > >(); }); }); describe("justType filters", () => { test("finds queries, mutations and actions", () => { const myModule = { query: queryGeneric((_, _args: { arg: number }) => "query result"), mutation: mutationGeneric((_) => "query result"), importantQuestion: actionGeneric((_, _args: { arg: number }) => 42), }; type API = ApiFromModules<{ myModule: typeof myModule; }>; type ExpectedAPI = { myModule: { query: FunctionReference< "query", "public", { arg: number; }, string >; mutation: FunctionReference< "mutation", "public", Record, string >; importantQuestion: FunctionReference< "action", "public", { arg: number }, number >; }; }; assert>; type jq = ReturnType>; type jm = ReturnType>; type ja = ReturnType>; assert< Equals< jq, { myModule: { query: FunctionReference< "query", "public", { arg: number; }, string >; }; } > >; assert< Equals< jm, { myModule: { mutation: FunctionReference< "mutation", "public", EmptyObject, string >; }; } > >; assert< Equals< ja, { myModule: { importantQuestion: FunctionReference< "action", "public", { arg: number; }, number >; }; } > >; }); test("ignores exports that aren't functions and modules that don't have them", () => { const myModule = { number: 123, function: () => "return value", object: { property: "value" }, }; type API = ApiFromModules<{ myModule: typeof myModule; }>; // None of these exports are queries or mutations or actions. type ExpectedAPI = {}; assert>; }); test("applies return type conversions", () => { const myModule = { returnsPromise: queryGeneric(() => Promise.resolve("query result")), returnsUndefined: queryGeneric(() => undefined), returnsVoid: queryGeneric(() => { // Intentionally empty }), returnsVoidPromise: queryGeneric(() => Promise.resolve()), }; type API = ApiFromModules<{ myModule: typeof myModule; }>; type ExpectedAPI = { myModule: { returnsPromise: FunctionReference< "query", "public", EmptyObject, string >; returnsUndefined: FunctionReference< "query", "public", EmptyObject, null >; returnsVoid: FunctionReference<"query", "public", EmptyObject, null>; returnsVoidPromise: FunctionReference< "query", "public", EmptyObject, null >; }; }; assert>; }); test("separates internal functions", () => { const myModule = { query: queryGeneric((_, _args: { arg: number }) => "query result"), internalQuery: internalQueryGeneric( (_, _args: { arg: number }) => "query result", ), mutation: mutationGeneric((_) => "query result"), internalMutation: internalMutationGeneric((_) => "query result"), }; const myActionsModule = { action: actionGeneric((_, _args: { arg: number }) => 42), internalAction: internalActionGeneric((_, _args: { arg: number }) => 42), }; type API = ApiFromModules<{ myModule: typeof myModule; "actions/myActionsModule": typeof myActionsModule; }>; type InternalAPI = ReturnType>; type ExpectedAPI = { myModule: { internalQuery: FunctionReference< "query", "internal", { arg: number; }, string >; internalMutation: FunctionReference< "mutation", "internal", EmptyObject, string >; }; actions: { myActionsModule: { internalAction: FunctionReference< "action", "internal", { arg: number; }, number >; }; }; }; assert>; }); test("correctly infers arguments", () => { const myModule = { noArg: queryGeneric((_) => "query result"), oneTypedArg: queryGeneric((_, _args: { arg: number }) => "query result"), onUnTypedArg: queryGeneric((_, _args) => "query result"), }; type API = ApiFromModules<{ myModule: typeof myModule; }>; type ExpectedAPI = { myModule: { noArg: FunctionReference<"query", "public", EmptyObject, string>; oneTypedArg: FunctionReference< "query", "public", { arg: number; }, string >; onUnTypedArg: FunctionReference< "query", "public", DefaultFunctionArgs, string >; }; }; assert>; }); }); describe("Args", () => { const module = { noArgs: mutationGeneric((_ctx) => { /* nop */ }), args: mutationGeneric((_ctx, _args: { property: string }) => { /* nop */ }), }; type API = ApiFromModules<{ module: typeof module; }>; describe("ArgsObject", () => { test("infers Record for functions with no args", () => { type MyFunction = API["module"]["noArgs"]; assert>(); }); test("infers args for functions with args", () => { type MyFunction = API["module"]["args"]; type ExpectedArgs = { property: string }; assert>(); }); }); describe("OptionalRestArgs", () => { test("infers rest type with optional args for functions with no args", () => { type MyFunction = API["module"]["noArgs"]; type ExpectedArgs = [Record?]; type Args = OptionalRestArgs; assert>(); }); test("infers rest type with required args for functions with args", () => { type MyFunction = API["module"]["args"]; type ExpectedArgs = [{ property: string }]; type Args = OptionalRestArgs; assert>(); }); }); describe("ArgsAndOptions", () => { type Options = { option1?: string; option2: number; }; test("infers rest type with optional args and optional options for functions with no args", () => { type MyFunction = API["module"]["noArgs"]; type ExpectedArgs = [Record?, Options?]; type Args = ArgsAndOptions; assert>(); }); test("infers rest type with required args and optional options for functions with args", () => { type MyFunction = API["module"]["args"]; type ExpectedArgs = [{ property: string }, Options?]; type Args = ArgsAndOptions; assert>(); }); }); }); test("ConvertReturnType", () => { assert, null>>; assert, null | string>>; assert>, null>>; assert>, null | string>>; assert>, string>>; });