UNPKG

typizator

Version:

Runtime types and metadata schemas for Typescript

182 lines (181 loc) 5.06 kB
import { Schema } from "./schemas"; import { InferTargetFromSchema } from "./type-conversions"; /** * Defines the run-time function call schema. To be used by facades, serializers, etc... */ export type FunctionCallDefinition = { /** * List of arguments types schemas */ args: [Schema?, ...Schema[]]; /** * Return value type schema */ retVal?: Schema; /** * If true, it tells the integration to exclude this function from the API interface */ hidden?: boolean; }; /** * Information */ export type NamedMetadata = { /** * Name of the function or of the child API */ name: string; /** * Full path from the root of the API, separated by slashes */ path: string; }; /** * Metadata for an API member function */ export type FunctionMetadata = { /** * Allows to make the difference between functions and sub-apis */ dataType: "function"; /** * List of arguments types schemas */ args: Schema[]; /** * Return value type schema */ retVal: Schema; /** * If true, it tells the integration to exclude this function from the API interface */ hidden?: boolean; } & NamedMetadata; /** * List of function definitions and sub-apis * * The field name can be any valid typescript identifier except **name**, **path** and **metadata** */ export type ApiDefinition = { [K: string]: FunctionCallDefinition | ApiDefinition; } & { hidden?: boolean; } & { metadata?: never; }; /** * Reproduces the API tree but with additional information like names and paths */ export type MetadataMembersImplementation<T extends ApiDefinition> = { [K in keyof T]: T[K] extends ApiDefinition ? MetadataMembersImplementation<T[K]> & { metadata: ApiMetadata<T[K]>; } : T[K] & { metadata: FunctionMetadata; }; }; /** * Metadata for the API endpoint */ export type ApiMetadata<T extends ApiDefinition> = { /** * Allows to make the difference between functions and sub-apis */ dataType: "api"; /** * Objects metadata tree reproducing the API structure */ implementation: MetadataMembersImplementation<T>; /** * If true, it tells the integration to exclude this API from the API interface */ hidden?: boolean; } & NamedMetadata; /** * Run-time metadata giving the run-time access to the API structure and data types */ export interface ApiSchema<T extends ApiDefinition, _ extends { hidden?: boolean; }> { get metadata(): ApiMetadata<T>; } /** * Creates a new API schema * @param definition Object containing function definitions matching `FunctionCallDefinition` and sub-apis allowing to build a tree API structure * @param props Optional properties to apply to the API. `hidden` as true will hide the API from the API interface * @returns API schema available at fun time */ export declare const apiS: <T extends ApiDefinition, P extends { hidden?: boolean | undefined; }>(definition: T, props?: P) => ApiSchema<T, P>; /** * Extracts argument types from a list of schemas. * * @example * This: * ```ts * [intS, stringS] * ``` * ...becomes this: * ```ts * [number,string] * ``` */ export type InferArguments<T extends [...any]> = T extends [...infer P] ? { [K in keyof P]: P[K] extends Schema ? InferTargetFromSchema<P[K]> : never; } : never; /** * Extracts the type from the API schema * * @example * This: * ```ts * apiS({ * helloWorld: { args: [stringS, intS], retVal: bigintS } * cruel: { * world: { args:[] } * } * }) * ``` * ...becomes this: * ```ts * { * helloWorld: (arg0:string, arg1:number) => Promise<bigint> * cruel: { * world: () => Promise<void> * } * } * ``` */ export type ApiImplementation<T> = T extends ApiSchema<infer S, any> ? ApiImplementation<S> : { [K in keyof T]: T[K] extends ApiDefinition ? ApiImplementation<T[K]> : T[K] extends FunctionCallDefinition ? (...args: InferArguments<T[K]["args"]>) => Promise<InferTargetFromSchema<T[K]["retVal"]>> : never; }; /** * Extracts the type from the API schema taking into account the visibility (`hidden` property) of the API and its functions * * @example * This: * ```ts * apiS({ * helloWorld: { args: [stringS, intS], retVal: bigintS } * cruel: { * world: { args:[] } * } * }) * ``` * ...becomes this: * ```ts * { * helloWorld: (arg0:string, arg1:number) => Promise<bigint> * cruel: { * world: () => Promise<void> * } * } * ``` */ export type ApiImplementationWithVisibility<T> = T extends ApiSchema<infer S, infer P> ? P extends { hidden: true; } ? never : ApiImplementationWithVisibility<S> : { [K in keyof T as T[K] extends { hidden: true; } ? never : K]: T[K] extends ApiDefinition ? ApiImplementationWithVisibility<T[K]> : T[K] extends FunctionCallDefinition ? (...args: InferArguments<T[K]["args"]>) => Promise<InferTargetFromSchema<T[K]["retVal"]>> : never; };