import * as tm from "type-mapping"; import {Path} from "../path"; import { SetQuery, setQuery, SetMethod, setMethod, Append, append, AssertCanAppendParam, AppendParam, appendParam, AssertCanSetParam, SetParam, setParam, UnsetParam, unsetParam, SetBody, setBody, SetHeader, setHeader, SetResponse, setResponse, DeepMergeQuery, deepMergeQuery, AppendParamField, appendParamField, AssertValidParamField, } from "./operation"; import {MethodOf, getMethod} from "./query"; import { IsValid, isValid, assertValid, } from "./predicate"; /** TODO Does the "CONNECT" method make sense? */ export enum Method { GET = "GET", POST = "POST", PUT = "PUT", DELETE = "DELETE", PATCH = "PATCH", HEAD = "HEAD", OPTIONS = "OPTIONS", CONNECT = "CONNECT", /** If a route's method is "Contextual", then it is "GET" if there is no body mapper, and "POST" if there is. */ Contextual = "Contextual", } export type MethodStr = keyof (typeof Method); export interface RouteData { readonly method : MethodStr, readonly path : Path, readonly param : undefined|tm.AnySafeMapper, readonly query : undefined|tm.AnySafeMapper, readonly body : undefined|tm.AnySafeMapper, readonly header : undefined|tm.AnySafeMapper, readonly response : undefined|tm.AnySafeMapper, }; export interface DefaultRouteData { readonly method : Method.Contextual, readonly path : Path, readonly param : undefined, readonly query : undefined, readonly body : undefined, readonly header : undefined, readonly response : undefined, } export class Route { readonly method : DataT["method"]; readonly path : DataT["path"]; readonly param : DataT["param"]; readonly query : DataT["query"]; readonly body : DataT["body"]; readonly header : DataT["header"]; readonly response : DataT["response"]; setMethod (method : MethodT) : SetMethod { return setMethod(this, method); } getMethod () : MethodOf { return getMethod(this); } constructor (data : DataT) { this.method = data.method; this.path = data.path; this.param = data.param; this.query = data.query; this.body = data.body; this.header = data.header; this.response = data.response; } static Create () : Route { return new Route({ method : Method.Contextual, path : Path.Create(), param : undefined, query : undefined, body : undefined, header : undefined, response : undefined, }); } append (part : string) : Append { return append(this, part); } appendParam ( this : AssertCanAppendParam, name : NameT, regex? : RegExp ) : AppendParam; appendParam ( this : this, field : AssertValidParamField, regex? : RegExp ) : AppendParamField; appendParam ( nameOrField : string|tm.AnyField, regex? : RegExp ) { if (typeof nameOrField == "string") { return appendParam(this as AssertCanAppendParam, nameOrField, regex); } else { return appendParamField(this, nameOrField, regex); } } setParam ( f : AssertCanSetParam, ) : SetParam { return setParam(this, f as any); } unsetParam () : UnsetParam { return unsetParam(this); } /** Your query mapper should handle the following types, `string|(string[])|undefined` */ setQuery (f : F) : SetQuery { return setQuery(this, f); } setBody (f : F) : SetBody { return setBody(this, f); } /** Your header mapper should handle the following types, `string|(string[])|undefined` Your header key will probably be lowercased. */ setHeader (f : F) : SetHeader { return setHeader(this, f); } setResponse (f : F) : SetResponse { return setResponse(this, f); } deepMergeQuery (f : F) : DeepMergeQuery { return deepMergeQuery(this, f); } isValid () : IsValid { return isValid(this); } assertValid () : void { assertValid(this); } } /** Synonym for `Route.Create()` */ export function route () { return Route.Create(); }