import UrlPattern from 'url-pattern' ; export { UrlPattern } ; const patternOpts = { segmentNameCharset : 'a-zA-Z0-9_-' , segmentValueCharset : 'a-zA-Z0-9@.+-_' } ; export type HandlerPromise = Promise < Response | any | void > ; export type HandlerFunction = ( ... args : any [ ] ) => HandlerPromise ; export interface HandlerContext extends MatchResult { } export interface RouteOptions { method ? : string ; matchUrl ? : boolean ; } export interface Route { pattern : UrlPattern ; handler : HandlerFunction ; options : RouteOptions ; } export interface MatchResult { params : any | null ; handler : HandlerFunction ; url : URL ; method : string ; route : Route ; request ? : Request ; event ? : FetchEvent ; ctx : any ; } export interface HandleResult { match : MatchResult ; handlerPromise : HandlerPromise ; } export class Router { private routes : Array < Route > = [ ] ; public ctx : any ; public all ( pattern , handler , options = { } ) { return this . addRoute ( pattern , handler , { ... options , method : '' } ) ; } public get ( pattern , handler , options = { } ) { return this . addRoute ( pattern , handler , { ... options , method : 'GET' } ) ; } public post ( pattern , handler , options = { } ) { return this . addRoute ( pattern , handler , { ... options , method : 'POST' } ) ; } public put ( pattern , handler , options = { } ) { return this . addRoute ( pattern , handler , { ... options , method : 'PUT' } ) ; } public patch ( pattern , handler , options = { } ) { return this . addRoute ( pattern , handler , { ... options , method : 'PATCH' } ) ; } public delete ( pattern , handler , options = { } ) { return this . addRoute ( pattern , handler , { ... options , method : 'DELETE' } ) ; } public head ( pattern , handler , options = { } ) { return this . addRoute ( pattern , handler , { ... options , method : 'HEAD' } ) ; } public options ( pattern , handler , options = { } ) { return this . addRoute ( pattern , handler , { ... options , method : 'OPTIONS' } ) ; } private addRoute ( pattern , handler , options = { } ) { if ( ! ( pattern instanceof UrlPattern ) ) { pattern = new UrlPattern ( pattern , patternOpts ) ; } this . routes . push ( { pattern , handler , options } ) ; return this ; } public match ( url , method ) { if ( ! ( url instanceof URL ) ) { url = url . startsWith ( '/' ) ? new URL ( `http://domain${ url }` ) : new URL ( url ) ; } for ( const route of this . routes ) { const { pattern , options , handler } = route ; if ( options . method && options . method !== method ) continue ; const params = pattern . match ( options . matchUrl ? url . href : url . pathname ) ; if ( params ) return { params , handler , url , method , route , ctx : this . ctx } ; } return null ; } public matchRequest ( request ) { return this . match ( request . url , request . method ) ; } public matchEvent ( event ) { return this . matchRequest ( event . request ) ; } public handle ( url , method ) { const match = this . match ( url , method ) ; if ( ! match ) return null ; const context = { ... match } ; const handlerPromise = match . handler ( context as HandlerContext ) ; return { handlerPromise , match : context } ; } public handleRequest ( request ) { const match = this . matchRequest ( request ) ; if ( ! match ) return null ; const context = { ... match , request } as HandlerContext ; const handlerPromise = match . handler ( context ) ; return { handlerPromise , match : context } ; } public handleEvent ( event ) { const request = event . request ; const match = this . matchRequest ( request ) ; if ( ! match ) return null ; const context = { ... match , request , event } as HandlerContext ; const handlerPromise = match . handler ( context ) ; event . respondWith ( handlerPromise ) ; return { handlerPromise , match : context } ; } public clear ( ) { this . routes . length = 0 ; } }