/** * This file has helper types that map from the specfication type to handler function types. */ import { ResponsesSpec, ContentsSpec, RootSpec, PathsSpec, OperationsSpec, OperationSpec, RequestBodySpec, } from "./spec-types"; /** * From the root of the spec, create a type for an object with handler functions */ export type HandlerFnsFromRootSpec = HandlerFnsFromPathsSpec; /** * From the paths of the spec, create a type for an object with handler functions for each path and operation */ export type HandlerFnsFromPathsSpec = { readonly [K in keyof T]: HandlerFnsFromOperationsSpec; }; /** * From the operations spec, create function types */ export type HandlerFnsFromOperationsSpec = { readonly [K in keyof T]: HandlerFnFromOperationSpec; }; /** * Create a handler function from the operation spec. */ export type HandlerFnFromOperationSpec = HandlerFn< Context, T["parameters"], T["requestBody"] extends RequestBodySpec ? HandlerContentFromSpec : {}, HandlerResponseFromSpec >; /** * From the specification, create a union type of possible response types */ export type HandlerResponseFromSpec = { readonly [K in keyof T]: { readonly httpCode: K } & (T[K]["content"] extends {} ? HandlerContentFromSpec : {}); }[keyof T]; /** * From the specification, create a union type of possible content types */ export type HandlerContentFromSpec = { readonly [K in keyof T]: { readonly contentType: K; readonly content: T[K] }; }[keyof T]; /** * A general description of a handler function */ export type HandlerFn< Context, Parameters extends HandlerParameters, RequestBody extends ContentWithType, Response extends HandlerResponse > = (ctx: Context, parameters: Parameters, requestBody: RequestBody) => Promise; /** * A general description of a handler function response */ export type HandlerResponse = { readonly httpCode: HttpCode; } & ContentWithType; export type ContentWithType = { // In the generated types, either both contentType and content is required, or both are never. // We should not end up with having only one of them specified. readonly contentType?: ContentType; readonly content?: Content; }; export type ParamSet = { readonly [key: string]: unknown }; export type HandlerParameters< PathParams extends ParamSet, QueryParams extends ParamSet, HeaderParams extends ParamSet, CookieParams extends ParamSet > = { readonly path: PathParams; readonly query: QueryParams; readonly header: HeaderParams; readonly cookie: CookieParams; }; /** * A general description of a handler object with functions for each path/operation */ export type HandlerFns = { readonly [path: string]: { readonly [op: string]: HandlerFn< unknown, HandlerParameters, ContentWithType, HandlerResponse >; }; }; // // --- TESTING // export type Olle = HandlerResponseFromSpec; // export type OlleExpanded = ExpandRecursively; // export type Olle2 = HandlerResponseFromSpec; // export type Olle2Expanded = ExpandRecursively; // // https://stackoverflow.com/questions/57683303/how-can-i-see-the-full-expanded-contract-of-a-typescript-type // // https://stackoverflow.com/questions/53113031/how-to-see-a-fully-expanded-typescript-type-without-n-more-and/53131824#53131824 // type Expand = T extends infer O ? { [K in keyof O]: O[K] } : never; // type ExpandRecursively = T extends object // ? T extends infer O // ? { [K in keyof O]: ExpandRecursively } // : never // : T; // export type Nisse1 = HandlerFnsFromPathsSpec; // export type Nisse1Expanded = Expand; // export type Nisse2 = HandlerFnFromOperationSpec; // export type Nisse2Expanded = ExpandRecursively; // export type Nisse3 = HandlerFnFromOperationSpec; // export type Nisse4 = HandlerFnsFromRootSpec; // --- OLD STUFF // /** // * Can these be used both to handle requests on the server, and make request on the client??? // */ // // export type PathOperationFns3 = { // // readonly "/units": { // // readonly get: ( // // ctx: Context, // // parameters: Spec["paths"]["/units"]["get"]["parameters"] // // ) => Promise>; // // readonly post: ( // // ctx: Context, // // parameters: Spec["paths"]["/units"]["post"]["parameters"], // // requestBody: Spec["paths"]["/units"]["post"]["requestBody"] // // ) => Promise>; // // }; // // readonly "/units/{unitId}": { // // readonly get: ( // // ctx: Context, // // parameters: Spec["paths"]["/units/{unitId}"]["get"]["parameters"] // // ) => Promise>; // // }; // // }; // export type HandlerFns = HandlerFnsFromRootSpec;