Update checked-in dependencies
This commit is contained in:
parent
7fdbca3ba3
commit
357e0ceaa9
360 changed files with 25673 additions and 917 deletions
249
node_modules/@mswjs/interceptors/src/Interceptor.ts
generated
vendored
Normal file
249
node_modules/@mswjs/interceptors/src/Interceptor.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
import { Logger } from '@open-draft/logger'
|
||||
import { Emitter, Listener } from 'strict-event-emitter'
|
||||
|
||||
export type InterceptorEventMap = Record<string, any>
|
||||
export type InterceptorSubscription = () => void
|
||||
|
||||
/**
|
||||
* Request header name to detect when a single request
|
||||
* is being handled by nested interceptors (XHR -> ClientRequest).
|
||||
* Obscure by design to prevent collisions with user-defined headers.
|
||||
* Ideally, come up with the Interceptor-level mechanism for this.
|
||||
* @see https://github.com/mswjs/interceptors/issues/378
|
||||
*/
|
||||
export const INTERNAL_REQUEST_ID_HEADER_NAME =
|
||||
'x-interceptors-internal-request-id'
|
||||
|
||||
export function getGlobalSymbol<V>(symbol: Symbol): V | undefined {
|
||||
return (
|
||||
// @ts-ignore https://github.com/Microsoft/TypeScript/issues/24587
|
||||
globalThis[symbol] || undefined
|
||||
)
|
||||
}
|
||||
|
||||
function setGlobalSymbol(symbol: Symbol, value: any): void {
|
||||
// @ts-ignore
|
||||
globalThis[symbol] = value
|
||||
}
|
||||
|
||||
export function deleteGlobalSymbol(symbol: Symbol): void {
|
||||
// @ts-ignore
|
||||
delete globalThis[symbol]
|
||||
}
|
||||
|
||||
export enum InterceptorReadyState {
|
||||
INACTIVE = 'INACTIVE',
|
||||
APPLYING = 'APPLYING',
|
||||
APPLIED = 'APPLIED',
|
||||
DISPOSING = 'DISPOSING',
|
||||
DISPOSED = 'DISPOSED',
|
||||
}
|
||||
|
||||
export type ExtractEventNames<Events extends Record<string, any>> =
|
||||
Events extends Record<infer EventName, any> ? EventName : never
|
||||
|
||||
export class Interceptor<Events extends InterceptorEventMap> {
|
||||
protected emitter: Emitter<Events>
|
||||
protected subscriptions: Array<InterceptorSubscription>
|
||||
protected logger: Logger
|
||||
|
||||
public readyState: InterceptorReadyState
|
||||
|
||||
constructor(private readonly symbol: symbol) {
|
||||
this.readyState = InterceptorReadyState.INACTIVE
|
||||
|
||||
this.emitter = new Emitter()
|
||||
this.subscriptions = []
|
||||
this.logger = new Logger(symbol.description!)
|
||||
|
||||
// Do not limit the maximum number of listeners
|
||||
// so not to limit the maximum amount of parallel events emitted.
|
||||
this.emitter.setMaxListeners(0)
|
||||
|
||||
this.logger.info('constructing the interceptor...')
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this interceptor can be applied
|
||||
* in the current environment.
|
||||
*/
|
||||
protected checkEnvironment(): boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply this interceptor to the current process.
|
||||
* Returns an already running interceptor instance if it's present.
|
||||
*/
|
||||
public apply(): void {
|
||||
const logger = this.logger.extend('apply')
|
||||
logger.info('applying the interceptor...')
|
||||
|
||||
if (this.readyState === InterceptorReadyState.APPLIED) {
|
||||
logger.info('intercepted already applied!')
|
||||
return
|
||||
}
|
||||
|
||||
const shouldApply = this.checkEnvironment()
|
||||
|
||||
if (!shouldApply) {
|
||||
logger.info('the interceptor cannot be applied in this environment!')
|
||||
return
|
||||
}
|
||||
|
||||
this.readyState = InterceptorReadyState.APPLYING
|
||||
|
||||
// Whenever applying a new interceptor, check if it hasn't been applied already.
|
||||
// This enables to apply the same interceptor multiple times, for example from a different
|
||||
// interceptor, only proxying events but keeping the stubs in a single place.
|
||||
const runningInstance = this.getInstance()
|
||||
|
||||
if (runningInstance) {
|
||||
logger.info('found a running instance, reusing...')
|
||||
|
||||
// Proxy any listeners you set on this instance to the running instance.
|
||||
this.on = (event, listener) => {
|
||||
logger.info('proxying the "%s" listener', event)
|
||||
|
||||
// Add listeners to the running instance so they appear
|
||||
// at the top of the event listeners list and are executed first.
|
||||
runningInstance.emitter.addListener(event, listener)
|
||||
|
||||
// Ensure that once this interceptor instance is disposed,
|
||||
// it removes all listeners it has appended to the running interceptor instance.
|
||||
this.subscriptions.push(() => {
|
||||
runningInstance.emitter.removeListener(event, listener)
|
||||
logger.info('removed proxied "%s" listener!', event)
|
||||
})
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
this.readyState = InterceptorReadyState.APPLIED
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
logger.info('no running instance found, setting up a new instance...')
|
||||
|
||||
// Setup the interceptor.
|
||||
this.setup()
|
||||
|
||||
// Store the newly applied interceptor instance globally.
|
||||
this.setInstance()
|
||||
|
||||
this.readyState = InterceptorReadyState.APPLIED
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the module augments and stubs necessary for this interceptor.
|
||||
* This method is not run if there's a running interceptor instance
|
||||
* to prevent instantiating an interceptor multiple times.
|
||||
*/
|
||||
protected setup(): void {}
|
||||
|
||||
/**
|
||||
* Listen to the interceptor's public events.
|
||||
*/
|
||||
public on<EventName extends ExtractEventNames<Events>>(
|
||||
event: EventName,
|
||||
listener: Listener<Events[EventName]>
|
||||
): this {
|
||||
const logger = this.logger.extend('on')
|
||||
|
||||
if (
|
||||
this.readyState === InterceptorReadyState.DISPOSING ||
|
||||
this.readyState === InterceptorReadyState.DISPOSED
|
||||
) {
|
||||
logger.info('cannot listen to events, already disposed!')
|
||||
return this
|
||||
}
|
||||
|
||||
logger.info('adding "%s" event listener:', event, listener)
|
||||
|
||||
this.emitter.on(event, listener)
|
||||
return this
|
||||
}
|
||||
|
||||
public once<EventName extends ExtractEventNames<Events>>(
|
||||
event: EventName,
|
||||
listener: Listener<Events[EventName]>
|
||||
): this {
|
||||
this.emitter.once(event, listener)
|
||||
return this
|
||||
}
|
||||
|
||||
public off<EventName extends ExtractEventNames<Events>>(
|
||||
event: EventName,
|
||||
listener: Listener<Events[EventName]>
|
||||
): this {
|
||||
this.emitter.off(event, listener)
|
||||
return this
|
||||
}
|
||||
|
||||
public removeAllListeners<EventName extends ExtractEventNames<Events>>(
|
||||
event?: EventName
|
||||
): this {
|
||||
this.emitter.removeAllListeners(event)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes of any side-effects this interceptor has introduced.
|
||||
*/
|
||||
public dispose(): void {
|
||||
const logger = this.logger.extend('dispose')
|
||||
|
||||
if (this.readyState === InterceptorReadyState.DISPOSED) {
|
||||
logger.info('cannot dispose, already disposed!')
|
||||
return
|
||||
}
|
||||
|
||||
logger.info('disposing the interceptor...')
|
||||
this.readyState = InterceptorReadyState.DISPOSING
|
||||
|
||||
if (!this.getInstance()) {
|
||||
logger.info('no interceptors running, skipping dispose...')
|
||||
return
|
||||
}
|
||||
|
||||
// Delete the global symbol as soon as possible,
|
||||
// indicating that the interceptor is no longer running.
|
||||
this.clearInstance()
|
||||
|
||||
logger.info('global symbol deleted:', getGlobalSymbol(this.symbol))
|
||||
|
||||
if (this.subscriptions.length > 0) {
|
||||
logger.info('disposing of %d subscriptions...', this.subscriptions.length)
|
||||
|
||||
for (const dispose of this.subscriptions) {
|
||||
dispose()
|
||||
}
|
||||
|
||||
this.subscriptions = []
|
||||
|
||||
logger.info('disposed of all subscriptions!', this.subscriptions.length)
|
||||
}
|
||||
|
||||
this.emitter.removeAllListeners()
|
||||
logger.info('destroyed the listener!')
|
||||
|
||||
this.readyState = InterceptorReadyState.DISPOSED
|
||||
}
|
||||
|
||||
private getInstance(): this | undefined {
|
||||
const instance = getGlobalSymbol<this>(this.symbol)
|
||||
this.logger.info('retrieved global instance:', instance?.constructor?.name)
|
||||
return instance
|
||||
}
|
||||
|
||||
private setInstance(): void {
|
||||
setGlobalSymbol(this.symbol, this)
|
||||
this.logger.info('set global instance!', this.symbol.description)
|
||||
}
|
||||
|
||||
private clearInstance(): void {
|
||||
deleteGlobalSymbol(this.symbol)
|
||||
this.logger.info('cleared global instance!', this.symbol.description)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue