Current Path : /var/www/www-root/data/www/monolith-realty.ru/bitrix/js/main/core/src/lib/event/ |
Current File : /var/www/www-root/data/www/monolith-realty.ru/bitrix/js/main/core/src/lib/event/event-emitter.js |
import Type from '../type'; import Runtime from '../runtime'; import Reflection from '../reflection'; import BaseEvent from './base-event'; import EventStore from './event-emitter/eventstore'; import WarningStore from './event-emitter/warningstore'; const eventStore = new EventStore({ defaultMaxListeners: 10 }); const warningStore = new WarningStore(); const aliasStore = new Map(); const globalTarget = { GLOBAL_TARGET: 'GLOBAL_TARGET' // this key only for debugging purposes }; eventStore.add(globalTarget, { maxListeners: 25 }); const isEmitterProperty = Symbol.for('BX.Event.EventEmitter.isEmitter'); const namespaceProperty = Symbol('namespaceProperty'); const targetProperty = Symbol('targetProperty'); export default class EventEmitter { static GLOBAL_TARGET = globalTarget; static DEFAULT_MAX_LISTENERS = eventStore.getDefaultMaxListeners(); /** @private */ static sequenceValue = 1; constructor(...args) { this[targetProperty] = null; this[namespaceProperty] = null; this[isEmitterProperty] = true; let target = this; if (Object.getPrototypeOf(this) === EventEmitter.prototype && args.length > 0) //new EventEmitter(obj) case { if (!Type.isObject(args[0])) { throw new TypeError(`The "target" argument must be an object.`); } target = args[0]; this.setEventNamespace(args[1]); } this[targetProperty] = target; } /** * Makes a target observable * @param {object} target * @param {string} namespace */ static makeObservable(target: Object, namespace: string): void { if (!Type.isObject(target)) { throw new TypeError('The "target" argument must be an object.'); } if (!Type.isStringFilled(namespace)) { throw new TypeError('The "namespace" must be an non-empty string.'); } if (EventEmitter.isEventEmitter(target)) { throw new TypeError('The "target" is an event emitter already.'); } const targetProto = Object.getPrototypeOf(target); const emitter = new EventEmitter(); emitter.setEventNamespace(namespace); Object.setPrototypeOf(emitter, targetProto); Object.setPrototypeOf(target, emitter); Object.getOwnPropertyNames(EventEmitter.prototype).forEach(method => { if (['constructor'].includes(method)) { return; } emitter[method] = function(...args) { return EventEmitter.prototype[method].apply(target, args); } }); } setEventNamespace(namespace) { if (Type.isStringFilled(namespace)) { this[namespaceProperty] = namespace; } } getEventNamespace() { return this[namespaceProperty]; } /** * Subscribes listener on specified global event * @param {object} target * @param {string} eventName * @param {Function<BaseEvent>} listener * @param {object} options */ static subscribe( target: Object, eventName: string, listener: (event: BaseEvent) => void, options?: { compatMode?: boolean, useGlobalNaming?: boolean } ): void { if (Type.isString(target)) { options = listener; listener = eventName; eventName = target; target = this.GLOBAL_TARGET; } if (!Type.isObject(target)) { throw new TypeError(`The "target" argument must be an object.`); } eventName = this.normalizeEventName(eventName); if (!Type.isStringFilled(eventName)) { throw new TypeError(`The "eventName" argument must be a string.`); } listener = this.normalizeListener(listener); options = Type.isPlainObject(options) ? options : {}; const fullEventName = this.resolveEventName(eventName, target, options.useGlobalNaming === true); const { eventsMap, onceMap } = eventStore.getOrAdd(target); const onceListeners = onceMap.get(fullEventName); let listeners = eventsMap.get(fullEventName); if ((listeners && listeners.has(listener)) || (onceListeners && onceListeners.has(listener))) { console.error(`You cannot subscribe the same "${fullEventName}" event listener twice.`); } else { if (listeners) { listeners.set( listener, { listener, options, sort: this.getNextSequenceValue() } ) } else { listeners = new Map([[ listener, { listener, options, sort: this.getNextSequenceValue() } ]]); eventsMap.set(fullEventName, listeners); } } const maxListeners = this.getMaxListeners(target, eventName); if (listeners.size > maxListeners) { warningStore.add(target, fullEventName, listeners); warningStore.printDelayed(); } } /** * Subscribes a listener on a specified event * @param {string} eventName * @param {Function<BaseEvent>} listener * @return {this} */ subscribe(eventName: string, listener: (event: BaseEvent) => void): this { EventEmitter.subscribe(this, eventName, listener); return this; } /** * * @param {object} options * @param {object} [aliases] * @param {boolean} [compatMode=false] */ subscribeFromOptions( options: { [eventName: string]: Function }, aliases?: { [alias: string]: { eventName: string, namespace: string } }, compatMode?: boolean ) { if (!Type.isPlainObject(options)) { return; } aliases = Type.isPlainObject(aliases) ? EventEmitter.normalizeAliases(aliases) : {}; Object.keys(options).forEach((eventName) => { const listener = EventEmitter.normalizeListener(options[eventName]); eventName = EventEmitter.normalizeEventName(eventName); if (aliases[eventName]) { const { eventName: actualName } = aliases[eventName]; EventEmitter.subscribe(this, actualName, listener, { compatMode: compatMode !== false }); } else { EventEmitter.subscribe(this, eventName, listener, { compatMode: compatMode === true }); } }) } /** * Subscribes a listener that is called at * most once for a specified event. * @param {object} target * @param {string} eventName * @param {Function<BaseEvent>} listener */ static subscribeOnce( target: Object, eventName: string, listener: (event: BaseEvent) => void ): void { if (Type.isString(target)) { listener = eventName; eventName = target; target = this.GLOBAL_TARGET; } if (!Type.isObject(target)) { throw new TypeError(`The "target" argument must be an object.`); } eventName = this.normalizeEventName(eventName); if (!Type.isStringFilled(eventName)) { throw new TypeError(`The "eventName" argument must be a string.`); } listener = this.normalizeListener(listener); const fullEventName = this.resolveEventName(eventName, target); const { eventsMap, onceMap } = eventStore.getOrAdd(target); const listeners = eventsMap.get(fullEventName); let onceListeners = onceMap.get(fullEventName); if ((listeners && listeners.has(listener)) || (onceListeners && onceListeners.has(listener))) { console.error(`You cannot subscribe the same "${fullEventName}" event listener twice.`); } else { const once = (...args) => { this.unsubscribe(target, eventName, once); onceListeners.delete(listener); listener(...args); }; if (onceListeners) { onceListeners.set(listener, once); } else { onceListeners = new Map([[listener, once]]); onceMap.set(fullEventName, onceListeners); } this.subscribe(target, eventName, once); } } /** * Subscribes a listener that is called at most once for a specified event. * @param {string} eventName * @param {Function<BaseEvent>} listener * @return {this} */ subscribeOnce(eventName: string, listener: (event: BaseEvent) => void): this { EventEmitter.subscribeOnce(this, eventName, listener); return this; } /** * Unsubscribes an event listener * @param {object} target * @param {string} eventName * @param {Function<BaseEvent>} listener * @param options */ static unsubscribe( target: Object, eventName: string, listener: (event: BaseEvent) => void, options?: { useGlobalNaming?: boolean } ): void { if (Type.isString(target)) { listener = eventName; eventName = target; target = this.GLOBAL_TARGET; } eventName = this.normalizeEventName(eventName); if (!Type.isStringFilled(eventName)) { throw new TypeError(`The "eventName" argument must be a string.`); } listener = this.normalizeListener(listener); options = Type.isPlainObject(options) ? options : {}; const fullEventName = this.resolveEventName(eventName, target, options.useGlobalNaming === true); const targetInfo = eventStore.get(target); const listeners = targetInfo && targetInfo.eventsMap.get(fullEventName); const onceListeners = targetInfo && targetInfo.onceMap.get(fullEventName); if (listeners) { listeners.delete(listener); } if (onceListeners) { const once = onceListeners.get(listener); if (once) { onceListeners.delete(listener); listeners.delete(once); } } } /** * Unsubscribes an event listener * @param {string} eventName * @param {Function<BaseEvent>} listener * @return {this} */ unsubscribe(eventName: string, listener: (event: BaseEvent) => void): this { EventEmitter.unsubscribe(this, eventName, listener); return this; } /** * Unsubscribes all event listeners * @param {object} target * @param {string} eventName * @param options */ static unsubscribeAll( target: Object, eventName?: string, options?: { useGlobalNaming?: boolean } ): void { if (Type.isString(target)) { eventName = target; target = this.GLOBAL_TARGET; } if (Type.isStringFilled(eventName)) { const targetInfo = eventStore.get(target); if (targetInfo) { options = Type.isPlainObject(options) ? options : {}; const fullEventName = this.resolveEventName(eventName, target, options.useGlobalNaming === true); targetInfo.eventsMap.delete(fullEventName); targetInfo.onceMap.delete(fullEventName) } } else if (Type.isNil(eventName)) { if (target === this.GLOBAL_TARGET) { console.error('You cannot unsubscribe all global listeners.'); } else { eventStore.delete(target); } } } /** * Unsubscribes all event listeners * @param {string} [eventName] */ unsubscribeAll(eventName?: string): void { EventEmitter.unsubscribeAll(this, eventName); } /** * * @param {object} target * @param {string} eventName * @param {BaseEvent | any} event * @param {object} options * @returns {Array} */ static emit( target: Object, eventName: string, event?: BaseEvent | {[key: string]: any}, options?: { cloneData?: boolean, thisArg?: Object, useGlobalNaming?: boolean } ): Array { if (Type.isString(target)) { options = event; event = eventName; eventName = target; target = this.GLOBAL_TARGET; } if (!Type.isObject(target)) { throw new TypeError(`The "target" argument must be an object.`); } eventName = this.normalizeEventName(eventName); if (!Type.isStringFilled(eventName)) { throw new TypeError(`The "eventName" argument must be a string.`); } options = Type.isPlainObject(options) ? options : {}; const fullEventName = this.resolveEventName(eventName, target, options.useGlobalNaming === true); const globalEvents = eventStore.get(this.GLOBAL_TARGET); const globalListeners = (globalEvents && globalEvents.eventsMap.get(fullEventName)) || new Map(); let targetListeners = new Set(); if (target !== this.GLOBAL_TARGET) { const targetEvents = eventStore.get(target); targetListeners = (targetEvents && targetEvents.eventsMap.get(fullEventName)) || new Map(); } const listeners = [...globalListeners.values(), ...targetListeners.values()]; listeners.sort(function(a, b) { return a.sort - b.sort; }); const preparedEvent = this.prepareEvent(target, fullEventName, event); const result = []; for (let i = 0; i < listeners.length; i++) { if (preparedEvent.isImmediatePropagationStopped()) { break; } const { listener, options: listenerOptions } = listeners[i]; //A previous listener could remove a current listener. if (globalListeners.has(listener) || targetListeners.has(listener)) { let listenerResult; if (listenerOptions.compatMode) { let params = []; const compatData = preparedEvent.getCompatData(); if (compatData !== null) { params = options.cloneData === true ? Runtime.clone(compatData) : compatData } else { params = [preparedEvent]; } const context = Type.isUndefined(options.thisArg) ? target : options.thisArg; listenerResult = listener.apply(context, params); } else { listenerResult = Type.isUndefined(options.thisArg) ? listener(preparedEvent) : listener.call(options.thisArg, preparedEvent) ; } result.push(listenerResult); } } return result; } /** * Emits specified event with specified event object * @param {string} eventName * @param {BaseEvent | any} event * @return {this} */ emit(eventName: string, event?: BaseEvent | {[key: string]: any}): this { if (this.getEventNamespace() === null) { console.warn( 'The instance of BX.Event.EventEmitter is supposed to have an event namespace. ' + 'Use emitter.setEventNamespace() to make events more unique.' ); } EventEmitter.emit(this, eventName, event); return this; } /** * Emits global event and returns a promise that is resolved when * all promise returned from event handlers are resolved, * or rejected when at least one of the returned promise is rejected. * Importantly. You can return any value from synchronous handlers, not just promise * @param {object} target * @param {string} eventName * @param {BaseEvent | any} event * @return {Promise<Array>} */ static emitAsync(target: Object, eventName: string, event?: BaseEvent | {[key: string]: any}): Promise<Array> { if (Type.isString(target)) { event = eventName; eventName = target; target = this.GLOBAL_TARGET; } return Promise.all(this.emit(target, eventName, event)); } /** * Emits event and returns a promise that is resolved when * all promise returned from event handlers are resolved, * or rejected when at least one of the returned promise is rejected. * Importantly. You can return any value from synchronous handlers, not just promise * @param {string} eventName * @param {BaseEvent|any} event * @return {Promise<Array>} */ emitAsync(eventName: string, event?: BaseEvent | {[key: string]: any}): Promise<Array> { if (this.getEventNamespace() === null) { console.warn( 'The instance of BX.Event.EventEmitter is supposed to have an event namespace. ' + 'Use emitter.setEventNamespace() to make events more unique.' ); } return EventEmitter.emitAsync(this, eventName, event); } /** * @private * @param {object} target * @param {string} eventName * @param {BaseEvent|any} event * @returns {BaseEvent} */ static prepareEvent( target: Object, eventName: string, event?: BaseEvent | {[key: string]: any}, ): BaseEvent { let preparedEvent = event; if (!(event instanceof BaseEvent)) { preparedEvent = new BaseEvent(); preparedEvent.setData(event); } preparedEvent.setTarget(this.isEventEmitter(target) ? target[targetProperty] : target); preparedEvent.setType(eventName); return preparedEvent; } /** * @private * @returns {number} */ static getNextSequenceValue(): number { return this.sequenceValue++; } /** * Sets max global events listeners count * Event.EventEmitter.setMaxListeners(10) - sets the default value for all events (global target) * Event.EventEmitter.setMaxListeners("onClose", 10) - sets the value for onClose event (global target) * Event.EventEmitter.setMaxListeners(obj, 10) - sets the default value for all events (obj target) * Event.EventEmitter.setMaxListeners(obj, "onClose", 10); - sets the value for onClose event (obj target) * @return {void} * @param args */ static setMaxListeners(...args): void { let target = this.GLOBAL_TARGET; let eventName = null; let count = undefined; if (args.length === 1) { count = args[0]; } else if (args.length === 2) { if (Type.isString(args[0])) { [eventName, count] = args; } else { [target, count] = args; } } else if (args.length >= 3) { [target, eventName, count] = args; } if (!Type.isObject(target)) { throw new TypeError(`The "target" argument must be an object.`); } if (eventName !== null && !Type.isStringFilled(eventName)) { throw new TypeError(`The "eventName" argument must be a string.`); } if (!Type.isNumber(count) || count < 0) { throw new TypeError( `The value of "count" is out of range. It must be a non-negative number. Received ${count}.` ); } const targetInfo = eventStore.getOrAdd(target); if (Type.isStringFilled(eventName)) { const fullEventName = this.resolveEventName(eventName, target); targetInfo.eventsMaxListeners.set(fullEventName, count); } else { targetInfo.maxListeners = count; } } /** * Sets max events listeners count * this.setMaxListeners(10) - sets the default value for all events * this.setMaxListeners("onClose", 10) sets the value for onClose event * @return {this} * @param args */ setMaxListeners(...args): this { EventEmitter.setMaxListeners(this, ...args); return this; } /** * Returns max event listeners count * @param {object} target * @param {string} [eventName] * @returns {number} */ static getMaxListeners(target: Object, eventName?: string): number { if (Type.isString(target)) { eventName = target; target = this.GLOBAL_TARGET; } else if (Type.isNil(target)) { target = this.GLOBAL_TARGET; } if (!Type.isObject(target)) { throw new TypeError(`The "target" argument must be an object.`); } const targetInfo = eventStore.get(target); if (targetInfo) { let maxListeners = targetInfo.maxListeners; if (Type.isStringFilled(eventName)) { const fullEventName = this.resolveEventName(eventName, target); maxListeners = targetInfo.eventsMaxListeners.get(fullEventName) || maxListeners; } return maxListeners; } return this.DEFAULT_MAX_LISTENERS; } /** * Returns max event listeners count * @param {string} [eventName] * @returns {number} */ getMaxListeners(eventName?: string): number { return EventEmitter.getMaxListeners(this, eventName); } /** * Adds or subtracts max listeners count * Event.EventEmitter.addMaxListeners() - adds one max listener for all events of global target * Event.EventEmitter.addMaxListeners(3) - adds three max listeners for all events of global target * Event.EventEmitter.addMaxListeners(-1) - subtracts one max listener for all events of global target * Event.EventEmitter.addMaxListeners('onClose') - adds one max listener for onClose event of global target * Event.EventEmitter.addMaxListeners('onClose', 2) - adds two max listeners for onClose event of global target * Event.EventEmitter.addMaxListeners('onClose', -1) - subtracts one max listener for onClose event of global target * * Event.EventEmitter.addMaxListeners(obj) - adds one max listener for all events of 'obj' target * Event.EventEmitter.addMaxListeners(obj, 3) - adds three max listeners for all events of 'obj' target * Event.EventEmitter.addMaxListeners(obj, -1) - subtracts one max listener for all events of 'obj' target * Event.EventEmitter.addMaxListeners(obj, 'onClose') - adds one max listener for onClose event of 'obj' target * Event.EventEmitter.addMaxListeners(obj, 'onClose', 2) - adds two max listeners for onClose event of 'obj' target * Event.EventEmitter.addMaxListeners(obj, 'onClose', -1) - subtracts one max listener for onClose event of 'obj' target * @param args * @returns {number} */ static addMaxListeners(...args) { const [target, eventName, increment] = this.destructMaxListenersArgs(...args); const maxListeners = Math.max(this.getMaxListeners(target, eventName) + increment, 0); if (Type.isStringFilled(eventName)) { EventEmitter.setMaxListeners(target, eventName, maxListeners); } else { EventEmitter.setMaxListeners(target, maxListeners); } return maxListeners; } /** * Increases max listeners count * * Event.EventEmitter.incrementMaxListeners() - adds one max listener for all events of global target * Event.EventEmitter.incrementMaxListeners(3) - adds three max listeners for all events of global target * Event.EventEmitter.incrementMaxListeners('onClose') - adds one max listener for onClose event of global target * Event.EventEmitter.incrementMaxListeners('onClose', 2) - adds two max listeners for onClose event of global target * * Event.EventEmitter.incrementMaxListeners(obj) - adds one max listener for all events of 'obj' target * Event.EventEmitter.incrementMaxListeners(obj, 3) - adds three max listeners for all events of 'obj' target * Event.EventEmitter.incrementMaxListeners(obj, 'onClose') - adds one max listener for onClose event of 'obj' target * Event.EventEmitter.incrementMaxListeners(obj, 'onClose', 2) - adds two max listeners for onClose event of 'obj' target */ static incrementMaxListeners(...args): number { const [target, eventName, increment] = this.destructMaxListenersArgs(...args); return this.addMaxListeners(target, eventName, Math.abs(increment)); } /** * Increases max listeners count * this.incrementMaxListeners() - adds one max listener for all events * this.incrementMaxListeners(3) - adds three max listeners for all events * this.incrementMaxListeners('onClose') - adds one max listener for onClose event * this.incrementMaxListeners('onClose', 2) - adds two max listeners for onClose event */ incrementMaxListeners(...args): number { return EventEmitter.incrementMaxListeners(this, ...args); } /** * Decreases max listeners count * * Event.EventEmitter.decrementMaxListeners() - subtracts one max listener for all events of global target * Event.EventEmitter.decrementMaxListeners(3) - subtracts three max listeners for all events of global target * Event.EventEmitter.decrementMaxListeners('onClose') - subtracts one max listener for onClose event of global target * Event.EventEmitter.decrementMaxListeners('onClose', 2) - subtracts two max listeners for onClose event of global target * * Event.EventEmitter.decrementMaxListeners(obj) - subtracts one max listener for all events of 'obj' target * Event.EventEmitter.decrementMaxListeners(obj, 3) - subtracts three max listeners for all events of 'obj' target * Event.EventEmitter.decrementMaxListeners(obj, 'onClose') - subtracts one max listener for onClose event of 'obj' target * Event.EventEmitter.decrementMaxListeners(obj, 'onClose', 2) - subtracts two max listeners for onClose event of 'obj' target */ static decrementMaxListeners(...args): number { const [target, eventName, increment] = this.destructMaxListenersArgs(...args); return this.addMaxListeners(target, eventName, -Math.abs(increment)); } /** * Increases max listeners count * this.decrementMaxListeners() - subtracts one max listener for all events * this.decrementMaxListeners(3) - subtracts three max listeners for all events * this.decrementMaxListeners('onClose') - subtracts one max listener for onClose event * this.decrementMaxListeners('onClose', 2) - subtracts two max listeners for onClose event */ decrementMaxListeners(...args): number { return EventEmitter.decrementMaxListeners(this, ...args); } /** * @private * @param {Array} args * @returns Array */ static destructMaxListenersArgs(...args) { let eventName = null; let increment = 1; let target = this.GLOBAL_TARGET; if (args.length === 1) { if (Type.isNumber(args[0])) { increment = args[0]; } else if (Type.isString(args[0])) { eventName = args[0]; } else { target = args[0]; } } else if (args.length === 2) { if (Type.isString(args[0])) { [eventName, increment] = args; } else if (Type.isString(args[1])) { [target, eventName] = args; } else { [target, increment] = args; } } else if (args.length >= 3) { [target, eventName, increment] = args; } if (!Type.isObject(target)) { throw new TypeError(`The "target" argument must be an object.`); } if (eventName !== null && !Type.isStringFilled(eventName)) { throw new TypeError(`The "eventName" argument must be a string.`); } if (!Type.isNumber(increment)) { throw new TypeError(`The value of "increment" must be a number.`); } return [target, eventName, increment]; } /** * Gets listeners list for a specified event * @param {object} target * @param {string} eventName */ static getListeners(target: Object, eventName: string): Function[] { if (Type.isString(target)) { eventName = target; target = this.GLOBAL_TARGET; } if (!Type.isObject(target)) { throw new TypeError(`The "target" argument must be an object.`); } eventName = this.normalizeEventName(eventName); if (!Type.isStringFilled(eventName)) { throw new TypeError(`The "eventName" argument must be a string.`); } const targetInfo = eventStore.get(target); if (!targetInfo) { return new Map(); } const fullEventName = this.resolveEventName(eventName, target); return targetInfo.eventsMap.get(fullEventName) || new Map(); } /** * Gets listeners list for specified event * @param {string} eventName */ getListeners(eventName: string): Function[] { return EventEmitter.getListeners(this, eventName); } /** * Returns a full event name with namespace * @param {string} eventName * @returns {string} */ getFullEventName(eventName: string) { if (!Type.isStringFilled(eventName)) { throw new TypeError(`The "eventName" argument must be a string.`); } return EventEmitter.makeFullEventName(this.getEventNamespace(), eventName); } /** * Registers aliases (old event names for BX.onCustomEvent) * @param aliases */ static registerAliases(aliases: { [alias: string]: { eventName: string, namespace: string } }) { aliases = this.normalizeAliases(aliases); Object.keys(aliases).forEach((alias) => { aliasStore.set(alias, { eventName: aliases[alias].eventName, namespace: aliases[alias].namespace }); }); EventEmitter.mergeEventAliases(aliases); } /** * @private * @param aliases */ static normalizeAliases(aliases: { [alias: string]: { eventName: string, namespace: string } }) { if (!Type.isPlainObject(aliases)) { throw new TypeError(`The "aliases" argument must be an object.`); } const result = Object.create(null); for (let alias in aliases) { if (!Type.isStringFilled(alias)) { throw new TypeError(`The alias must be an non-empty string.`); } const options = aliases[alias]; if (!options || !Type.isStringFilled(options.eventName) || !Type.isStringFilled(options.namespace)) { throw new TypeError(`The alias options must set the "eventName" and the "namespace".`); } alias = this.normalizeEventName(alias); result[alias] = { eventName: options.eventName, namespace: options.namespace }; } return result; } /** * @private */ static mergeEventAliases(aliases) { const globalEvents = eventStore.get(this.GLOBAL_TARGET); if (!globalEvents) { return; } Object.keys(aliases).forEach((alias) => { const options = aliases[alias]; alias = this.normalizeEventName(alias); const fullEventName = this.makeFullEventName(options.namespace, options.eventName); const aliasListeners = globalEvents.eventsMap.get(alias); if (aliasListeners) { const listeners = globalEvents.eventsMap.get(fullEventName) || new Map(); globalEvents.eventsMap.set(fullEventName, new Map([...listeners, ...aliasListeners])); globalEvents.eventsMap.delete(alias); } const aliasOnceListeners = globalEvents.onceMap.get(alias); if (aliasOnceListeners) { const onceListeners = globalEvents.onceMap.get(fullEventName) || new Map(); globalEvents.onceMap.set(fullEventName, new Map([...onceListeners, ...aliasOnceListeners])); globalEvents.onceMap.delete(alias); } const aliasMaxListeners = globalEvents.eventsMaxListeners.get(alias); if (aliasMaxListeners) { const eventMaxListeners = globalEvents.eventsMaxListeners.get(fullEventName) || 0; globalEvents.eventsMaxListeners.set(fullEventName, Math.max(eventMaxListeners, aliasMaxListeners)); globalEvents.eventsMaxListeners.delete(alias); } }); } /** * Returns true if the target is an instance of Event.EventEmitter * @param {object} target * @returns {boolean} */ static isEventEmitter(target: Object) { return Type.isObject(target) && target[isEmitterProperty] === true; } /** * @private * @param {string} eventName * @returns {string} */ static normalizeEventName(eventName: string): string { if (!Type.isStringFilled(eventName)) { return ''; } return eventName.toLowerCase(); } /** * @private */ static normalizeListener(listener: Function | string): Function { if (Type.isString(listener)) { listener = Reflection.getClass(listener); } if (!Type.isFunction(listener)) { throw new TypeError( `The "listener" argument must be of type Function. Received type ${typeof listener}.` ); } return listener; } /** * @private * @param eventName * @param target * @param useGlobalNaming * @returns {string} */ static resolveEventName(eventName: string, target: Object, useGlobalNaming: boolean = false) { eventName = this.normalizeEventName(eventName); if (!Type.isStringFilled(eventName)) { return ''; } if (this.isEventEmitter(target) && useGlobalNaming !== true) { if (target.getEventNamespace() !== null && eventName.includes('.')) { console.warn(`Possible the wrong event name "${eventName}".`); } eventName = target.getFullEventName(eventName); } else if (aliasStore.has(eventName)) { const { namespace, eventName: actualEventName } = aliasStore.get(eventName); eventName = this.makeFullEventName(namespace, actualEventName); } return eventName; } /** * @private * @param {string} namespace * @param {string} eventName * @returns {string} */ static makeFullEventName(namespace: string, eventName: string) { const fullName = Type.isStringFilled(namespace) ? `${namespace}:${eventName}` : eventName; return Type.isStringFilled(fullName) ? fullName.toLowerCase() : ''; } }