This commit is contained in:
Tutur33
2023-11-24 22:35:41 +01:00
parent 3c0b507a93
commit 7644b2a0f7
45165 changed files with 4803356 additions and 3 deletions
+6
View File
@@ -0,0 +1,6 @@
declare module '@ioc:Adonis/Core/Application' {
import { EmitterContract } from '@ioc:Adonis/Core/Event';
interface ContainerBindings {
'Adonis/Core/Event': EmitterContract;
}
}
+8
View File
@@ -0,0 +1,8 @@
/*
* @adonisjs/events
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
+207
View File
@@ -0,0 +1,207 @@
declare module '@ioc:Adonis/Core/Event' {
/**
* Returns the data type for a given key
*/
export type DataForEvent<K extends string> = K extends keyof EventsList ? EventsList[K] : any;
/**
* Shape of event handler
*/
export type EventHandler<T extends any = any> = (data: T) => Promise<void> | void;
/**
* Shape of catch all events handler
*/
export type AnyHandler = (event: keyof EventsList, data: {
[P in keyof EventsList]: EventsList[P];
}[keyof EventsList]) => Promise<void> | void;
/**
* Shape of event trap handler
*/
export type TrapHandler<T extends any = any> = EventHandler<T>;
/**
* The error handler for handling events when an emit call fails
*/
export type ErrorHandler = (event: string, error: any, data: any) => void;
/**
* Shape of trap all events handler
*/
export type TrapAllHandler = AnyHandler;
/**
* The shape of emitter transport. This has to be same as
* `emittery`.
*/
export interface EmitterTransportContract {
on(event: string, handler: EventHandler): any;
once(event: string): Promise<any>;
onAny(handler: (event: any, data: any) => Promise<void> | void): any;
emit(event: string, data: any): Promise<any>;
off(event: string, handler: EventHandler): any;
offAny(handler: (event: any, data: any) => Promise<void> | void): any;
off(event: string, handler: EventHandler): any;
clearListeners(event?: string): any;
listenerCount(event?: string): number;
}
/**
* Fake emitter to be used for finding and asserting
* faked events
*/
export interface FakeEmitterContract {
/**
* Returns all the emitted events
*/
all(): {
name: string;
data: any;
}[];
/**
* Find if the event exists
*/
exists<K extends keyof EventsList>(event: K): boolean;
exists(event: string): boolean;
exists<Events extends Record<string, any> = EventsList>(matchCallback: (event: {
[K in keyof Events]: {
name: K;
data: Events[K];
};
}[keyof Events]) => boolean): boolean;
/**
* Find an event
*/
find<K extends keyof EventsList>(event: K): {
name: K;
data: DataForEvent<K>;
} | null;
find(event: string): {
name: string;
data: any;
};
find<Events extends Record<string, any> = EventsList>(matchCallback: (event: {
[K in keyof Events]: {
name: K;
data: Events[K];
};
}[keyof Events]) => boolean): {
[K in keyof Events]: {
name: K;
data: Events[K];
};
}[keyof Events] | null;
/**
* Find multiple events
*/
filter<K extends keyof EventsList>(event: K): {
name: K;
data: DataForEvent<K>;
}[];
filter(event: string): {
name: string;
data: any;
}[];
filter<Events extends Record<string, any> = EventsList>(matchCallback: (event: {
[K in keyof Events]: {
name: K;
data: Events[K];
};
}[keyof Events]) => boolean): {
[K in keyof Events]: {
name: K;
data: Events[K];
};
}[keyof Events][];
/**
* Get number of events emitted
*/
size(): number;
}
/**
* Shape of Event emitter
*/
export interface EmitterContract {
transport: EmitterTransportContract;
/**
* Fake the upcoming events
*/
fake<K extends keyof EventsList>(events?: K[] | string[]): FakeEmitterContract;
/**
* Define a custom error handler
*/
onError(handler: ErrorHandler): this;
/**
* Define a custom IoC Container base namespace for resolving
* the listener bindings.
*/
namespace(namespace: string): this;
/**
* Listen for an event
*/
on<K extends keyof EventsList>(event: K, handler: EventHandler<EventsList[K]> | string): this;
on<K extends string>(event: K, handler: EventHandler<DataForEvent<K>> | string): this;
/**
* Listen for an event only once
*/
once<K extends keyof EventsList>(event: K, handler: EventHandler<EventsList[K]> | string): this;
once<K extends string>(event: K, handler: EventHandler<DataForEvent<K>> | string): this;
/**
* Listen for all events
*/
onAny(handler: AnyHandler | string): this;
/**
* Emit an event
*/
emit<K extends keyof EventsList>(event: K, data: EventsList[K]): Promise<void>;
emit<K extends string>(event: K, data: DataForEvent<K>): Promise<void>;
/**
* Remove event listener
*/
off<K extends keyof EventsList>(event: K, handler: EventHandler | string): void;
off<K extends string>(event: K, handler: EventHandler | string): void;
/**
* Remove event listener listening for all events
*/
offAny(handler: AnyHandler | string): void;
/**
* Clear a given listener for a given event
*/
clearListener<K extends keyof EventsList>(event: K, handler: EventHandler | string): void;
clearListener<K extends string>(event: K, handler: EventHandler | string): void;
/**
* Clear all listeners for a given event
*/
clearListeners<K extends keyof EventsList>(event: K): void;
clearListeners<K extends string>(event: K): void;
/**
* Clear all listeners for all events
*/
clearAllListeners(): void;
/**
* Returns count of listeners listening for a given event
*/
listenerCount<K extends keyof EventsList>(event?: K): number;
listenerCount<K extends string>(event?: K): number;
/**
* Returns true when an event has one or more listeners
*/
hasListeners<K extends keyof EventsList>(event?: K): boolean;
hasListeners<K extends string>(event?: K): boolean;
/**
* Trap a specific event. The event listener won't be executed during
* the trap. Call [[this.restore]] to remove traps
*/
trap<K extends keyof EventsList>(event: K, handler: TrapHandler<EventsList[K]>): this;
trap<K extends string>(event: K, handler: TrapHandler<DataForEvent<K>>): this;
/**
* Trap all the events, which are not trapped using the [[this.trap]] method
*/
trapAll(handler: AnyHandler): this;
/**
* Restore traps
*/
restore(): void;
}
/**
* An interface to define typed events
*/
export interface EventsList {
}
const Event: EmitterContract;
export default Event;
}
+8
View File
@@ -0,0 +1,8 @@
/*
* @adonisjs/events
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
+2
View File
@@ -0,0 +1,2 @@
/// <reference path="container.d.ts" />
/// <reference path="events.d.ts" />
+10
View File
@@ -0,0 +1,10 @@
/*
* @adonisjs/events
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/// <reference path="./container.ts" />
/// <reference path="./events.ts" />
+9
View File
@@ -0,0 +1,9 @@
import { ApplicationContract } from '@ioc:Adonis/Core/Application';
export default class EventProvider {
protected app: ApplicationContract;
constructor(app: ApplicationContract);
/**
* Register `Event emitter` to the container.
*/
register(): void;
}
+25
View File
@@ -0,0 +1,25 @@
"use strict";
/*
* @adonisjs/events
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
class EventProvider {
constructor(app) {
this.app = app;
}
/**
* Register `Event emitter` to the container.
*/
register() {
this.app.container.singleton('Adonis/Core/Event', () => {
const { Emitter } = require('../src/Emitter');
return new Emitter(this.app);
});
}
}
exports.default = EventProvider;
+108
View File
@@ -0,0 +1,108 @@
/// <reference path="../../adonis-typings/events.d.ts" />
import { ApplicationContract } from '@ioc:Adonis/Core/Application';
import { AnyHandler, EventsList, TrapHandler, EventHandler, DataForEvent, ErrorHandler, TrapAllHandler, EmitterContract, EmitterTransportContract } from '@ioc:Adonis/Core/Event';
import { FakeEmitter } from '../FakeEmitter';
/**
* Emitter class exposes the API for async event emitter built on top of
* Emittery. It also exposes an API to pre-define the Typescript types
* for different events.
*/
export declare class Emitter implements EmitterContract {
transport: EmitterTransportContract;
private iocResolver?;
/**
* Error handler to report emitter errors
*/
private errorHandler?;
/**
* Deprecated properties to manage trapping events
*/
private trappingEvents;
private traps;
private trapAllHandler?;
/**
* Fakes
*/
private eventsToFake;
private fakeEmitter;
constructor(app?: ApplicationContract);
/**
* Returns reference to the IoC resolver. Do not call this method until
* handler is not a string
*/
private getResolver;
/**
* Define a custom error handler
*/
onError(handler: ErrorHandler): this;
/**
* Define event handler for a given event
*/
on<K extends keyof EventsList | string>(event: K, handler: EventHandler<DataForEvent<K>> | string): this;
/**
* Define event handler for a given event and to be called
* only once.
*/
once<K extends keyof EventsList | string>(event: K, handler: EventHandler<DataForEvent<K>> | string): this;
/**
* Define catch all event handler to listen for all events.
*/
onAny(handler: AnyHandler | string): this;
/**
* Emit event
*/
emit<K extends keyof EventsList | string>(event: K, data: DataForEvent<K>): Promise<any>;
/**
* Remove existing event listener
*/
off<K extends keyof EventsList>(event: K | string, handler: EventHandler | string): void;
/**
* Remove existing event listener for catch all handler
*/
offAny(handler: AnyHandler | string): void;
/**
* Remove existing event listener.
* @alias off
*/
clearListener<K extends keyof EventsList | string>(event: K, handler: EventHandler | string): void;
/**
* Clear all listeners for a given event
*/
clearListeners<K extends keyof EventsList | string>(event: K): void;
/**
* Clear all listeners for all events
*/
clearAllListeners(): void;
/**
* Returns count of listeners for a given event or all
* events.
*/
listenerCount<K extends keyof EventsList | string>(event?: K): number;
/**
* Returns a boolean telling if listeners count for a given
* event or all events is greater than 0 or not.
*/
hasListeners<K extends keyof EventsList | string>(event?: K): boolean;
/**
* Define custom namespace for event listeners. It is set to `App/Listeners`
* by default.
*/
namespace(namespace: string): this;
/**
* Trap event instead of emitting it
*/
trap<K extends keyof EventsList | string>(event: K, handler: TrapHandler<DataForEvent<K>>): this;
/**
* Trap all events instead of emitting them
*/
trapAll(handler: TrapAllHandler): this;
/**
* Fake event emitter to collect events in-memory vs
* emitting them
*/
fake(events?: any[]): FakeEmitter;
/**
* Restore fakes
*/
restore(): void;
}
+250
View File
@@ -0,0 +1,250 @@
"use strict";
/*
* @adonisjs/events
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Emitter = void 0;
/// <reference path="../../adonis-typings/events.ts" />
const emittery_1 = __importDefault(require("emittery"));
const FakeEmitter_1 = require("../FakeEmitter");
const IocResolver_1 = require("../IocResolver");
/**
* Emitter class exposes the API for async event emitter built on top of
* Emittery. It also exposes an API to pre-define the Typescript types
* for different events.
*/
class Emitter {
constructor(app) {
this.transport = new emittery_1.default();
/**
* Deprecated properties to manage trapping events
*/
this.trappingEvents = false;
this.traps = new Map();
/**
* Fakes
*/
this.eventsToFake = new Set();
this.fakeEmitter = new FakeEmitter_1.FakeEmitter();
if (app) {
this.iocResolver = new IocResolver_1.IocResolver(app);
}
}
/**
* Returns reference to the IoC resolver. Do not call this method until
* handler is not a string
*/
getResolver(handler) {
if (!this.iocResolver) {
throw new Error(`Cannot resolve string based event handler "${handler}". IoC container is not provided to the event emitter`);
}
return this.iocResolver;
}
/**
* Define a custom error handler
*/
onError(handler) {
this.errorHandler = handler;
return this;
}
/**
* Define event handler for a given event
*/
on(event, handler) {
if (typeof handler === 'string') {
handler = this.getResolver(handler).getEventHandler(event, handler);
}
this.transport.on(event, handler);
return this;
}
/**
* Define event handler for a given event and to be called
* only once.
*/
once(event, handler) {
this.transport.once(event).then((data) => {
if (typeof handler === 'string') {
this.getResolver(handler).getEventHandler(event, handler)(data);
this.getResolver(handler).removeEventHandler(event, handler);
}
else {
handler(data);
}
});
return this;
}
/**
* Define catch all event handler to listen for all events.
*/
onAny(handler) {
if (typeof handler === 'string') {
handler = this.getResolver(handler).getAnyHandler(handler);
}
this.transport.onAny(handler);
return this;
}
/**
* Emit event
*/
async emit(event, data) {
try {
let shouldEmitEvent = true;
/**
* Register event with the fake emitter
*/
if (this.eventsToFake.has('*') || this.eventsToFake.has(event)) {
shouldEmitEvent = false;
this.fakeEmitter.events.push({ name: event, data });
}
if (this.trappingEvents) {
/**
* Give preference to the handler for a specific event
*/
if (this.traps.has(event)) {
shouldEmitEvent = false;
await this.traps.get(event)(data);
}
else if (this.trapAllHandler) {
shouldEmitEvent = false;
await this.trapAllHandler(event, data);
}
}
if (shouldEmitEvent) {
return await this.transport.emit(event, data);
}
}
catch (error) {
if (this.errorHandler) {
return this.errorHandler(event, error, data);
}
throw error;
}
}
/**
* Remove existing event listener
*/
off(event, handler) {
if (typeof handler === 'string') {
const offHandler = this.getResolver(handler).removeEventHandler(event, handler);
if (offHandler) {
this.transport.off(event, offHandler);
}
return;
}
this.transport.off(event, handler);
}
/**
* Remove existing event listener for catch all handler
*/
offAny(handler) {
if (typeof handler === 'string') {
const offHandler = this.getResolver(handler).removeAnyHandler(handler);
if (offHandler) {
this.transport.offAny(offHandler);
}
return;
}
this.transport.offAny(handler);
}
/**
* Remove existing event listener.
* @alias off
*/
clearListener(event, handler) {
this.off(event, handler);
}
/**
* Clear all listeners for a given event
*/
clearListeners(event) {
this.transport.clearListeners(event);
}
/**
* Clear all listeners for all events
*/
clearAllListeners() {
this.transport.clearListeners();
}
/**
* Returns count of listeners for a given event or all
* events.
*/
listenerCount(event) {
return this.transport.listenerCount(event ? event : undefined);
}
/**
* Returns a boolean telling if listeners count for a given
* event or all events is greater than 0 or not.
*/
hasListeners(event) {
return this.listenerCount(event) > 0;
}
/**
* Define custom namespace for event listeners. It is set to `App/Listeners`
* by default.
*/
namespace(namespace) {
if (this.iocResolver) {
this.iocResolver.namespace(namespace);
}
return this;
}
/**
* Trap event instead of emitting it
*/
trap(event, handler) {
process.emitWarning('DeprecationWarning', '"Event.trap" is deprecated. Instead use "Event.fake" method');
this.trappingEvents = true;
this.traps.set(event, handler);
return this;
}
/**
* Trap all events instead of emitting them
*/
trapAll(handler) {
process.emitWarning('DeprecationWarning', '"Event.trapAll" is deprecated. Instead use "Event.fake" method');
this.trappingEvents = true;
this.trapAllHandler = handler;
return this;
}
/**
* Fake event emitter to collect events in-memory vs
* emitting them
*/
fake(events) {
/**
* If no events have been mentioned, then fake
* all the events
*/
if (!events) {
this.eventsToFake.add('*');
return this.fakeEmitter;
}
/**
* Only track event names when wildcard is not added
*/
if (!this.eventsToFake.has('*')) {
events.forEach((event) => this.eventsToFake.add(event));
}
return this.fakeEmitter;
}
/**
* Restore fakes
*/
restore() {
this.trappingEvents = false;
this.trapAllHandler = undefined;
this.traps.clear();
this.eventsToFake.clear();
this.fakeEmitter.restore();
}
}
exports.Emitter = Emitter;
+44
View File
@@ -0,0 +1,44 @@
import { FakeEmitterContract } from '@ioc:Adonis/Core/Event';
/**
* Fake emitter to be used for finding and asserting
* faked events
*/
export declare class FakeEmitter implements FakeEmitterContract {
events: {
name: string;
data: any;
}[];
/**
* Get all the emitted events
*/
all(): {
name: string;
data: any;
}[];
/**
* Returns the size of captured events
*/
size(): number;
/**
* Find if the event has emitted
*/
exists(eventOrCallback: string | ((event: {
name: string;
data: any;
}) => boolean)): boolean;
/**
* Get selected events
*/
filter(eventOrCallback: string | ((event: {
name: string;
data: any;
}) => boolean)): any[];
/**
* Find a specific event
*/
find(eventOrCallback: string | ((event: {
name: string;
data: any;
}) => boolean)): any;
restore(): void;
}
+60
View File
@@ -0,0 +1,60 @@
"use strict";
/*
* @adonisjs/events
*
* (c) AdonisJS
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.FakeEmitter = void 0;
/**
* Fake emitter to be used for finding and asserting
* faked events
*/
class FakeEmitter {
constructor() {
this.events = [];
}
/**
* Get all the emitted events
*/
all() {
return this.events;
}
/**
* Returns the size of captured events
*/
size() {
return this.events.length;
}
/**
* Find if the event has emitted
*/
exists(eventOrCallback) {
return !!this.find(eventOrCallback);
}
/**
* Get selected events
*/
filter(eventOrCallback) {
if (typeof eventOrCallback === 'function') {
return this.events.filter(eventOrCallback);
}
return this.events.filter((event) => event.name === eventOrCallback);
}
/**
* Find a specific event
*/
find(eventOrCallback) {
if (typeof eventOrCallback === 'function') {
return this.events.find(eventOrCallback);
}
return this.events.find((event) => event.name === eventOrCallback);
}
restore() {
this.events = [];
}
}
exports.FakeEmitter = FakeEmitter;
+65
View File
@@ -0,0 +1,65 @@
/// <reference path="../../adonis-typings/events.d.ts" />
import { ApplicationContract } from '@ioc:Adonis/Core/Application';
import { AnyHandler, EventHandler } from '@ioc:Adonis/Core/Event';
/**
* Resolves string based event listeners from the IoC container. Also this method wraps
* the IoC container bindings in a closure. That closure is later used to remove
* the event listeners properly.
*/
export declare class IocResolver {
/**
* A reference to the event handlers resolved from the IoC container and
* cached. It is a map of
*
* [event, [namespace, resolvedHandler]]
*/
private eventHandlers;
/**
* A reference to the catch all event handlers. It is a map of
*
* [namespace, resolvedHandler]
*/
private anyHandlers;
/**
* Reference to AdonisJS IoC container resolver. It looks for listeners inside the
* `App/Listeners` namespace or the namespace defined inside `eventListeners`
* property
*/
private containerResolver;
/**
* A custom base namespace defined directly on the event class.
*/
private listenersBaseNamespace?;
constructor(app: ApplicationContract);
/**
* Returns the listener by resolving the namespace from the IoC container
*/
private getReferenceListener;
/**
* Returns all handlers for a given event.
*/
private getHandlersFor;
/**
* Define custom namespace for Event listeners
*/
namespace(namespace: string): void;
/**
* Returns event handler callback for an IoC container string reference.
* Adding same handler for the same event is noop.
*/
getEventHandler(event: string, handler: string): EventHandler;
/**
* Removes the event handler from the tracked list and also returns
* it back.
*/
removeEventHandler(event: string, handler: string): EventHandler | null;
/**
* Returns Event handler for wildcard events. Adding the same
* handler for multiple times is a noop.
*/
getAnyHandler(handler: string): AnyHandler;
/**
* Removes and returns the handler for a string reference.
*/
removeAnyHandler(handler: string): AnyHandler | null;
}
+118
View File
@@ -0,0 +1,118 @@
"use strict";
/*
* @adonisjs/events
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.IocResolver = void 0;
/**
* Resolves string based event listeners from the IoC container. Also this method wraps
* the IoC container bindings in a closure. That closure is later used to remove
* the event listeners properly.
*/
class IocResolver {
constructor(app) {
/**
* A reference to the event handlers resolved from the IoC container and
* cached. It is a map of
*
* [event, [namespace, resolvedHandler]]
*/
this.eventHandlers = new Map();
/**
* A reference to the catch all event handlers. It is a map of
*
* [namespace, resolvedHandler]
*/
this.anyHandlers = new Map();
this.containerResolver = app.container.getResolver(undefined, 'eventListeners', 'App/Listeners');
}
/**
* Returns the listener by resolving the namespace from the IoC container
*/
getReferenceListener(handler) {
return (...args) => {
return this.containerResolver.call(handler, this.listenersBaseNamespace, args);
};
}
/**
* Returns all handlers for a given event.
*/
getHandlersFor(event) {
if (!this.eventHandlers.has(event)) {
this.eventHandlers.set(event, new Map());
}
return this.eventHandlers.get(event);
}
/**
* Define custom namespace for Event listeners
*/
namespace(namespace) {
this.listenersBaseNamespace = namespace;
}
/**
* Returns event handler callback for an IoC container string reference.
* Adding same handler for the same event is noop.
*/
getEventHandler(event, handler) {
const handlers = this.getHandlersFor(event);
/**
* Return the existing handler when same handler for the
* same event already exists.
*
* Emittery will also re-use the same handler. So it is a noop
* everywhere.
*/
if (handlers.has(handler)) {
return handlers.get(handler);
}
const eventHandler = this.getReferenceListener(handler);
/**
* Store reference to the handler, so that we can clean it off
* later.
*/
handlers.set(handler, eventHandler);
return eventHandler;
}
/**
* Removes the event handler from the tracked list and also returns
* it back.
*/
removeEventHandler(event, handler) {
const handlers = this.getHandlersFor(event);
const eventHandler = handlers.get(handler);
if (eventHandler) {
handlers.delete(handler);
return eventHandler;
}
return null;
}
/**
* Returns Event handler for wildcard events. Adding the same
* handler for multiple times is a noop.
*/
getAnyHandler(handler) {
if (this.anyHandlers.has(handler)) {
return this.anyHandlers.get(handler);
}
const eventHandler = this.getReferenceListener(handler);
this.anyHandlers.set(handler, eventHandler);
return eventHandler;
}
/**
* Removes and returns the handler for a string reference.
*/
removeAnyHandler(handler) {
const anyHandler = this.anyHandlers.get(handler);
if (anyHandler) {
this.anyHandlers.delete(handler);
return anyHandler;
}
return null;
}
}
exports.IocResolver = IocResolver;
+1
View File
@@ -0,0 +1 @@
export { Emitter } from './src/Emitter';
+13
View File
@@ -0,0 +1,13 @@
"use strict";
/*
* @adonisjs/events
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Emitter = void 0;
var Emitter_1 = require("./src/Emitter");
Object.defineProperty(exports, "Emitter", { enumerable: true, get: function () { return Emitter_1.Emitter; } });