Skip to main content
Go to Latest
File
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.// Copyright Node.js contributors. All rights reserved. MIT License.
import { ERR_EVENT_RECURSION, ERR_INVALID_ARG_TYPE, ERR_INVALID_THIS, ERR_MISSING_ARGS,} from "./errors.ts";import { validateObject, validateString } from "./validators.mjs";import { emitWarning } from "../process.ts";import { nextTick } from "../_next_tick.ts";
import { customInspectSymbol, kEnumerableProperty } from "./util.mjs";import { inspect } from "../util.ts";
const kIsEventTarget = Symbol.for("nodejs.event_target");const kIsNodeEventTarget = Symbol("kIsNodeEventTarget");
import { EventEmitter } from "../events.ts";const { kMaxEventTargetListeners, kMaxEventTargetListenersWarned,} = EventEmitter;
const kEvents = Symbol("kEvents");const kIsBeingDispatched = Symbol("kIsBeingDispatched");const kStop = Symbol("kStop");const kTarget = Symbol("kTarget");const kHandlers = Symbol("khandlers");const kWeakHandler = Symbol("kWeak");
const kHybridDispatch = Symbol.for("nodejs.internal.kHybridDispatch");const kCreateEvent = Symbol("kCreateEvent");const kNewListener = Symbol("kNewListener");const kRemoveListener = Symbol("kRemoveListener");const kIsNodeStyleListener = Symbol("kIsNodeStyleListener");const kTrustEvent = Symbol("kTrustEvent");
const kType = Symbol("type");const kDefaultPrevented = Symbol("defaultPrevented");const kCancelable = Symbol("cancelable");const kTimestamp = Symbol("timestamp");const kBubbles = Symbol("bubbles");const kComposed = Symbol("composed");const kPropagationStopped = Symbol("propagationStopped");
function isEvent(value) { return typeof value?.[kType] === "string";}
class Event extends globalThis.Event { /** * @param {string} type * @param {{ * bubbles?: boolean, * cancelable?: boolean, * composed?: boolean, * }} [options] */ constructor(type, options = null) { super(type, options); if (arguments.length === 0) { throw new ERR_MISSING_ARGS("type"); } validateObject(options, "options", { allowArray: true, allowFunction: true, nullable: true, }); const { cancelable, bubbles, composed } = { ...options }; this[kCancelable] = !!cancelable; this[kBubbles] = !!bubbles; this[kComposed] = !!composed; this[kType] = `${type}`; this[kDefaultPrevented] = false; this[kTimestamp] = performance.now(); this[kPropagationStopped] = false; this[kTarget] = null; this[kIsBeingDispatched] = false; }
[customInspectSymbol](depth, options) { if (!isEvent(this)) { throw new ERR_INVALID_THIS("Event"); } const name = this.constructor.name; if (depth < 0) { return name; }
const opts = Object.assign({}, options, { depth: NumberIsInteger(options.depth) ? options.depth - 1 : options.depth, });
return `${name} ${ inspect({ type: this[kType], defaultPrevented: this[kDefaultPrevented], cancelable: this[kCancelable], timeStamp: this[kTimestamp], }, opts) }`; }
stopImmediatePropagation() { if (!isEvent(this)) { throw new ERR_INVALID_THIS("Event"); } this[kStop] = true; }
preventDefault() { if (!isEvent(this)) { throw new ERR_INVALID_THIS("Event"); } this[kDefaultPrevented] = true; }
/** * @type {EventTarget} */ get target() { if (!isEvent(this)) { throw new ERR_INVALID_THIS("Event"); } return this[kTarget]; }
/** * @type {EventTarget} */ get currentTarget() { if (!isEvent(this)) { throw new ERR_INVALID_THIS("Event"); } return this[kTarget]; }
/** * @type {EventTarget} */ get srcElement() { if (!isEvent(this)) { throw new ERR_INVALID_THIS("Event"); } return this[kTarget]; }
/** * @type {string} */ get type() { if (!isEvent(this)) { throw new ERR_INVALID_THIS("Event"); } return this[kType]; }
/** * @type {boolean} */ get cancelable() { if (!isEvent(this)) { throw new ERR_INVALID_THIS("Event"); } return this[kCancelable]; }
/** * @type {boolean} */ get defaultPrevented() { if (!isEvent(this)) { throw new ERR_INVALID_THIS("Event"); } return this[kCancelable] && this[kDefaultPrevented]; }
/** * @type {number} */ get timeStamp() { if (!isEvent(this)) { throw new ERR_INVALID_THIS("Event"); } return this[kTimestamp]; }
// The following are non-op and unused properties/methods from Web API Event. // These are not supported in Node.js and are provided purely for // API completeness. /** * @returns {EventTarget[]} */ composedPath() { if (!isEvent(this)) { throw new ERR_INVALID_THIS("Event"); } return this[kIsBeingDispatched] ? [this[kTarget]] : []; }
/** * @type {boolean} */ get returnValue() { if (!isEvent(this)) { throw new ERR_INVALID_THIS("Event"); } return !this.defaultPrevented; }
/** * @type {boolean} */ get bubbles() { if (!isEvent(this)) { throw new ERR_INVALID_THIS("Event"); } return this[kBubbles]; }
/** * @type {boolean} */ get composed() { if (!isEvent(this)) { throw new ERR_INVALID_THIS("Event"); } return this[kComposed]; }
/** * @type {number} */ get eventPhase() { if (!isEvent(this)) { throw new ERR_INVALID_THIS("Event"); } return this[kIsBeingDispatched] ? Event.AT_TARGET : Event.NONE; }
/** * @type {boolean} */ get cancelBubble() { if (!isEvent(this)) { throw new ERR_INVALID_THIS("Event"); } return this[kPropagationStopped]; }
/** * @type {boolean} */ set cancelBubble(value) { if (!isEvent(this)) { throw new ERR_INVALID_THIS("Event"); } if (value) { this.stopPropagation(); } }
stopPropagation() { if (!isEvent(this)) { throw new ERR_INVALID_THIS("Event"); } this[kPropagationStopped] = true; }
static NONE = 0; static CAPTURING_PHASE = 1; static AT_TARGET = 2; static BUBBLING_PHASE = 3;}
Object.defineProperties( Event.prototype, { [Symbol.toStringTag]: { writable: true, enumerable: false, configurable: true, value: "Event", }, stopImmediatePropagation: kEnumerableProperty, preventDefault: kEnumerableProperty, target: kEnumerableProperty, currentTarget: kEnumerableProperty, srcElement: kEnumerableProperty, type: kEnumerableProperty, cancelable: kEnumerableProperty, defaultPrevented: kEnumerableProperty, timeStamp: kEnumerableProperty, composedPath: kEnumerableProperty, returnValue: kEnumerableProperty, bubbles: kEnumerableProperty, composed: kEnumerableProperty, eventPhase: kEnumerableProperty, cancelBubble: kEnumerableProperty, stopPropagation: kEnumerableProperty, },);
class NodeCustomEvent extends Event { constructor(type, options) { super(type, options); if (options?.detail) { this.detail = options.detail; } }}
// Weak listener cleanup// This has to be lazy for snapshots to worklet weakListenersState = null;// The resource needs to retain the callback so that it doesn't// get garbage collected now that it's weak.let objectToWeakListenerMap = null;function weakListeners() { weakListenersState ??= new FinalizationRegistry( (listener) => listener.remove(), ); objectToWeakListenerMap ??= new WeakMap(); return { registry: weakListenersState, map: objectToWeakListenerMap };}
// The listeners for an EventTarget are maintained as a linked list.// Unfortunately, the way EventTarget is defined, listeners are accounted// using the tuple [handler,capture], and even if we don't actually make// use of capture or bubbling, in order to be spec compliant we have to// take on the additional complexity of supporting it. Fortunately, using// the linked list makes dispatching faster, even if adding/removing is// slower.class Listener { constructor( previous, listener, once, capture, passive, isNodeStyleListener, weak, ) { this.next = undefined; if (previous !== undefined) { previous.next = this; } this.previous = previous; this.listener = listener; // TODO(benjamingr) these 4 can be 'flags' to save 3 slots this.once = once; this.capture = capture; this.passive = passive; this.isNodeStyleListener = isNodeStyleListener; this.removed = false; this.weak = Boolean(weak); // Don't retain the object
if (this.weak) { this.callback = new WeakRef(listener); weakListeners().registry.register(listener, this, this); // Make the retainer retain the listener in a WeakMap weakListeners().map.set(weak, listener); this.listener = this.callback; } else if (typeof listener === "function") { this.callback = listener; this.listener = listener; } else { this.callback = Function.prototype.bind.call( listener.handleEvent, listener, ); this.listener = listener; } }
same(listener, capture) { const myListener = this.weak ? this.listener.deref() : this.listener; return myListener === listener && this.capture === capture; }
remove() { if (this.previous !== undefined) { this.previous.next = this.next; } if (this.next !== undefined) { this.next.previous = this.previous; } this.removed = true; if (this.weak) { weakListeners().registry.unregister(this); } }}
function initEventTarget(self) { self[kEvents] = new Map(); self[kMaxEventTargetListeners] = EventEmitter.defaultMaxListeners; self[kMaxEventTargetListenersWarned] = false;}
class EventTarget extends globalThis.EventTarget { // Used in checking whether an object is an EventTarget. This is a well-known // symbol as EventTarget may be used cross-realm. // Ref: https://github.com/nodejs/node/pull/33661 static [kIsEventTarget] = true;
constructor() { super(); initEventTarget(this); }
[kNewListener](size, type, _listener, _once, _capture, _passive, _weak) { if ( this[kMaxEventTargetListeners] > 0 && size > this[kMaxEventTargetListeners] && !this[kMaxEventTargetListenersWarned] ) { this[kMaxEventTargetListenersWarned] = true; // No error code for this since it is a Warning // eslint-disable-next-line no-restricted-syntax const w = new Error( "Possible EventTarget memory leak detected. " + `${size} ${type} listeners ` + `added to ${inspect(this, { depth: -1 })}. Use ` + "events.setMaxListeners() to increase limit", ); w.name = "MaxListenersExceededWarning"; w.target = this; w.type = type; w.count = size; emitWarning(w); } } [kRemoveListener](_size, _type, _listener, _capture) {}
/** * @callback EventTargetCallback * @param {Event} event */
/** * @typedef {{ handleEvent: EventTargetCallback }} EventListener */
/** * @param {string} type * @param {EventTargetCallback|EventListener} listener * @param {{ * capture?: boolean, * once?: boolean, * passive?: boolean, * signal?: AbortSignal * }} [options] */ addEventListener(type, listener, options = {}) { if (!isEventTarget(this)) { throw new ERR_INVALID_THIS("EventTarget"); } if (arguments.length < 2) { throw new ERR_MISSING_ARGS("type", "listener"); }
// We validateOptions before the shouldAddListeners check because the spec // requires us to hit getters. const { once, capture, passive, signal, isNodeStyleListener, weak, } = validateEventListenerOptions(options);
if (!shouldAddListener(listener)) { // The DOM silently allows passing undefined as a second argument // No error code for this since it is a Warning // eslint-disable-next-line no-restricted-syntax const w = new Error( `addEventListener called with ${listener}` + " which has no effect.", ); w.name = "AddEventListenerArgumentTypeWarning"; w.target = this; w.type = type; emitWarning(w); return; } type = String(type);
if (signal) { if (signal.aborted) { return; } // TODO(benjamingr) make this weak somehow? ideally the signal would // not prevent the event target from GC. signal.addEventListener("abort", () => { this.removeEventListener(type, listener, options); }, { once: true, [kWeakHandler]: this }); }
let root = this[kEvents].get(type);
if (root === undefined) { root = { size: 1, next: undefined }; // This is the first handler in our linked list. new Listener( root, listener, once, capture, passive, isNodeStyleListener, weak, ); this[kNewListener]( root.size, type, listener, once, capture, passive, weak, ); this[kEvents].set(type, root); return; }
let handler = root.next; let previous = root;
// We have to walk the linked list to see if we have a match while (handler !== undefined && !handler.same(listener, capture)) { previous = handler; handler = handler.next; }
if (handler !== undefined) { // Duplicate! Ignore return; }
new Listener( previous, listener, once, capture, passive, isNodeStyleListener, weak, ); root.size++; this[kNewListener](root.size, type, listener, once, capture, passive, weak); }
/** * @param {string} type * @param {EventTargetCallback|EventListener} listener * @param {{ * capture?: boolean, * }} [options] */ removeEventListener(type, listener, options = {}) { if (!isEventTarget(this)) { throw new ERR_INVALID_THIS("EventTarget"); } if (!shouldAddListener(listener)) { return; }
type = String(type); const capture = options?.capture === true;
const root = this[kEvents].get(type); if (root === undefined || root.next === undefined) { return; }
let handler = root.next; while (handler !== undefined) { if (handler.same(listener, capture)) { handler.remove(); root.size--; if (root.size === 0) { this[kEvents].delete(type); } this[kRemoveListener](root.size, type, listener, capture); break; } handler = handler.next; } }
/** * @param {Event} event */ dispatchEvent(event) { if (!isEventTarget(this)) { throw new ERR_INVALID_THIS("EventTarget"); }
if (!(event instanceof globalThis.Event)) { throw new ERR_INVALID_ARG_TYPE("event", "Event", event); }
if (event[kIsBeingDispatched]) { throw new ERR_EVENT_RECURSION(event.type); }
this[kHybridDispatch](event, event.type, event);
return event.defaultPrevented !== true; }
[kHybridDispatch](nodeValue, type, event) { const createEvent = () => { if (event === undefined) { event = this[kCreateEvent](nodeValue, type); event[kTarget] = this; event[kIsBeingDispatched] = true; } return event; }; if (event !== undefined) { event[kTarget] = this; event[kIsBeingDispatched] = true; }
const root = this[kEvents].get(type); if (root === undefined || root.next === undefined) { if (event !== undefined) { event[kIsBeingDispatched] = false; } return true; }
let handler = root.next; let next;
while ( handler !== undefined && (handler.passive || event?.[kStop] !== true) ) { // Cache the next item in case this iteration removes the current one next = handler.next;
if (handler.removed) { // Deal with the case an event is removed while event handlers are // Being processed (removeEventListener called from a listener) handler = next; continue; } if (handler.once) { handler.remove(); root.size--; const { listener, capture } = handler; this[kRemoveListener](root.size, type, listener, capture); }
try { let arg; if (handler.isNodeStyleListener) { arg = nodeValue; } else { arg = createEvent(); } const callback = handler.weak ? handler.callback.deref() : handler.callback; let result; if (callback) { result = callback.call(this, arg); if (!handler.isNodeStyleListener) { arg[kIsBeingDispatched] = false; } } if (result !== undefined && result !== null) { addCatch(result); } } catch (err) { emitUncaughtException(err); }
handler = next; }
if (event !== undefined) { event[kIsBeingDispatched] = false; } }
[kCreateEvent](nodeValue, type) { return new NodeCustomEvent(type, { detail: nodeValue }); } [customInspectSymbol](depth, options) { if (!isEventTarget(this)) { throw new ERR_INVALID_THIS("EventTarget"); } const name = this.constructor.name; if (depth < 0) { return name; }
const opts = ObjectAssign({}, options, { depth: Number.isInteger(options.depth) ? options.depth - 1 : options.depth, });
return `${name} ${inspect({}, opts)}`; }}
Object.defineProperties(EventTarget.prototype, { addEventListener: kEnumerableProperty, removeEventListener: kEnumerableProperty, dispatchEvent: kEnumerableProperty, [Symbol.toStringTag]: { writable: true, enumerable: false, configurable: true, value: "EventTarget", },});
function initNodeEventTarget(self) { initEventTarget(self);}
class NodeEventTarget extends EventTarget { static [kIsNodeEventTarget] = true; static defaultMaxListeners = 10;
constructor() { super(); initNodeEventTarget(this); }
/** * @param {number} n */ setMaxListeners(n) { if (!isNodeEventTarget(this)) { throw new ERR_INVALID_THIS("NodeEventTarget"); } EventEmitter.setMaxListeners(n, this); }
/** * @returns {number} */ getMaxListeners() { if (!isNodeEventTarget(this)) { throw new ERR_INVALID_THIS("NodeEventTarget"); } return this[kMaxEventTargetListeners]; }
/** * @returns {string[]} */ eventNames() { if (!isNodeEventTarget(this)) { throw new ERR_INVALID_THIS("NodeEventTarget"); } return Array.from(this[kEvents].keys()); }
/** * @param {string} [type] * @returns {number} */ listenerCount(type) { if (!isNodeEventTarget(this)) { throw new ERR_INVALID_THIS("NodeEventTarget"); } const root = this[kEvents].get(String(type)); return root !== undefined ? root.size : 0; }
/** * @param {string} type * @param {EventTargetCallback|EventListener} listener * @param {{ * capture?: boolean, * }} [options] * @returns {NodeEventTarget} */ off(type, listener, options) { if (!isNodeEventTarget(this)) { throw new ERR_INVALID_THIS("NodeEventTarget"); } this.removeEventListener(type, listener, options); return this; }
/** * @param {string} type * @param {EventTargetCallback|EventListener} listener * @param {{ * capture?: boolean, * }} [options] * @returns {NodeEventTarget} */ removeListener(type, listener, options) { if (!isNodeEventTarget(this)) { throw new ERR_INVALID_THIS("NodeEventTarget"); } this.removeEventListener(type, listener, options); return this; }
/** * @param {string} type * @param {EventTargetCallback|EventListener} listener * @returns {NodeEventTarget} */ on(type, listener) { if (!isNodeEventTarget(this)) { throw new ERR_INVALID_THIS("NodeEventTarget"); } this.addEventListener(type, listener, { [kIsNodeStyleListener]: true }); return this; }
/** * @param {string} type * @param {EventTargetCallback|EventListener} listener * @returns {NodeEventTarget} */ addListener(type, listener) { if (!isNodeEventTarget(this)) { throw new ERR_INVALID_THIS("NodeEventTarget"); } this.addEventListener(type, listener, { [kIsNodeStyleListener]: true }); return this; }
/** * @param {string} type * @param {any} arg * @returns {boolean} */ emit(type, arg) { if (!isNodeEventTarget(this)) { throw new ERR_INVALID_THIS("NodeEventTarget"); } validateString(type, "type"); const hadListeners = this.listenerCount(type) > 0; this[kHybridDispatch](arg, type); return hadListeners; }
/** * @param {string} type * @param {EventTargetCallback|EventListener} listener * @returns {NodeEventTarget} */ once(type, listener) { if (!isNodeEventTarget(this)) { throw new ERR_INVALID_THIS("NodeEventTarget"); } this.addEventListener(type, listener, { once: true, [kIsNodeStyleListener]: true, }); return this; }
/** * @param {string} type * @returns {NodeEventTarget} */ removeAllListeners(type) { if (!isNodeEventTarget(this)) { throw new ERR_INVALID_THIS("NodeEventTarget"); } if (type !== undefined) { this[kEvents].delete(String(type)); } else { this[kEvents].clear(); }
return this; }}
Object.defineProperties(NodeEventTarget.prototype, { setMaxListeners: kEnumerableProperty, getMaxListeners: kEnumerableProperty, eventNames: kEnumerableProperty, listenerCount: kEnumerableProperty, off: kEnumerableProperty, removeListener: kEnumerableProperty, on: kEnumerableProperty, addListener: kEnumerableProperty, once: kEnumerableProperty, emit: kEnumerableProperty, removeAllListeners: kEnumerableProperty,});
// EventTarget API
function shouldAddListener(listener) { if ( typeof listener === "function" || typeof listener?.handleEvent === "function" ) { return true; }
if (listener == null) { return false; }
throw new ERR_INVALID_ARG_TYPE("listener", "EventListener", listener);}
function validateEventListenerOptions(options) { if (typeof options === "boolean") { return { capture: options }; }
if (options === null) { return {}; } validateObject(options, "options", { allowArray: true, allowFunction: true, }); return { once: Boolean(options.once), capture: Boolean(options.capture), passive: Boolean(options.passive), signal: options.signal, weak: options[kWeakHandler], isNodeStyleListener: Boolean(options[kIsNodeStyleListener]), };}
function isEventTarget(obj) { return obj instanceof globalThis.EventTarget;}
function isNodeEventTarget(obj) { return obj?.constructor?.[kIsNodeEventTarget];}
function addCatch(promise) { const then = promise.then; if (typeof then === "function") { then.call(promise, undefined, function (err) { // The callback is called with nextTick to avoid a follow-up // rejection from this promise. emitUncaughtException(err); }); }}
function emitUncaughtException(err) { nextTick(() => { throw err; });}
function makeEventHandler(handler) { // Event handlers are dispatched in the order they were first set // See https://github.com/nodejs/node/pull/35949#issuecomment-722496598 function eventHandler(...args) { if (typeof eventHandler.handler !== "function") { return; } return Reflect.apply(eventHandler.handler, this, args); } eventHandler.handler = handler; return eventHandler;}
function defineEventHandler(emitter, name) { // 8.1.5.1 Event handlers - basically `on[eventName]` attributes Object.defineProperty(emitter, `on${name}`, { get() { return this[kHandlers]?.get(name)?.handler ?? null; }, set(value) { if (!this[kHandlers]) { this[kHandlers] = new Map(); } let wrappedHandler = this[kHandlers]?.get(name); if (wrappedHandler) { if (typeof wrappedHandler.handler === "function") { this[kEvents].get(name).size--; const size = this[kEvents].get(name).size; this[kRemoveListener](size, name, wrappedHandler.handler, false); } wrappedHandler.handler = value; if (typeof wrappedHandler.handler === "function") { this[kEvents].get(name).size++; const size = this[kEvents].get(name).size; this[kNewListener](size, name, value, false, false, false, false); } } else { wrappedHandler = makeEventHandler(value); this.addEventListener(name, wrappedHandler); } this[kHandlers].set(name, wrappedHandler); }, configurable: true, enumerable: true, });}
const EventEmitterMixin = (Superclass) => { class MixedEventEmitter extends Superclass { constructor(...args) { super(...args); EventEmitter.call(this); } } const protoProps = Object.getOwnPropertyDescriptors(EventEmitter.prototype); delete protoProps.constructor; Object.defineProperties(MixedEventEmitter.prototype, protoProps); return MixedEventEmitter;};
export { defineEventHandler, Event, EventEmitterMixin, EventTarget, initEventTarget, initNodeEventTarget, isEventTarget, kCreateEvent, kEvents, kNewListener, kRemoveListener, kTrustEvent, kWeakHandler, NodeEventTarget,};
export default { Event, EventEmitterMixin, EventTarget, NodeEventTarget, defineEventHandler, initEventTarget, initNodeEventTarget, kCreateEvent, kNewListener, kTrustEvent, kRemoveListener, kEvents, kWeakHandler, isEventTarget,};