From 66f2fc62917a5b6f52ded1ac372e17aeab40e1da Mon Sep 17 00:00:00 2001 From: Zach Barham Date: Sun, 17 Jul 2022 13:22:14 +1000 Subject: [PATCH] Merge body and query into an options object --- project/src/index.ts | 1 - project/src/internal-types.ts | 11 ---------- project/src/plugin.ts | 7 +++++- project/src/real-types.ts | 19 +++++++++++++++++ project/tsup.config.ts | 2 +- test/pages/api/users/[id]/index.ts | 4 +++- test/pages/unsafeUser.tsx | 14 ++++++++++-- test/types/nappi.d.ts | 34 ++++++++++++------------------ 8 files changed, 55 insertions(+), 37 deletions(-) delete mode 100644 project/src/internal-types.ts diff --git a/project/src/index.ts b/project/src/index.ts index 188645d..d6c55a9 100644 --- a/project/src/index.ts +++ b/project/src/index.ts @@ -1,4 +1,3 @@ export type {InferResponse} from "./inferResponse"; export type {ApiResponse} from "./ApiResponse"; -export type ApiMap = Record; export * from "./real-types"; diff --git a/project/src/internal-types.ts b/project/src/internal-types.ts deleted file mode 100644 index 7cb773e..0000000 --- a/project/src/internal-types.ts +++ /dev/null @@ -1,11 +0,0 @@ -type Cast = Type extends To ? Type : To; -type Split = T extends `${infer First}&${infer Rest}` ? [First, ...Split] : [T]; -type TrimEquals = T extends [infer First, ...infer Rest] - ? First extends `${infer Name}=${string}` - ? [Name, ...TrimEquals>] : [First, ...TrimEquals>] - : []; -type ArrayToUnion = T extends [infer First, ...infer Rest] - ? First | ArrayToUnion - : T extends [infer First] ? First : never; - -export type QueryParamToKeys = ArrayToUnion>>; diff --git a/project/src/plugin.ts b/project/src/plugin.ts index b28808c..910ac38 100644 --- a/project/src/plugin.ts +++ b/project/src/plugin.ts @@ -76,6 +76,11 @@ function inferQueryParams(path: string) { : never`; } +function inferBody(path: string) { + const id = safifyIdentifier(path); + return `typeof ${id} extends SafeNappiApiHandler ? Body : unknown` +} + export function nappiPlugin(baseConfig: NextConfig, config: NappiPluginConfig = {}): NextConfig { const {baseDir = getBaseDir(), tsOut = "types/nappi.d.ts"} = config; @@ -94,7 +99,7 @@ export function nappiPlugin(baseConfig: NextConfig, config: NappiPluginConfig = `declare module "${name}" {`, `export * from "${name}/dist/real-types";`, ...files.flatMap(path => getApiPaths(path).map(apiPath => - `export function jsonFetch(path: \`${apiPath}\`, query?: (${inferQueryParams(path)}) extends never ? undefined : {[Key in ${inferQueryParams(path)}]?: string}): Promise<${getResponseType(path)}>;` + `export function jsonFetch(path: \`${apiPath}\`, options?: JsonFetchOptions<${inferQueryParams(path)}, ${inferBody(path)}>): Promise<${getResponseType(path)}>;` )), "export type ApiResponse getApiPaths(path).map(apiPath => `\`${apiPath}\``)).join(" | "), diff --git a/project/src/real-types.ts b/project/src/real-types.ts index 6644dbc..cf1b8ea 100644 --- a/project/src/real-types.ts +++ b/project/src/real-types.ts @@ -9,3 +9,22 @@ interface NextApiRequestWithData extends NextApiRequ export type SafeNappiApiHandler = (req: NextApiRequestWithData, res: NextApiResponse) => unknown | Promise; + +export type JsonFetchOptions = unknown extends Body ? { + body?: Body; + query?: { + [Key in Query]?: string; + }; + init?: RequestInit; +} : Body extends never ? { + query?: { + [Key in Query]?: string; + }; + init?: RequestInit; +} : { + body: Body; + query?: { + [Key in Query]?: string; + }; + init?: RequestInit; +}; diff --git a/project/tsup.config.ts b/project/tsup.config.ts index 8286ac7..9afb1a4 100644 --- a/project/tsup.config.ts +++ b/project/tsup.config.ts @@ -4,6 +4,6 @@ export const tsup: Options = { sourcemap: true, dts: true, clean: true, - entryPoints: ["src/index.ts", "src/real-types.ts", "src/internal-types.ts", "src/plugin.ts"], + entryPoints: ["src/index.ts", "src/real-types.ts", "src/plugin.ts"], format: ["cjs"], }; diff --git a/test/pages/api/users/[id]/index.ts b/test/pages/api/users/[id]/index.ts index 316ce8e..f37dd93 100644 --- a/test/pages/api/users/[id]/index.ts +++ b/test/pages/api/users/[id]/index.ts @@ -2,10 +2,12 @@ import { User } from "lib/types/backend"; import { StandardResponse } from "lib/types/shared"; import {SafeNappiApiHandler} from "safe-nappi"; -const handler: SafeNappiApiHandler, "id"> = ( +const handler: SafeNappiApiHandler, "id", {foo: "bar"}> = ( req, res ) => { + console.log(req.body); + const id = req.query.id; if (typeof id !== "string") return res.status(400).json({ diff --git a/test/pages/unsafeUser.tsx b/test/pages/unsafeUser.tsx index 62f73ce..fbe9560 100644 --- a/test/pages/unsafeUser.tsx +++ b/test/pages/unsafeUser.tsx @@ -1,8 +1,18 @@ import React, { useEffect, useState } from "react"; -import { jsonFetch } from "safe-nappi"; +import {jsonFetch} from "safe-nappi"; async function doLeFetchificationOfLaDaeeeeeta() { - const data = await jsonFetch("/api/users/fafe?ip=foo&foo=baz"); + const data = await jsonFetch("/api/users/fafe", { + body: { + foo: "bar" + }, + query: { + id: "" + }, + init: { + + } + }); } diff --git a/test/types/nappi.d.ts b/test/types/nappi.d.ts index bf8957a..7a3fac7 100644 --- a/test/types/nappi.d.ts +++ b/test/types/nappi.d.ts @@ -1,53 +1,47 @@ import { NextApiHandler } from "next"; import type {default as unsafeUser} from "../pages/api/unsafeUser"; -import type {default as users_id_index} from "../pages/api/users/[id]/index"; import type {default as users_index} from "../pages/api/users/index"; +import type {default as users_id_index} from "../pages/api/users/[id]/index"; import {SafeNappiApiHandler} from "safe-nappi/dist/real-types"; declare module "safe-nappi" { export * from "safe-nappi/dist/real-types"; -export function jsonFetch(path: `/api/unsafeUser`, query?: (typeof unsafeUser extends SafeNappiApiHandler - ? QueryParams - : never) extends never ? undefined : {[Key in typeof unsafeUser extends SafeNappiApiHandler +export function jsonFetch(path: `/api/unsafeUser`, options?: JsonFetchOptions ? QueryParams - : never]?: string}): Promise + : never, typeof unsafeUser extends SafeNappiApiHandler ? Body : unknown>): Promise ? NextResponse : typeof unsafeUser extends SafeNappiApiHandler ? SnResponse : never>; -export function jsonFetch(path: `/api/users/${string}`, query?: (typeof users_id_index extends SafeNappiApiHandler +export function jsonFetch(path: `/api/users`, options?: JsonFetchOptions ? QueryParams - : never) extends never ? undefined : {[Key in typeof users_id_index extends SafeNappiApiHandler - ? QueryParams - : never]?: string}): Promise + : never, typeof users_index extends SafeNappiApiHandler ? Body : unknown>): Promise ? NextResponse - : typeof users_id_index extends SafeNappiApiHandler + : typeof users_index extends SafeNappiApiHandler ? SnResponse : never>; -export function jsonFetch(path: `/api/users`, query?: (typeof users_index extends SafeNappiApiHandler - ? QueryParams - : never) extends never ? undefined : {[Key in typeof users_index extends SafeNappiApiHandler +export function jsonFetch(path: `/api/users/${string}`, options?: JsonFetchOptions ? QueryParams - : never]?: string}): Promise + : never, typeof users_id_index extends SafeNappiApiHandler ? Body : unknown>): Promise ? NextResponse - : typeof users_index extends SafeNappiApiHandler + : typeof users_id_index extends SafeNappiApiHandler ? SnResponse : never>; export type ApiResponse = Path extends `/api/unsafeUser` ? typeof unsafeUser extends NextApiHandler ? NextResponse : typeof unsafeUser extends SafeNappiApiHandler ? SnResponse : never : -Path extends `/api/users/${string}` ? typeof users_id_index extends NextApiHandler +Path extends `/api/users` ? typeof users_index extends NextApiHandler ? NextResponse - : typeof users_id_index extends SafeNappiApiHandler + : typeof users_index extends SafeNappiApiHandler ? SnResponse : never : -Path extends `/api/users` ? typeof users_index extends NextApiHandler +Path extends `/api/users/${string}` ? typeof users_id_index extends NextApiHandler ? NextResponse - : typeof users_index extends SafeNappiApiHandler + : typeof users_id_index extends SafeNappiApiHandler ? SnResponse : never : never;