import { FabRequestResponder , PluginMetadata , FabResponderArgs , FabFileMetadata , FabMetadata , FabRequestResponderWithParams , MatchParams , FabCache , FABServerContext , PluginArgs , ResponseInterceptor , } from '@fab/core' ; import { Key , pathToRegexp } from 'path-to-regexp' ; export enum Priority { LAST , LATER , MIDDLE , EARLY , FIRST } export type FabPluginRuntime = ( Runtime : FABRuntime , args : PluginArgs ) => void ; export type RuntimeImports = Array < { plugin : FabPluginRuntime ; args : PluginArgs ; } > ; export class FABRouter { private pipeline : { [ order in Priority ] : FabRequestResponder [ ] ; } ; constructor ( ) { this . pipeline = { [ Priority . LAST ] : [ ] , [ Priority . LATER ] : [ ] , [ Priority . MIDDLE ] : [ ] , [ Priority . EARLY ] : [ ] , [ Priority . FIRST ] : [ ] , } ; } getPipeline ( ) { return [ ... this . pipeline [ Priority . FIRST ] , ... this . pipeline [ Priority . EARLY ] , ... this . pipeline [ Priority . MIDDLE ] , ... this . pipeline [ Priority . LATER ] , ... this . pipeline [ Priority . LAST ] , ] ; } addToPipeline ( responder , priority = Priority . MIDDLE ) { this . pipeline [ priority ] . push ( responder ) ; } on ( route , responder , priority ? ) { if ( route === '*' ) { this . onAll ( ( context ) => responder ( { ... context , params : { } } ) , priority ) ; } else { const groups = [ ] ; const regexp = pathToRegexp ( route , groups ) ; this . addToPipeline ( async ( context ) => { const { pathname } = context . url ; const match = regexp . exec ( pathname ) ; if ( match ) { const params = { } ; groups . forEach ( ( group , i ) => { params [ group . name ] = match [ i + 1 ] ; } ) ; return await responder ( { ... context , params } ) ; } return undefined ; } , priority ) ; } } onAll ( responder , priority ? ) { this . addToPipeline ( responder , priority ) ; } interceptResponse ( interceptor , priority = Priority . EARLY ) { this . addToPipeline ( async ( context ) => { return { interceptResponse : interceptor , } ; } , priority ) ; } } class NoopCache implements FabCache { set = async ( ) => { } ; setJSON = async ( ) => { } ; get = async ( ) => undefined ; getJSON = async ( ) => undefined ; getArrayBuffer = async ( ) => undefined ; getNumber = async ( ) => undefined ; getStream = async ( ) => undefined ; } export class FABRuntime < T extends PluginMetadata = PluginMetadata > { Metadata : T ; FileMetadata : FabFileMetadata ; Router : FABRouter ; Cache : FabCache ; ServerContext : FABServerContext ; constructor ( metadata , file_metadata , context ) { this . Metadata = metadata ; this . FileMetadata = file_metadata ; this . Router = new FABRouter ( ) ; this . Cache = context . cache || new NoopCache ( ) ; this . ServerContext = context ; } static initialize ( metadata , plugins , context ) { const instance = new FABRuntime ( metadata . plugin_metadata , metadata . file_metadata , context ) ; plugins . forEach ( ( { plugin , args } ) => plugin ( instance , args ) ) ; return instance ; } getPipeline ( ) { return this . Router . getPipeline ( ) ; } }