From ca742e471e813b983e76ef3599a87a87e06ebcb5 Mon Sep 17 00:00:00 2001 From: "Kevin R. Whitley" Date: Sun, 14 Apr 2024 14:52:43 -0500 Subject: [PATCH] Add missing generics to Router stages (in options) (#241) * checking in stuff * updated type sandbox * cleaned up global request type * updated CHANGELOG * released v5.0.13 - fixed types: router and autorouter stages should use router-level generics * linting --- CHANGELOG.md | 4 +- examples/types/additional-arguments.ts | 15 +++---- examples/types/generics-router-stages.ts | 33 +++++++++++++++ examples/types/ittyrouter-generics.ts | 51 ++++++++++++++++++++++++ package.json | 2 +- rollup.config.mjs | 1 - src/AutoRouter.ts | 9 +++-- src/IttyRouter.ts | 5 +-- src/Router.ts | 4 +- src/types/AutoRouterOptions.ts | 10 +++-- src/types/AutoRouterType.ts | 6 +-- src/types/ErrorHandler.ts | 3 +- src/types/IttyRouterType.ts | 27 ++++++------- src/types/RequestHandler.ts | 6 ++- src/types/ResponseHandler.ts | 6 +-- src/types/RouteEntry.ts | 5 ++- src/types/RouterOptions.ts | 13 ++++-- src/types/RouterType.ts | 15 ++++--- 18 files changed, 157 insertions(+), 58 deletions(-) create mode 100644 examples/types/generics-router-stages.ts create mode 100644 examples/types/ittyrouter-generics.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 915c65e..820efbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ ## Changelog -- **v5.0.11** +- **v5.0.13** + - fixed: Router/AutoRouter stages were not connected to router-level generics +- **v5.0.12** - fixed: ./types was not being properly exported - **v5.0.10** - fixed: response formatters in finally stage could still cross pollute headers in Node diff --git a/examples/types/additional-arguments.ts b/examples/types/additional-arguments.ts index 6ad8933..16c72cf 100644 --- a/examples/types/additional-arguments.ts +++ b/examples/types/additional-arguments.ts @@ -1,9 +1,5 @@ -import { RequestHandler } from '../../src/types' -import { IRequestStrict } from '../../src/types' import { Router } from '../../src/Router' -import { IttyRouter } from '../../src/IttyRouter' -import { AutoRouter } from '../../src/AutoRouter' -import { IRequest } from 'itty-router' +import { IRequest, IRequestStrict, RequestHandler } from '../../src/types' // we define our environment type Environment = { age: number } @@ -27,19 +23,18 @@ router // before middleware .get('/', (request, env) => { request.user = 'kevin' // invalid (strict) - env.whatever = 123 // valid (any) - env.age = 123 // valid (any) + env.age = 123 // valid }) // route-level overrides .get('/', (request, env) => { - request.foo = 'bar' // invalid + request.foo = 'bar' // valid env.whatever = 123 // invalid env.age = 123 // valid }) // route-level overrides .get('/', (request, env) => { - request.foo = 'bar' // invalid + request.foo = 'bar' // valid env.age = 123 // invalid env.name = 'Mittens' // valid }) @@ -52,5 +47,5 @@ router }) .get('/', (request, env) => { - env.age = 'foo' // valid (any) + env.age = 'foo' // invalid }) diff --git a/examples/types/generics-router-stages.ts b/examples/types/generics-router-stages.ts new file mode 100644 index 0000000..ac663cd --- /dev/null +++ b/examples/types/generics-router-stages.ts @@ -0,0 +1,33 @@ +import { error } from 'console' +import { Router } from '../../src/Router' +import { withParams } from '../../src/withParams' +import { IRequest, IRequestStrict, RequestHandler } from '../../src/types' + +// we define our environment +type Environment = { age: number } +type Pet = { name: string } + +// and now both args combined (that Workers send to the .fetch()) +type Args = [Environment] +type AlternativeArgs = [Pet] + +const router = Router({ + before: [ + (request, env) => { + env.age = 123 // valid + env.foo // invalid + request.foo // invalid + request.body // valid + }, + withParams, + ], + catch: error, + finally: [ + (response, request, env) => { + response.whatever // valid (any) + env.age = 123 // valid + env.foo // invalid + request.foo // invalid + }, + ] +}) diff --git a/examples/types/ittyrouter-generics.ts b/examples/types/ittyrouter-generics.ts new file mode 100644 index 0000000..c26c86b --- /dev/null +++ b/examples/types/ittyrouter-generics.ts @@ -0,0 +1,51 @@ +import { IttyRouter } from '../../src/IttyRouter' +import { IRequest, IRequestStrict, RequestHandler } from '../../src/types' + +// we define our environment +type Environment = { age: number } +type Pet = { name: string } + +// and now both args combined (that Workers send to the .fetch()) +type Args = [Environment] +type AlternativeArgs = [Pet] + +// creating some middleware that needs access to CF variables +export const withUser: RequestHandler = + (request, env) => { + request.user = 'Kevin' + env.age = 123 + env.name = 'Kevin' // invalid + } + +const router = IttyRouter() + +router + // before middleware + .get('/', (request, env) => { + request.user = 'kevin' // invalid (strict) + env.age = 123 // valid + }) + + // route-level overrides + .get('/', (request, env) => { + request.foo = 'bar' // valid + env.whatever = 123 // invalid + env.age = 123 // valid + }) + // route-level overrides + .get('/', (request, env) => { + request.foo = 'bar' // valid + env.age = 123 // invalid + env.name = 'Mittens' // valid + }) + + // after middleware + .get('/', withUser, (request, env) => { + request.user = 'Kevin' + env.age = 123 // valid + env.whatever = 123 // invalid + }) + + .get('/', (request, env) => { + env.age = 'foo' // invalid + }) diff --git a/package.json b/package.json index c67aeac..fbcff87 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "itty-router", - "version": "5.0.12", + "version": "5.0.13", "description": "A tiny, zero-dependency router, designed to make beautiful APIs in any environment.", "main": "./index.js", "module": "./index.mjs", diff --git a/rollup.config.mjs b/rollup.config.mjs index 595f66f..b619079 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -16,7 +16,6 @@ const files = (await globby('./src/*.ts', { types: path.replace('/src/', '/dist/').replace('.ts', '.d.ts'), })).sort((a, b) => a.shortPath.toLowerCase() < b.shortPath.toLowerCase() ? -1 : 1) - // read original package.json const pkg = await fs.readJSON('./package.json') diff --git a/src/AutoRouter.ts b/src/AutoRouter.ts index e239920..e83eda9 100644 --- a/src/AutoRouter.ts +++ b/src/AutoRouter.ts @@ -13,17 +13,20 @@ export const AutoRouter = < missing = () => error(404), finally: f = [], before = [], - ...options }: AutoRouterOptions = {} -): AutoRouterType => Router({ + ...options }: AutoRouterOptions = {} +) => Router({ before: [ + // @ts-ignore withParams, ...before ], + // @ts-ignore catch: error, finally: [ + // @ts-ignore (r: any, ...args) => r ?? missing(r, ...args), format, ...f, ], ...options, -}) +}) as AutoRouterType diff --git a/src/IttyRouter.ts b/src/IttyRouter.ts index bbed2a3..31673fb 100644 --- a/src/IttyRouter.ts +++ b/src/IttyRouter.ts @@ -10,14 +10,13 @@ export const IttyRouter = < RequestType extends IRequest = IRequest, Args extends any[] = any[], ResponseType = any, - GlobalRequestType = RequestType, ->({ base = '', routes = [], ...other }: IttyRouterOptions = {}): IttyRouterType => +>({ base = '', routes = [], ...other }: IttyRouterOptions = {}): IttyRouterType => // @ts-ignore ({ __proto__: new Proxy({}, { // @ts-expect-error (we're adding an expected prop "path" to the get) get: (target: any, prop: string, receiver: object, path: string) => - (route: string, ...handlers: RequestHandler[]) => + (route: string, ...handlers: RequestHandler[]) => routes.push( [ prop.toUpperCase(), diff --git a/src/Router.ts b/src/Router.ts index d561804..ed2055c 100644 --- a/src/Router.ts +++ b/src/Router.ts @@ -10,7 +10,7 @@ export const Router = < RequestType = IRequest, Args extends any[] = any[], ResponseType = any ->({ base = '', routes = [], ...other }: RouterOptions = {}): RouterType => +>({ base = '', routes = [], ...other }: RouterOptions = {}): RouterType => ({ __proto__: new Proxy({}, { // @ts-expect-error (we're adding an expected prop "path" to the get) @@ -72,4 +72,4 @@ export const Router = < return response }, - } as RouterType) + } as RouterType) diff --git a/src/types/AutoRouterOptions.ts b/src/types/AutoRouterOptions.ts index 80afbf2..68386d5 100644 --- a/src/types/AutoRouterOptions.ts +++ b/src/types/AutoRouterOptions.ts @@ -2,7 +2,11 @@ import { RequestHandler } from './RequestHandler' import { ResponseHandler } from './ResponseHandler' import { RouterOptions } from './RouterOptions' -export type AutoRouterOptions = { - missing?: RequestHandler +export type AutoRouterOptions< + RequestType, + Args extends any[], + ResponseType +> = { + missing?: RequestHandler format?: ResponseHandler -} & RouterOptions +} & RouterOptions diff --git a/src/types/AutoRouterType.ts b/src/types/AutoRouterType.ts index 1921c81..ef76260 100644 --- a/src/types/AutoRouterType.ts +++ b/src/types/AutoRouterType.ts @@ -4,10 +4,10 @@ import { ResponseHandler } from './ResponseHandler' import { RouterType } from './RouterType' export type AutoRouterType< - R = IRequest, + RequestType = IRequest, Args extends any[] = any[], ResponseType = any > = { - missing?: RequestHandler + missing?: RequestHandler format?: ResponseHandler -} & RouterType +} & RouterType diff --git a/src/types/ErrorHandler.ts b/src/types/ErrorHandler.ts index 2b133db..7ec77a6 100644 --- a/src/types/ErrorHandler.ts +++ b/src/types/ErrorHandler.ts @@ -3,5 +3,6 @@ import { IRequest } from './IRequest' export type ErrorHandler< ErrorType extends Error = StatusError, - RequestType = IRequest, Args extends any[] = any[] + RequestType = IRequest, + Args extends any[] = any[] > = (error: ErrorType, request: RequestType, ...args: Args) => any diff --git a/src/types/IttyRouterType.ts b/src/types/IttyRouterType.ts index 4279e64..621adcf 100644 --- a/src/types/IttyRouterType.ts +++ b/src/types/IttyRouterType.ts @@ -6,20 +6,19 @@ import { RouteEntry } from './RouteEntry' import { CustomRoutes } from './CustomRoutes' export type IttyRouterType< - R = IRequest, - A extends any[] = any[], + RequestType = IRequest, + Args extends any[] = any[], ResponseType = any, - GlobalRequestType = R, > = { - __proto__: IttyRouterType + __proto__: IttyRouterType routes: RouteEntry[] - fetch: (request: RequestLike, ...extra: Args) => Promise - all: Route - delete: Route - get: Route - head: Route - options: Route - patch: Route - post: Route - put: Route -} & CustomRoutes> & GenericTraps + fetch: (request: RequestLike, ...extra: A) => Promise + all: Route + delete: Route + get: Route + head: Route + options: Route + patch: Route + post: Route + put: Route +} & CustomRoutes> & GenericTraps diff --git a/src/types/RequestHandler.ts b/src/types/RequestHandler.ts index 0cb8d15..489b56b 100644 --- a/src/types/RequestHandler.ts +++ b/src/types/RequestHandler.ts @@ -1,4 +1,6 @@ import { IRequest } from './IRequest' -export type RequestHandler = any[]> = - (request: R, ...args: Args) => any +export type RequestHandler< + RequestType = IRequest, + Args extends Array = any[] +> = (request: RequestType, ...args: Args) => any diff --git a/src/types/ResponseHandler.ts b/src/types/ResponseHandler.ts index ab84377..f8dea0f 100644 --- a/src/types/ResponseHandler.ts +++ b/src/types/ResponseHandler.ts @@ -1,11 +1,11 @@ import { IRequest } from './IRequest' export type ResponseHandler< - ResponseType = Response, + ResponseType = any, RequestType = IRequest, Args extends any[] = any[] > = ( - response: ResponseType & any, - request: RequestType & any, + response: ResponseType, + request: RequestType, ...args: Args ) => any diff --git a/src/types/RouteEntry.ts b/src/types/RouteEntry.ts index 0a618c4..c3bb768 100644 --- a/src/types/RouteEntry.ts +++ b/src/types/RouteEntry.ts @@ -1,8 +1,9 @@ +import { IRequest } from './IRequest' import { RequestHandler } from './RequestHandler' -export type RouteEntry = [ +export type RouteEntry = [ httpMethod: string, match: RegExp, - handlers: RequestHandler[], + handlers: RequestHandler[], path?: string, ] diff --git a/src/types/RouterOptions.ts b/src/types/RouterOptions.ts index d9965fe..981de6f 100644 --- a/src/types/RouterOptions.ts +++ b/src/types/RouterOptions.ts @@ -1,10 +1,15 @@ +import { StatusError } from 'StatusError' import { ErrorHandler } from './ErrorHandler' +import { IRequest } from './IRequest' import { IttyRouterOptions } from './IttyRouterOptions' import { RequestHandler } from './RequestHandler' import { ResponseHandler } from './ResponseHandler' -export type RouterOptions = { - before?: RequestHandler[] - catch?: ErrorHandler - finally?: ResponseHandler[] +export type RouterOptions< + RequestType = IRequest, + Args extends any[] = [], +> = { + before?: RequestHandler[] + catch?: ErrorHandler + finally?: ResponseHandler[] } & IttyRouterOptions diff --git a/src/types/RouterType.ts b/src/types/RouterType.ts index b34c9a7..46f8471 100644 --- a/src/types/RouterType.ts +++ b/src/types/RouterType.ts @@ -1,11 +1,16 @@ +import { StatusError } from 'StatusError' import { ErrorHandler } from './ErrorHandler' import { IRequest } from './IRequest' import { IttyRouterType } from './IttyRouterType' import { RequestHandler } from './RequestHandler' import { ResponseHandler } from './ResponseHandler' -export type RouterType = { - before?: RequestHandler[] - catch?: ErrorHandler - finally?: ResponseHandler[] -} & IttyRouterType +export type RouterType< + RequestType = IRequest, + Args extends any[] = any[], + ResponseType = any +> = { + before?: RequestHandler[] + catch?: ErrorHandler + finally?: ResponseHandler[] +} & IttyRouterType