type Partial = { [P in keyof T]?: T[P]; }; type AppConfig = { compiledUserContentDir: string; missingRefValueReplacement: string, mdBlogPostsDir: string; packageName: string; previewLength: number; staticFilesDir: string; pagesDir: string; viewTemplatesDir: string; userCustomConfigPath: string; userProjectRootDir: string; }; type AppConfigFactoryParams = AppConfig & { userCustomConfig: Partial; }; type RequireOnlyOne = Pick> & { [K in Keys]-?: Required> & Partial, undefined>> }[Keys] // Internal Placeholders type ActionParamsDefaultRetType = {}; type RouteConfigDefaultAdditionalPropsType = {}; type RouteUserConfigDefaultAdditionalPropsType = {}; type RouteCtorConfigDefaultAdditionalPropsType = {}; type GetControllerActionParamsMethod = (props: { request: HttpRequest; }) => T; type RouteInterface = U & CanResolveRouteInterface & { controller: RouteControllerCtorConfig; getControllerActionParams?: GetControllerActionParamsMethod }; // We need two things: // 1. A config generated by user passed to DI to create the route // > ...UserConfig // 2. A config used by Di to pass to the route constructor // > ...CtorConfig // We need two more things: // a. Path // b. RegExp type DiNamedConfig = { name: string; }; type AsInstanceConfig = { instance: I; }; type RouteControllerTypeBothConfig = DiNamedConfig | AsInstanceConfig; type ActionParamsObjectType = { actionParams?: A; actionParamsGetter?: (props: { request: HttpRequest; }) => A; } type RouteControllerWithActionParamsConfig = RequireOnlyOne, 'actionParams' | 'actionParamsGetter'> type RouteControllerGenericConfig = T & RouteControllerWithActionParamsConfig; type RouteControllerUserConfig = RouteControllerGenericConfig; type RouteControllerCtorConfig = RouteControllerGenericConfig, A>; // 1. ...UserConfig type RouteUserConfig = AsInstanceConfig> | (E & DiNamedConfig & { controller: RouteControllerUserConfig; }); // 2. ...CtorConfig type RouteCtorConfig = E & { controller: RouteControllerCtorConfig; }; // Our 4 things // F : Further props passed to route First level config // A : ActionParams object type RouteMatchPathUserConfig = RouteUserConfig; type RouteMatchRegExpUserConfig = RouteUserConfig; type RouteMatchPathCtorConfig = RouteCtorConfig; type RouteMatchRegExpCtorConfig = RouteCtorConfig; type ValidPostSlugListGetterConf = { validPostSlugListGetter: () => string[]; } type StaticFilePathListGetterConf = { staticFilePathListGetter: () => string[]; } interface HttpRequest { url: string; method: 'GET' | 'POST'; } interface IsValidRequestInterface { isValid: (request: HttpRequest) => boolean; } interface MatchesRequestRegExpInterface { matches: (request: HttpRequest, pathRegExp: RegExp) => boolean; } interface MatchesRequestPathInterface { matches: (request: HttpRequest, path: string) => boolean; } interface CanResolveRouteInterface { canResolve: (request: HttpRequest) => boolean; } type RegExpRouteSpecConfig = RouteMatchRegExpConfig & MaybeDiControllerConfig; type RegExpRouteConstructorConfig = RouteMatchRegExpConfig & RouteConstructorControllerConfig; interface RegExpRouteValidatorConstructorInterface { new (config: RegExpRouteConstructorConfig): RouteInterface; } type PathRouteSpecConfig = RouteMatchPathConfig & MaybeDiControllerConfig; type PathRouteConstructorConfig = RouteMatchPathConfig & RouteConstructorControllerConfig; interface PathRouteValidatorConstructorInterface { new (config: PathRouteConstructorConfig): RouteInterface; } interface ResponseInterface { code: number; headers: { [k: string]: string; }; body: string; } interface ControllerConstructor { new (config: any): ControllerInterface; } interface ControllerInterface { action: (params: A) => Promise; }