import { invariant } from 'outvariant' import { EventMap, Emitter } from 'strict-event-emitter' import { RequestHandler } from './handlers/RequestHandler' import { LifeCycleEventEmitter } from './sharedOptions' import { devUtils } from './utils/internal/devUtils' import { pipeEvents } from './utils/internal/pipeEvents' import { toReadonlyArray } from './utils/internal/toReadonlyArray' import { Disposable } from './utils/internal/Disposable' import type { WebSocketHandler } from './handlers/WebSocketHandler' export abstract class HandlersController { abstract prepend( runtimeHandlers: Array, ): void abstract reset(nextHandles: Array): void abstract currentHandlers(): Array } export class InMemoryHandlersController implements HandlersController { private handlers: Array constructor( private initialHandlers: Array, ) { this.handlers = [...initialHandlers] } public prepend( runtimeHandles: Array, ): void { this.handlers.unshift(...runtimeHandles) } public reset(nextHandlers: Array): void { this.handlers = nextHandlers.length > 0 ? [...nextHandlers] : [...this.initialHandlers] } public currentHandlers(): Array { return this.handlers } } /** * Generic class for the mock API setup. */ export abstract class SetupApi extends Disposable { protected handlersController: HandlersController protected readonly emitter: Emitter protected readonly publicEmitter: Emitter public readonly events: LifeCycleEventEmitter constructor(...initialHandlers: Array) { super() invariant( this.validateHandlers(initialHandlers), devUtils.formatMessage( `Failed to apply given request handlers: invalid input. Did you forget to spread the request handlers Array?`, ), ) this.handlersController = new InMemoryHandlersController(initialHandlers) this.emitter = new Emitter() this.publicEmitter = new Emitter() pipeEvents(this.emitter, this.publicEmitter) this.events = this.createLifeCycleEvents() this.subscriptions.push(() => { this.emitter.removeAllListeners() this.publicEmitter.removeAllListeners() }) } private validateHandlers(handlers: ReadonlyArray): boolean { // Guard against incorrect call signature of the setup API. return handlers.every((handler) => !Array.isArray(handler)) } public use( ...runtimeHandlers: Array ): void { invariant( this.validateHandlers(runtimeHandlers), devUtils.formatMessage( `Failed to call "use()" with the given request handlers: invalid input. Did you forget to spread the array of request handlers?`, ), ) this.handlersController.prepend(runtimeHandlers) } public restoreHandlers(): void { this.handlersController.currentHandlers().forEach((handler) => { if ('isUsed' in handler) { handler.isUsed = false } }) } public resetHandlers( ...nextHandlers: Array ): void { this.handlersController.reset(nextHandlers) } public listHandlers(): ReadonlyArray { return toReadonlyArray(this.handlersController.currentHandlers()) } private createLifeCycleEvents(): LifeCycleEventEmitter { return { on: (...args: any[]) => { return (this.publicEmitter.on as any)(...args) }, removeListener: (...args: any[]) => { return (this.publicEmitter.removeListener as any)(...args) }, removeAllListeners: (...args: any[]) => { return this.publicEmitter.removeAllListeners(...args) }, } } }