diff --git a/dist/Eventful.d.ts b/dist/Eventful.d.ts index cb81ced..d63503e 100644 --- a/dist/Eventful.d.ts +++ b/dist/Eventful.d.ts @@ -1,4 +1,5 @@ import type { Constructor } from 'lowclass/dist/Constructor.js'; +declare const isEventful: unique symbol; /** * @mixin * @class Eventful - An instance of Eventful emits events that code can @@ -33,6 +34,7 @@ import type { Constructor } from 'lowclass/dist/Constructor.js'; */ export declare function Eventful(Base?: T): { new (...a: any[]): { + "__#1@#eventMap": Map> | null; /** * @method on - Register a `callback` to be executed any * time an event with name `eventName` is triggered by an instance of @@ -72,23 +74,8 @@ export declare function Eventful(Base?: T): { * @param {data} any - The data that is passed to each callback subscribed to the event. */ emit(eventName: string, data?: any): void; - "__#1@#eventMap": Map> | null; + [isEventful]: boolean; }; } & T; -/** - * @decorator - * @function emits - This is a decorator that when used on a property in a - * class definition, causes setting of that property to emit the specified - * event, with the event payload being the property value. This decorator must - * be used in a class that extends from Eventful, otherwise an error is thrown. - * - * @example - * class Foo { - * @emits('propchange') foo = 123 - * } - * const f = new Foo - * f.on('propchange', value => console.log('value: ', value)) - * f.foo = 456 // logs "value: 456" - */ -export declare function emits(eventName: string): any; +export {}; //# sourceMappingURL=Eventful.d.ts.map \ No newline at end of file diff --git a/dist/Eventful.d.ts.map b/dist/Eventful.d.ts.map index 46aaf48..d834403 100644 --- a/dist/Eventful.d.ts.map +++ b/dist/Eventful.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"Eventful.d.ts","sourceRoot":"","sources":["../src/Eventful.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,8BAA8B,CAAA;AAY7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,WAAW,EAAE,IAAI,GAAE,CAAiB;;QAKrE;;;;;;;;;;;WAWG;sBACW,MAAM,YAAY,QAAQ,YAAY,GAAG;QAevD;;;;;;;;WAQG;uBACY,MAAM,aAAa,QAAQ,YAAY,GAAG;QAoBzD;;;;;;;;;;;;;;WAcG;wBACa,MAAM,SAAS,GAAG;0BAqBvB,IAAI,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI;;MAMtD;AAYD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,GAAG,CAI5C"} \ No newline at end of file +{"version":3,"file":"Eventful.d.ts","sourceRoot":"","sources":["../src/Eventful.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,8BAA8B,CAAA;AAI7D,QAAA,MAAM,UAAU,eAAuB,CAAA;AAEvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,WAAW,EAAE,IAAI,GAAE,CAAiB;;0BAO1D,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI;QAEnD;;;;;;;;;;;WAWG;sBACW,MAAM,YAAY,QAAQ,YAAY,GAAG;QAevD;;;;;;;;WAQG;uBACY,MAAM,aAAa,QAAQ,YAAY,GAAG;QAoBzD;;;;;;;;;;;;;;WAcG;wBACa,MAAM,SAAS,GAAG;;;MAYnC"} \ No newline at end of file diff --git a/dist/Eventful.js b/dist/Eventful.js index ec7b7ca..a979dd3 100644 --- a/dist/Eventful.js +++ b/dist/Eventful.js @@ -1,10 +1,5 @@ -// TODO, make strongly typed event args. Combine with stuff in Events.ts (or similar). -// TODO, Make sure emit will not attempt to call event handlers removed -// during emit (in place modification of listeners array during emit iteration -// will try to access undefined after the end of the array). Possibly use -// for..of with a Set instead, otherwise modify the iteration index manually. -// TODO, an option to defer events, and batch them (so that 3 of the -// same event and payload triggers only one event instead of three) +// TODO, come up with a pattern for event handler args to be typed. +const isEventful = Symbol('isEventful'); /** * @mixin * @class Eventful - An instance of Eventful emits events that code can @@ -38,9 +33,12 @@ * ``` */ export function Eventful(Base = Object) { - class Eventful extends Base { - // @ts-ignore to avoid "is using private name" errors in consumer code. - [isEventful] = isEventful; + return class Eventful extends Base { + [isEventful] = true; + // We're using Set here so that iteration of event handlers is + // impervious to items being deleted during iteration (i.e. during + // emit). + #eventMap = null; /** * @method on - Register a `callback` to be executed any * time an event with name `eventName` is triggered by an instance of @@ -62,8 +60,8 @@ export function Eventful(Base = Object) { eventMap = this.#eventMap = new Map(); let callbacks = eventMap.get(eventName); if (!callbacks) - eventMap.set(eventName, (callbacks = [])); - callbacks.push([callback, context]); + eventMap.set(eventName, (callbacks = new Set())); + callbacks.add([callback, context]); } /** * @method off - Stop a `callback` from being fired for event named `eventName`. If @@ -81,11 +79,11 @@ export function Eventful(Base = Object) { const callbacks = eventMap.get(eventName); if (!callbacks) return; - const index = callbacks.findIndex(tuple => tuple[0] === callback && tuple[1] === context); - if (index === -1) + const tuple = Array.from(callbacks).find(tuple => tuple[0] === callback && tuple[1] === context); + if (!tuple) return; - callbacks.splice(index, 1); - if (callbacks.length === 0) + callbacks.delete(tuple); + if (callbacks.size === 0) eventMap.delete(eventName); if (eventMap.size === 0) this.#eventMap = null; @@ -112,147 +110,19 @@ export function Eventful(Base = Object) { const callbacks = eventMap.get(eventName); if (!callbacks) return; - let tuple; - let callback; - let context; - for (let i = 0, len = callbacks.length; i < len; i += 1) { - tuple = callbacks[i]; - callback = tuple[0]; - context = tuple[1]; + for (const [callback, context] of new Set(callbacks)) callback.call(context, data); - } } - #eventMap = null; - } - Eventful.prototype[isEventful] = isEventful; - return Eventful; + }; } -const isEventful = Symbol('isEventful'); +// Use defineProperty instead of assignment because [Symbol.hasInstance] is writable:false Object.defineProperty(Eventful, Symbol.hasInstance, { - value(obj) { - if (!obj) + value(value) { + if (!value) return false; - if (obj[isEventful]) + if (value[isEventful]) return true; return false; }, }); -/** - * @decorator - * @function emits - This is a decorator that when used on a property in a - * class definition, causes setting of that property to emit the specified - * event, with the event payload being the property value. This decorator must - * be used in a class that extends from Eventful, otherwise an error is thrown. - * - * @example - * class Foo { - * @emits('propchange') foo = 123 - * } - * const f = new Foo - * f.on('propchange', value => console.log('value: ', value)) - * f.foo = 456 // logs "value: 456" - */ -export function emits(eventName) { - return (prototype, propName, descriptor) => { - return _emits(prototype, propName, descriptor ?? undefined, eventName); - }; -} -function _emits(prototype, propName, descriptor, eventName) { - if (!(prototype instanceof Eventful)) - throw new TypeError('The @emits decorator is only for use on properties of classes that extend from Eventful.'); - const vName = Symbol('@emits: ' + propName); - // property decorators are not passed a descriptor (unlike decorators on accessors or methods) - let calledAsPropertyDecorator = false; - if (!descriptor) { - calledAsPropertyDecorator = true; - descriptor = Object.getOwnPropertyDescriptor(prototype, propName); - } - let hasOriginalAccessor = false; - let originalGet; - let originalSet; - let initialValue; - let writable; - if (descriptor) { - if (descriptor.get || descriptor.set) { - hasOriginalAccessor = true; - originalGet = descriptor.get; - originalSet = descriptor.set; - // reactivity requires both - if (!originalSet) { - console.warn('The `@emits` decorator was used on an accessor named "' + - propName + - '" which did not have a setter. This means an event will never be emitted because the value can not be set. In this case the decorator doesn\'t do anything.'); - return; - } - delete descriptor.get; - delete descriptor.set; - } - else { - initialValue = descriptor.value; - writable = descriptor.writable; - // if it isn't writable, we don't need to make a reactive variable because - // the value won't change - if (!writable) { - console.warn('The `@emits` decorator was used on a property named "' + - propName + - '" that is not writable. An event can not be emitted because the property can not be modified. In this case the decorator does not do anything.'); - return; - } - delete descriptor.value; - delete descriptor.writable; - } - } - let initialValueIsSet = false; - function emitEvent() { - this.emit(eventName, propName); - } - descriptor = { - ...descriptor, - configurable: true, - ...(hasOriginalAccessor - ? originalGet - ? { - get() { - return originalGet.call(this); - }, - } - : {} - : { - get() { - if (!initialValueIsSet) { - initialValueIsSet = true; - return (this[vName] = initialValue); - } - return this[vName]; - }, - }), - ...(hasOriginalAccessor - ? { - set(newValue) { - originalSet.call(this, newValue); - // TODO should we defer the event, or not? Perhaps provide an option, and defer by default. - Promise.resolve().then(emitEvent.bind(this)); - // emitEvent.call(this as Eventful) - }, - } - : { - set(newValue) { - if (!initialValueIsSet) - initialValueIsSet = true; - this[vName] = newValue; - Promise.resolve().then(emitEvent.bind(this)); - }, - }), - }; - // If a decorator is called on a property, then returning a descriptor does - // nothing, so we need to set the descriptor manually. - if (calledAsPropertyDecorator) - Object.defineProperty(prototype, propName, descriptor); - // If a decorator is called on an accessor or method, then we must return a - // descriptor in order to modify it, and doing it manually won't work. - else - return descriptor; - // Weird, huh? - // This will all change with updates to the ES decorators proposal, https://github.com/tc39/proposal-decorators -} //# sourceMappingURL=Eventful.js.map \ No newline at end of file diff --git a/dist/Eventful.js.map b/dist/Eventful.js.map index f23142b..07b86da 100644 --- a/dist/Eventful.js.map +++ b/dist/Eventful.js.map @@ -1 +1 @@ -{"version":3,"file":"Eventful.js","sourceRoot":"","sources":["../src/Eventful.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"Eventful.js","sourceRoot":"","sources":["../src/Eventful.ts"],"names":[],"mappings":"AAEA,mEAAmE;AAEnE,MAAM,UAAU,GAAG,MAAM,CAAC,YAAY,CAAC,CAAA;AAEvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,UAAU,QAAQ,CAAwB,OAAU,MAAa;IACtE,OAAO,MAAM,QAAS,SAAQ,IAAI;QACjC,CAAC,UAAU,CAAC,GAAG,IAAI,CAAA;QAEnB,8DAA8D;QAC9D,kEAAkE;QAClE,SAAS;QACT,SAAS,GAA6C,IAAI,CAAA;QAE1D;;;;;;;;;;;WAWG;QACH,EAAE,CAAC,SAAiB,EAAE,QAAkB,EAAE,OAAa;YACtD,IAAI,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAA;YAE7B,cAAc;YACd,IAAI,OAAO,QAAQ,KAAK,UAAU;gBAAE,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAA;YAE/G,IAAI,CAAC,QAAQ;gBAAE,QAAQ,GAAG,IAAI,CAAC,SAAS,GAAG,IAAI,GAAG,EAAE,CAAA;YAEpD,IAAI,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;YAEvC,IAAI,CAAC,SAAS;gBAAE,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,SAAS,GAAG,IAAI,GAAG,EAAE,CAAC,CAAC,CAAA;YAEhE,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAA;QACnC,CAAC;QAED;;;;;;;;WAQG;QACH,GAAG,CAAC,SAAiB,EAAE,QAAmB,EAAE,OAAa;YACxD,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAA;YAE/B,IAAI,CAAC,QAAQ;gBAAE,OAAM;YAErB,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;YAEzC,IAAI,CAAC,SAAS;gBAAE,OAAM;YAEtB,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAA;YAEhG,IAAI,CAAC,KAAK;gBAAE,OAAM;YAElB,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YAEvB,IAAI,SAAS,CAAC,IAAI,KAAK,CAAC;gBAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;YAEpD,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC;gBAAE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAA;QAC/C,CAAC;QAED;;;;;;;;;;;;;;WAcG;QACH,IAAI,CAAC,SAAiB,EAAE,IAAU;YACjC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAA;YAE/B,IAAI,CAAC,QAAQ;gBAAE,OAAM;YAErB,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;YAEzC,IAAI,CAAC,SAAS;gBAAE,OAAM;YAEtB,KAAK,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,IAAI,GAAG,CAAC,SAAS,CAAC;gBAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;QACnF,CAAC;KACD,CAAA;AACF,CAAC;AAED,0FAA0F;AAC1F,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,WAAW,EAAE;IACnD,KAAK,CAAC,KAAU;QACf,IAAI,CAAC,KAAK;YAAE,OAAO,KAAK,CAAA;QACxB,IAAI,KAAK,CAAC,UAAU,CAAC;YAAE,OAAO,IAAI,CAAA;QAClC,OAAO,KAAK,CAAA;IACb,CAAC;CACD,CAAC,CAAA"} \ No newline at end of file diff --git a/dist/Eventful.test.js.map b/dist/Eventful.test.js.map index 3f6c642..de5dc95 100644 --- a/dist/Eventful.test.js.map +++ b/dist/Eventful.test.js.map @@ -1 +1 @@ -{"version":3,"file":"Eventful.test.js","sourceRoot":"","sources":["../src/Eventful.test.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"Eventful.test.js","sourceRoot":"","sources":["../src/Eventful.test.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/emits.d.ts b/dist/emits.d.ts new file mode 100644 index 0000000..a6fd983 --- /dev/null +++ b/dist/emits.d.ts @@ -0,0 +1,17 @@ +/** + * @decorator + * @function emits - This is a decorator that when used on a property in a + * class definition, causes setting of that property to emit the specified + * event, with the event payload being the property value. This decorator must + * be used in a class that extends from Eventful, otherwise an error is thrown. + * + * @example + * class Foo { + * @emits('propchange') foo = 123 + * } + * const f = new Foo + * f.on('propchange', value => console.log('value: ', value)) + * f.foo = 456 // logs "value: 456" + */ +export declare function emits(eventName: string): any; +//# sourceMappingURL=emits.d.ts.map \ No newline at end of file diff --git a/dist/emits.d.ts.map b/dist/emits.d.ts.map new file mode 100644 index 0000000..ab8393f --- /dev/null +++ b/dist/emits.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"emits.d.ts","sourceRoot":"","sources":["../src/emits.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,GAAG,CAI5C"} \ No newline at end of file diff --git a/dist/emits.js b/dist/emits.js new file mode 100644 index 0000000..d045249 --- /dev/null +++ b/dist/emits.js @@ -0,0 +1,120 @@ +import { Eventful } from './Eventful.js'; +/** + * @decorator + * @function emits - This is a decorator that when used on a property in a + * class definition, causes setting of that property to emit the specified + * event, with the event payload being the property value. This decorator must + * be used in a class that extends from Eventful, otherwise an error is thrown. + * + * @example + * class Foo { + * @emits('propchange') foo = 123 + * } + * const f = new Foo + * f.on('propchange', value => console.log('value: ', value)) + * f.foo = 456 // logs "value: 456" + */ +export function emits(eventName) { + return (prototype, propName, descriptor) => { + return _emits(prototype, propName, descriptor ?? undefined, eventName); + }; +} +function _emits(prototype, propName, descriptor, eventName) { + if (!(prototype instanceof Eventful)) + throw new TypeError('The @emits decorator is only for use on properties of classes that extend from Eventful.'); + const vName = Symbol('@emits: ' + propName); + // property decorators are not passed a descriptor (unlike decorators on accessors or methods) + let calledAsPropertyDecorator = false; + if (!descriptor) { + calledAsPropertyDecorator = true; + descriptor = Object.getOwnPropertyDescriptor(prototype, propName); + } + let hasOriginalAccessor = false; + let originalGet; + let originalSet; + let initialValue; + let writable; + if (descriptor) { + if (descriptor.get || descriptor.set) { + hasOriginalAccessor = true; + originalGet = descriptor.get; + originalSet = descriptor.set; + // reactivity requires both + if (!originalSet) { + console.warn('The `@emits` decorator was used on an accessor named "' + + propName + + '" which did not have a setter. This means an event will never be emitted because the value can not be set. In this case the decorator doesn\'t do anything.'); + return; + } + delete descriptor.get; + delete descriptor.set; + } + else { + initialValue = descriptor.value; + writable = descriptor.writable; + // if it isn't writable, we don't need to make a reactive variable because + // the value won't change + if (!writable) { + console.warn('The `@emits` decorator was used on a property named "' + + propName + + '" that is not writable. An event can not be emitted because the property can not be modified. In this case the decorator does not do anything.'); + return; + } + delete descriptor.value; + delete descriptor.writable; + } + } + let initialValueIsSet = false; + function emitEvent() { + this.emit(eventName, propName); + } + descriptor = { + ...descriptor, + configurable: true, + ...(hasOriginalAccessor + ? originalGet + ? { + get() { + return originalGet.call(this); + }, + } + : {} + : { + get() { + if (!initialValueIsSet) { + initialValueIsSet = true; + return (this[vName] = initialValue); + } + return this[vName]; + }, + }), + ...(hasOriginalAccessor + ? { + set(newValue) { + originalSet.call(this, newValue); + // TODO should we defer the event, or not? Perhaps provide an option, and defer by default. + Promise.resolve().then(emitEvent.bind(this)); + // emitEvent.call(this as Eventful) + }, + } + : { + set(newValue) { + if (!initialValueIsSet) + initialValueIsSet = true; + this[vName] = newValue; + Promise.resolve().then(emitEvent.bind(this)); + }, + }), + }; + // If a decorator is called on a property, then returning a descriptor does + // nothing, so we need to set the descriptor manually. + if (calledAsPropertyDecorator) + Object.defineProperty(prototype, propName, descriptor); + // If a decorator is called on an accessor or method, then we must return a + // descriptor in order to modify it, and doing it manually won't work. + else + return descriptor; + // Weird, huh? + // This will all change with updates to the ES decorators proposal, https://github.com/tc39/proposal-decorators +} +//# sourceMappingURL=emits.js.map \ No newline at end of file diff --git a/dist/emits.js.map b/dist/emits.js.map new file mode 100644 index 0000000..3d9cdb9 --- /dev/null +++ b/dist/emits.js.map @@ -0,0 +1 @@ +{"version":3,"file":"emits.js","sourceRoot":"","sources":["../src/emits.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,eAAe,CAAA;AAEtC;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,KAAK,CAAC,SAAiB;IACtC,OAAO,CAAC,SAAc,EAAE,QAAgB,EAAE,UAA+B,EAAE,EAAE;QAC5E,OAAO,MAAM,CAAC,SAAS,EAAE,QAAQ,EAAE,UAAU,IAAI,SAAS,EAAE,SAAS,CAAC,CAAA;IACvE,CAAC,CAAA;AACF,CAAC;AAED,SAAS,MAAM,CAAC,SAAc,EAAE,QAAgB,EAAE,UAA0C,EAAE,SAAiB;IAC9G,IAAI,CAAC,CAAC,SAAS,YAAY,QAAQ,CAAC;QACnC,MAAM,IAAI,SAAS,CAAC,0FAA0F,CAAC,CAAA;IAEhH,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,GAAG,QAAQ,CAAC,CAAA;IAE3C,8FAA8F;IAC9F,IAAI,yBAAyB,GAAG,KAAK,CAAA;IAErC,IAAI,CAAC,UAAU,EAAE,CAAC;QACjB,yBAAyB,GAAG,IAAI,CAAA;QAChC,UAAU,GAAG,MAAM,CAAC,wBAAwB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;IAClE,CAAC;IAED,IAAI,mBAAmB,GAAG,KAAK,CAAA;IAC/B,IAAI,WAAoC,CAAA;IACxC,IAAI,WAA2C,CAAA;IAC/C,IAAI,YAAiB,CAAA;IACrB,IAAI,QAA6B,CAAA;IAEjC,IAAI,UAAU,EAAE,CAAC;QAChB,IAAI,UAAU,CAAC,GAAG,IAAI,UAAU,CAAC,GAAG,EAAE,CAAC;YACtC,mBAAmB,GAAG,IAAI,CAAA;YAC1B,WAAW,GAAG,UAAU,CAAC,GAAG,CAAA;YAC5B,WAAW,GAAG,UAAU,CAAC,GAAG,CAAA;YAE5B,2BAA2B;YAC3B,IAAI,CAAC,WAAW,EAAE,CAAC;gBAClB,OAAO,CAAC,IAAI,CACX,wDAAwD;oBACvD,QAAQ;oBACR,6JAA6J,CAC9J,CAAA;gBACD,OAAM;YACP,CAAC;YAED,OAAO,UAAU,CAAC,GAAG,CAAA;YACrB,OAAO,UAAU,CAAC,GAAG,CAAA;QACtB,CAAC;aAAM,CAAC;YACP,YAAY,GAAG,UAAU,CAAC,KAAK,CAAA;YAC/B,QAAQ,GAAG,UAAU,CAAC,QAAQ,CAAA;YAE9B,0EAA0E;YAC1E,yBAAyB;YACzB,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CACX,uDAAuD;oBACtD,QAAQ;oBACR,gJAAgJ,CACjJ,CAAA;gBACD,OAAM;YACP,CAAC;YAED,OAAO,UAAU,CAAC,KAAK,CAAA;YACvB,OAAO,UAAU,CAAC,QAAQ,CAAA;QAC3B,CAAC;IACF,CAAC;IAED,IAAI,iBAAiB,GAAG,KAAK,CAAA;IAC7B,SAAS,SAAS;QACjB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;IAC/B,CAAC;IAED,UAAU,GAAG;QACZ,GAAG,UAAU;QACb,YAAY,EAAE,IAAI;QAClB,GAAG,CAAC,mBAAmB;YACtB,CAAC,CAAC,WAAW;gBACZ,CAAC,CAAC;oBACA,GAAG;wBACF,OAAO,WAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;oBAC/B,CAAC;iBACA;gBACH,CAAC,CAAC,EAAE;YACL,CAAC,CAAC;gBACA,GAAG;oBACF,IAAI,CAAC,iBAAiB,EAAE,CAAC;wBACxB,iBAAiB,GAAG,IAAI,CAAA;wBACxB,OAAO,CAAE,IAAY,CAAC,KAAK,CAAC,GAAG,YAAY,CAAC,CAAA;oBAC7C,CAAC;oBAED,OAAQ,IAAY,CAAC,KAAK,CAAC,CAAA;gBAC5B,CAAC;aACA,CAAC;QACL,GAAG,CAAC,mBAAmB;YACtB,CAAC,CAAC;gBACA,GAAG,CAAC,QAAa;oBAChB,WAAY,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;oBAEjC,2FAA2F;oBAC3F,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAwB,CAAC,CAAC,CAAA;oBAChE,mCAAmC;gBACpC,CAAC;aACA;YACH,CAAC,CAAC;gBACA,GAAG,CAAC,QAAa;oBAChB,IAAI,CAAC,iBAAiB;wBAAE,iBAAiB,GAAG,IAAI,CAC/C;oBAAC,IAAY,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAA;oBAChC,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAwB,CAAC,CAAC,CAAA;gBACjE,CAAC;aACA,CAAC;KACL,CAAA;IAED,2EAA2E;IAC3E,sDAAsD;IACtD,IAAI,yBAAyB;QAAE,MAAM,CAAC,cAAc,CAAC,SAAS,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAA;IACrF,2EAA2E;IAC3E,sEAAsE;;QACjE,OAAO,UAAU,CAAA;IACtB,cAAc;IACd,+GAA+G;AAChH,CAAC"} \ No newline at end of file diff --git a/dist/index.d.ts b/dist/index.d.ts index 31e687f..5e24323 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -1,3 +1,4 @@ export * from './Eventful.js'; +export * from './emits.js'; export declare const version = "0.3.2"; //# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dist/index.d.ts.map b/dist/index.d.ts.map index 3c2263d..b6c254e 100644 --- a/dist/index.d.ts.map +++ b/dist/index.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAA;AAE7B,eAAO,MAAM,OAAO,UAAU,CAAA"} \ No newline at end of file +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAE1B,eAAO,MAAM,OAAO,UAAU,CAAA"} \ No newline at end of file diff --git a/dist/index.js b/dist/index.js index 64ade57..e2c8983 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1,3 +1,4 @@ export * from './Eventful.js'; +export * from './emits.js'; export const version = '0.3.2'; //# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/index.js.map b/dist/index.js.map index f793e4e..968f541 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAA;AAE7B,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAA"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAE1B,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAA"} \ No newline at end of file diff --git a/src/Eventful.ts b/src/Eventful.ts index 193f1d4..5f75b2a 100644 --- a/src/Eventful.ts +++ b/src/Eventful.ts @@ -1,14 +1,8 @@ import type {Constructor} from 'lowclass/dist/Constructor.js' -// TODO, make strongly typed event args. Combine with stuff in Events.ts (or similar). +// TODO, come up with a pattern for event handler args to be typed. -// TODO, Make sure emit will not attempt to call event handlers removed -// during emit (in place modification of listeners array during emit iteration -// will try to access undefined after the end of the array). Possibly use -// for..of with a Set instead, otherwise modify the iteration index manually. - -// TODO, an option to defer events, and batch them (so that 3 of the -// same event and payload triggers only one event instead of three) +const isEventful = Symbol('isEventful') /** * @mixin @@ -43,9 +37,13 @@ import type {Constructor} from 'lowclass/dist/Constructor.js' * ``` */ export function Eventful(Base: T = Object as any) { - class Eventful extends Base { - // @ts-ignore to avoid "is using private name" errors in consumer code. - [isEventful as any] = isEventful as any + return class Eventful extends Base { + [isEventful] = true + + // We're using Set here so that iteration of event handlers is + // impervious to items being deleted during iteration (i.e. during + // emit). + #eventMap: Map> | null = null /** * @method on - Register a `callback` to be executed any @@ -69,9 +67,9 @@ export function Eventful(Base: T = Object as any) { let callbacks = eventMap.get(eventName) - if (!callbacks) eventMap.set(eventName, (callbacks = [])) + if (!callbacks) eventMap.set(eventName, (callbacks = new Set())) - callbacks.push([callback, context]) + callbacks.add([callback, context]) } /** @@ -92,13 +90,13 @@ export function Eventful(Base: T = Object as any) { if (!callbacks) return - const index = callbacks.findIndex(tuple => tuple[0] === callback && tuple[1] === context) + const tuple = Array.from(callbacks).find(tuple => tuple[0] === callback && tuple[1] === context) - if (index === -1) return + if (!tuple) return - callbacks.splice(index, 1) + callbacks.delete(tuple) - if (callbacks.length === 0) eventMap.delete(eventName) + if (callbacks.size === 0) eventMap.delete(eventName) if (eventMap.size === 0) this.#eventMap = null } @@ -127,168 +125,16 @@ export function Eventful(Base: T = Object as any) { if (!callbacks) return - let tuple: (typeof callbacks)[0] - let callback: (typeof callbacks)[0][0] - let context: (typeof callbacks)[0][1] - - for (let i = 0, len = callbacks.length; i < len; i += 1) { - tuple = callbacks[i] - callback = tuple[0] - context = tuple[1] - callback.call(context, data) - } + for (const [callback, context] of new Set(callbacks)) callback.call(context, data) } - - #eventMap: Map> | null = null } - - Eventful.prototype[isEventful] = isEventful - - return Eventful } -const isEventful = Symbol('isEventful') - +// Use defineProperty instead of assignment because [Symbol.hasInstance] is writable:false Object.defineProperty(Eventful, Symbol.hasInstance, { - value(obj: any): boolean { - if (!obj) return false - if (obj[isEventful]) return true + value(value: any): boolean { + if (!value) return false + if (value[isEventful]) return true return false }, }) - -/** - * @decorator - * @function emits - This is a decorator that when used on a property in a - * class definition, causes setting of that property to emit the specified - * event, with the event payload being the property value. This decorator must - * be used in a class that extends from Eventful, otherwise an error is thrown. - * - * @example - * class Foo { - * @emits('propchange') foo = 123 - * } - * const f = new Foo - * f.on('propchange', value => console.log('value: ', value)) - * f.foo = 456 // logs "value: 456" - */ -export function emits(eventName: string): any { - return (prototype: any, propName: string, descriptor?: PropertyDescriptor) => { - return _emits(prototype, propName, descriptor ?? undefined, eventName) - } -} - -function _emits(prototype: any, propName: string, descriptor: PropertyDescriptor | undefined, eventName: string): any { - if (!(prototype instanceof Eventful)) - throw new TypeError('The @emits decorator is only for use on properties of classes that extend from Eventful.') - - const vName = Symbol('@emits: ' + propName) - - // property decorators are not passed a descriptor (unlike decorators on accessors or methods) - let calledAsPropertyDecorator = false - - if (!descriptor) { - calledAsPropertyDecorator = true - descriptor = Object.getOwnPropertyDescriptor(prototype, propName) - } - - let hasOriginalAccessor = false - let originalGet: (() => any) | undefined - let originalSet: ((v: any) => void) | undefined - let initialValue: any - let writable: boolean | undefined - - if (descriptor) { - if (descriptor.get || descriptor.set) { - hasOriginalAccessor = true - originalGet = descriptor.get - originalSet = descriptor.set - - // reactivity requires both - if (!originalSet) { - console.warn( - 'The `@emits` decorator was used on an accessor named "' + - propName + - '" which did not have a setter. This means an event will never be emitted because the value can not be set. In this case the decorator doesn\'t do anything.', - ) - return - } - - delete descriptor.get - delete descriptor.set - } else { - initialValue = descriptor.value - writable = descriptor.writable - - // if it isn't writable, we don't need to make a reactive variable because - // the value won't change - if (!writable) { - console.warn( - 'The `@emits` decorator was used on a property named "' + - propName + - '" that is not writable. An event can not be emitted because the property can not be modified. In this case the decorator does not do anything.', - ) - return - } - - delete descriptor.value - delete descriptor.writable - } - } - - let initialValueIsSet = false - function emitEvent(this: EventfulInstance) { - this.emit(eventName, propName) - } - - descriptor = { - ...descriptor, - configurable: true, - ...(hasOriginalAccessor - ? originalGet - ? { - get(): any { - return originalGet!.call(this) - }, - } - : {} - : { - get(): any { - if (!initialValueIsSet) { - initialValueIsSet = true - return ((this as any)[vName] = initialValue) - } - - return (this as any)[vName] - }, - }), - ...(hasOriginalAccessor - ? { - set(newValue: any) { - originalSet!.call(this, newValue) - - // TODO should we defer the event, or not? Perhaps provide an option, and defer by default. - Promise.resolve().then(emitEvent.bind(this as EventfulInstance)) - // emitEvent.call(this as Eventful) - }, - } - : { - set(newValue: any) { - if (!initialValueIsSet) initialValueIsSet = true - ;(this as any)[vName] = newValue - Promise.resolve().then(emitEvent.bind(this as EventfulInstance)) - }, - }), - } - - // If a decorator is called on a property, then returning a descriptor does - // nothing, so we need to set the descriptor manually. - if (calledAsPropertyDecorator) Object.defineProperty(prototype, propName, descriptor) - // If a decorator is called on an accessor or method, then we must return a - // descriptor in order to modify it, and doing it manually won't work. - else return descriptor - // Weird, huh? - // This will all change with updates to the ES decorators proposal, https://github.com/tc39/proposal-decorators -} - -type EventfulInstance = InstanceType> diff --git a/src/emits.ts b/src/emits.ts new file mode 100644 index 0000000..1867a4c --- /dev/null +++ b/src/emits.ts @@ -0,0 +1,137 @@ +import {Eventful} from './Eventful.js' + +/** + * @decorator + * @function emits - This is a decorator that when used on a property in a + * class definition, causes setting of that property to emit the specified + * event, with the event payload being the property value. This decorator must + * be used in a class that extends from Eventful, otherwise an error is thrown. + * + * @example + * class Foo { + * @emits('propchange') foo = 123 + * } + * const f = new Foo + * f.on('propchange', value => console.log('value: ', value)) + * f.foo = 456 // logs "value: 456" + */ +export function emits(eventName: string): any { + return (prototype: any, propName: string, descriptor?: PropertyDescriptor) => { + return _emits(prototype, propName, descriptor ?? undefined, eventName) + } +} + +function _emits(prototype: any, propName: string, descriptor: PropertyDescriptor | undefined, eventName: string): any { + if (!(prototype instanceof Eventful)) + throw new TypeError('The @emits decorator is only for use on properties of classes that extend from Eventful.') + + const vName = Symbol('@emits: ' + propName) + + // property decorators are not passed a descriptor (unlike decorators on accessors or methods) + let calledAsPropertyDecorator = false + + if (!descriptor) { + calledAsPropertyDecorator = true + descriptor = Object.getOwnPropertyDescriptor(prototype, propName) + } + + let hasOriginalAccessor = false + let originalGet: (() => any) | undefined + let originalSet: ((v: any) => void) | undefined + let initialValue: any + let writable: boolean | undefined + + if (descriptor) { + if (descriptor.get || descriptor.set) { + hasOriginalAccessor = true + originalGet = descriptor.get + originalSet = descriptor.set + + // reactivity requires both + if (!originalSet) { + console.warn( + 'The `@emits` decorator was used on an accessor named "' + + propName + + '" which did not have a setter. This means an event will never be emitted because the value can not be set. In this case the decorator doesn\'t do anything.', + ) + return + } + + delete descriptor.get + delete descriptor.set + } else { + initialValue = descriptor.value + writable = descriptor.writable + + // if it isn't writable, we don't need to make a reactive variable because + // the value won't change + if (!writable) { + console.warn( + 'The `@emits` decorator was used on a property named "' + + propName + + '" that is not writable. An event can not be emitted because the property can not be modified. In this case the decorator does not do anything.', + ) + return + } + + delete descriptor.value + delete descriptor.writable + } + } + + let initialValueIsSet = false + function emitEvent(this: EventfulInstance) { + this.emit(eventName, propName) + } + + descriptor = { + ...descriptor, + configurable: true, + ...(hasOriginalAccessor + ? originalGet + ? { + get(): any { + return originalGet!.call(this) + }, + } + : {} + : { + get(): any { + if (!initialValueIsSet) { + initialValueIsSet = true + return ((this as any)[vName] = initialValue) + } + + return (this as any)[vName] + }, + }), + ...(hasOriginalAccessor + ? { + set(newValue: any) { + originalSet!.call(this, newValue) + + // TODO should we defer the event, or not? Perhaps provide an option, and defer by default. + Promise.resolve().then(emitEvent.bind(this as EventfulInstance)) + // emitEvent.call(this as Eventful) + }, + } + : { + set(newValue: any) { + if (!initialValueIsSet) initialValueIsSet = true + ;(this as any)[vName] = newValue + Promise.resolve().then(emitEvent.bind(this as EventfulInstance)) + }, + }), + } + + // If a decorator is called on a property, then returning a descriptor does + // nothing, so we need to set the descriptor manually. + if (calledAsPropertyDecorator) Object.defineProperty(prototype, propName, descriptor) + // If a decorator is called on an accessor or method, then we must return a + // descriptor in order to modify it, and doing it manually won't work. + else return descriptor + // Weird, huh? + // This will all change with updates to the ES decorators proposal, https://github.com/tc39/proposal-decorators +} + +type EventfulInstance = InstanceType> diff --git a/src/index.ts b/src/index.ts index 0f60f8b..e15a925 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,4 @@ export * from './Eventful.js' +export * from './emits.js' export const version = '0.3.2'