UNPKG

msw

Version:

Seamless REST/GraphQL API mocking library for browser and Node.js.

1 lines 7.59 kB
{"version":3,"sources":["../../../src/core/experimental/handlers-controller.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport { type RequestHandler } from '../handlers/RequestHandler'\nimport { type WebSocketHandler } from '../handlers/WebSocketHandler'\nimport { devUtils } from '../utils/internal/devUtils'\nimport { getSiblingHandlers } from '../utils/internal/attachSiblingHandlers'\n\nexport type AnyHandler = RequestHandler | WebSocketHandler\nexport type HandlersMap = Partial<Record<AnyHandler['kind'], Array<AnyHandler>>>\n\nexport function groupHandlersByKind(handlers: Array<AnyHandler>): HandlersMap {\n const groups: HandlersMap = {}\n\n const pushUnique = (kind: AnyHandler['kind'], handler: AnyHandler) => {\n const bucket = (groups[kind] ||= [])\n\n if (!bucket.includes(handler)) {\n bucket.push(handler)\n }\n }\n\n /**\n * @note `Object.groupBy` is not implemented in Node.js v20.\n */\n for (const handler of handlers) {\n pushUnique(handler.kind, handler)\n\n for (const sibling of getSiblingHandlers(handler)) {\n pushUnique(sibling.kind, sibling)\n }\n }\n\n return groups\n}\n\nexport interface HandlersControllerState {\n initialHandlers: HandlersMap\n handlers: HandlersMap\n}\n\nexport abstract class HandlersController {\n protected getInitialState(\n initialHandlers: Array<AnyHandler>,\n ): HandlersControllerState {\n invariant(\n this.#validateHandlers(initialHandlers),\n devUtils.formatMessage(\n 'Failed to apply given request handlers: invalid input. Did you forget to spread the request handlers Array?',\n ),\n )\n\n const normalizedInitialHandlers = groupHandlersByKind(initialHandlers)\n\n return {\n initialHandlers: normalizedInitialHandlers,\n handlers: { ...normalizedInitialHandlers },\n }\n }\n\n protected abstract getState(): HandlersControllerState\n protected abstract setState(nextState: Partial<HandlersControllerState>): void\n\n public currentHandlers(): Array<AnyHandler> {\n return Object.values(this.getState().handlers)\n .flat()\n .filter((handler) => handler != null)\n }\n\n public getHandlersByKind(kind: AnyHandler['kind']): Array<AnyHandler> {\n return this.getState().handlers[kind] || []\n }\n\n public use(nextHandlers: Array<AnyHandler>): void {\n invariant(\n this.#validateHandlers(nextHandlers),\n devUtils.formatMessage(\n '[MSW] Failed to call \"use()\" with the given request handlers: invalid input. Did you forget to spread the array of request handlers?',\n ),\n )\n\n if (nextHandlers.length === 0) {\n return\n }\n\n const { handlers } = this.getState()\n const overrides = groupHandlersByKind(nextHandlers)\n\n // Prepend overrides to their respective kind buckets so they take\n // priority over existing handlers while preserving input order.\n for (const kind in overrides) {\n const overridesForKind = overrides[kind as AnyHandler['kind']]!\n const existingForKind = handlers[kind as AnyHandler['kind']]\n handlers[kind as AnyHandler['kind']] = existingForKind\n ? [...overridesForKind, ...existingForKind]\n : overridesForKind\n }\n\n this.setState({ handlers })\n }\n\n public reset(nextHandlers: Array<AnyHandler>): void {\n invariant(\n nextHandlers.length > 0 ? this.#validateHandlers(nextHandlers) : true,\n devUtils.formatMessage(\n 'Failed to replace initial handlers during reset: invalid handlers. Did you forget to spread the handlers array?',\n ),\n )\n\n for (const handler of this.currentHandlers()) {\n if ('reset' in handler) {\n handler['reset']()\n }\n }\n\n const { initialHandlers } = this.getState()\n\n if (nextHandlers.length === 0) {\n this.setState({\n handlers: { ...initialHandlers },\n })\n\n return\n }\n\n const normalizedNextHandlers = groupHandlersByKind(nextHandlers)\n\n this.setState({\n initialHandlers: normalizedNextHandlers,\n handlers: { ...normalizedNextHandlers },\n })\n }\n\n public restore(): void {\n for (const handler of this.currentHandlers()) {\n if ('restore' in handler) {\n handler['restore']()\n }\n }\n }\n\n #validateHandlers(handlers: Array<AnyHandler>): boolean {\n return handlers.every((handler) => !Array.isArray(handler))\n }\n}\n\nexport class InMemoryHandlersController extends HandlersController {\n #handlers: HandlersMap\n #initialHandlers: HandlersMap\n\n constructor(initialHandlers: Array<AnyHandler>) {\n super()\n\n const initialState = this.getInitialState(initialHandlers)\n\n this.#initialHandlers = initialState.initialHandlers\n this.#handlers = initialState.handlers\n }\n\n protected getState(): HandlersControllerState {\n return {\n initialHandlers: this.#initialHandlers,\n handlers: this.#handlers,\n }\n }\n\n protected setState(nextState: Partial<HandlersControllerState>): void {\n if (nextState.initialHandlers) {\n this.#initialHandlers = nextState.initialHandlers\n }\n\n if (nextState.handlers) {\n this.#handlers = nextState.handlers\n }\n }\n}\n"],"mappings":"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","names":[]}