asljs-eventful 0.2.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # MIT License
2
2
 
3
- Copyright (c) 2025 Alexandrite Software Ltd
3
+ Copyright (c) 2026 Alexandrite Software Ltd
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -36,7 +36,10 @@ obj.emit('greet', 'Hello');
36
36
  ```ts
37
37
  import { eventful, type Eventful } from 'asljs-eventful';
38
38
 
39
- const obj: Eventful<{ name: string }> =
39
+ type Events =
40
+ { greet: [msg: string] };
41
+
42
+ const obj: { name: string } & Eventful<Events> =
40
43
  eventful({ name: 'Alice' });
41
44
 
42
45
  obj.on('greet',
@@ -72,6 +75,7 @@ class MyClass extends EventfulBase {
72
75
 
73
76
  ```ts
74
77
  import { EventfulBase } from 'asljs-eventful';
78
+
75
79
  class MyClass extends EventfulBase {
76
80
  name: string;
77
81
 
@@ -158,12 +162,12 @@ const obj =
158
162
  payload);
159
163
  } });
160
164
 
161
- // Tracing actions include:
162
- // - 'new' on creation: payload { object }
163
- // - 'on' when subscribing: payload { object, event, listener }
164
- // - 'off' when unsubscribing: payload { object, event, listener }
165
- // - 'emit' for sync emit: payload { object, event, args, listeners }
166
- // - 'emitAsync' for async emit: payload { object, event, args, listeners }
165
+ // Tracing (event, payload):
166
+ // - 'new' on creation, { object }
167
+ // - 'on' when subscribing, { object, event, listener }
168
+ // - 'off' when unsubscribing, { object, event, listener }
169
+ // - 'emit' for sync emit, { object, event, args, listeners }
170
+ // - 'emitAsync' for async emit, { object, event, args, listeners }
167
171
  ```
168
172
 
169
173
  Custom error handler for listener errors:
@@ -191,7 +195,9 @@ const obj =
191
195
 
192
196
  ### Global Events
193
197
 
194
- `eventful` is also a global emitter. When you create an enhanced object via `eventful(target, options)`, its lifecycle and actions are traced via the per-instance `trace` hook and also emitted as global events on `eventful`.
198
+ `eventful` is also a global emitter. When you create an enhanced object via
199
+ `eventful(target, options)`, its lifecycle and actions are traced via the
200
+ per-instance `trace` hook and also emitted as global events on `eventful`.
195
201
 
196
202
  ```js
197
203
  const offNew =
@@ -213,7 +219,9 @@ offNew();
213
219
  offError();
214
220
  ```
215
221
 
216
- Note: if a **global** `eventful.on('error', ...)` listener throws, `eventful` throws a `ListenerError` (an `Error` subclass with fields `{ error, object, event, listener }`) to avoid an infinite error loop.
222
+ Note: if a **global** `eventful.on('error', ...)` listener throws, `eventful`
223
+ throws a `ListenerError` (an `Error` subclass with fields
224
+ `{ error, object, event, listener }`) to avoid an infinite error loop.
217
225
 
218
226
  ## API
219
227
 
@@ -224,8 +232,10 @@ a new empty object is created.
224
232
 
225
233
  - `target` (Object): The object to be enhanced with event capabilities.
226
234
  - `options` (Object): Configuration options.
227
- - `error` (Function | null): Optional error hook called with `{ error, object, event, listener }`.
228
- - `trace` (Function | null): Optional trace hook called with `(action, payload)`.
235
+ - `error` (Function | null): Optional error hook called with
236
+ `{ error, object, event, listener }`.
237
+ - `trace` (Function | null): Optional trace hook called with
238
+ `(action, payload)`.
229
239
  - `strict` (Boolean): If true, propagates listener errors; otherwise they
230
240
  are isolated. Defaults to false.
231
241
 
package/dist/eventful.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import { ListenerError } from './types.js';
2
- import { eventTypeGuard, functionTypeGuard, isFunction, isObject, } from './guards.js';
2
+ import { eventNameTypeGuard, functionTypeGuard, isFunction, isObject, } from './guards.js';
3
3
  const eventfulImpl = (object = Object.create(null), options = {}) => {
4
4
  if (!isObject(object)
5
5
  && !isFunction(object)) {
6
6
  throw new TypeError('Expect an object or a function.');
7
7
  }
8
8
  for (const method of ['on', 'once', 'off', 'emit', 'emitAsync', 'has']) {
9
- if (object[method] !== undefined) {
9
+ if (method in object) {
10
10
  throw new Error(`Method "${method}" already exists.`);
11
11
  }
12
12
  }
@@ -66,7 +66,7 @@ const eventfulImpl = (object = Object.create(null), options = {}) => {
66
66
  eventful.emit('error', errorArgs);
67
67
  }
68
68
  function on(event, listener) {
69
- eventTypeGuard(event);
69
+ eventNameTypeGuard(event);
70
70
  functionTypeGuard(listener);
71
71
  traceFn('on', { object,
72
72
  event,
@@ -78,7 +78,7 @@ const eventfulImpl = (object = Object.create(null), options = {}) => {
78
78
  : false;
79
79
  }
80
80
  function once(event, listener) {
81
- eventTypeGuard(event);
81
+ eventNameTypeGuard(event);
82
82
  functionTypeGuard(listener);
83
83
  const off = on(event, (...args) => {
84
84
  off();
@@ -87,7 +87,7 @@ const eventfulImpl = (object = Object.create(null), options = {}) => {
87
87
  return off;
88
88
  }
89
89
  function off(event, listener) {
90
- eventTypeGuard(event);
90
+ eventNameTypeGuard(event);
91
91
  functionTypeGuard(listener);
92
92
  traceFn('off', { object,
93
93
  event,
@@ -95,11 +95,11 @@ const eventfulImpl = (object = Object.create(null), options = {}) => {
95
95
  return remove(event, listener);
96
96
  }
97
97
  function has(event) {
98
- eventTypeGuard(event);
98
+ eventNameTypeGuard(event);
99
99
  return (map.get(event)?.size ?? 0) > 0;
100
100
  }
101
101
  function emit(event, ...args) {
102
- eventTypeGuard(event);
102
+ eventNameTypeGuard(event);
103
103
  const listeners = map.get(event)
104
104
  || emptySet;
105
105
  traceFn('emit', { object,
@@ -120,7 +120,7 @@ const eventfulImpl = (object = Object.create(null), options = {}) => {
120
120
  }
121
121
  }
122
122
  async function emitAsync(event, ...args) {
123
- eventTypeGuard(event);
123
+ eventNameTypeGuard(event);
124
124
  const listeners = map.get(event)
125
125
  || emptySet;
126
126
  traceFn('emitAsync', { object,
package/dist/guards.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { EventName } from './types.js';
2
- export declare function eventTypeGuard(value: any): asserts value is EventName;
2
+ export declare function eventNameTypeGuard(value: any): asserts value is EventName;
3
3
  export declare function isFunction(value: any): value is Function;
4
4
  export declare function isObject(value: any): value is object;
5
5
  export declare function functionTypeGuard(value: any): asserts value is Function;
package/dist/guards.js CHANGED
@@ -1,4 +1,4 @@
1
- export function eventTypeGuard(value) {
1
+ export function eventNameTypeGuard(value) {
2
2
  if (typeof value !== 'string'
3
3
  && typeof value !== 'symbol') {
4
4
  throw new TypeError('Expect event to be a string or symbol.');
package/dist/types.d.ts CHANGED
@@ -69,29 +69,29 @@ export interface Eventful<E extends EventMap = EventMap> {
69
69
  /**
70
70
  * Subscribe to an event. Returns an unsubscribe function.
71
71
  */
72
- on(event: keyof E & EventName, listener: Listener<E[keyof E & EventName]>): () => boolean;
72
+ on<K extends keyof E & EventName>(event: K, listener: Listener<E[K]>): () => boolean;
73
73
  /**
74
74
  * Subscribe once to an event. Returns an unsubscribe function
75
75
  * (called automatically).
76
76
  */
77
- once(event: keyof E & EventName, listener: Listener<E[keyof E & EventName]>): () => boolean;
77
+ once<K extends keyof E & EventName>(event: K, listener: Listener<E[K]>): () => boolean;
78
78
  /**
79
79
  * Unsubscribe a previously registered listener. Returns true if removed.
80
80
  */
81
- off(event: keyof E & EventName, listener: Listener<E[keyof E & EventName]>): boolean;
81
+ off<K extends keyof E & EventName>(event: K, listener: Listener<E[K]>): boolean;
82
82
  /**
83
83
  * Emit an event synchronously. All listeners run in order.
84
84
  * Errors are isolated (ignored) unless `strict` is true.
85
85
  */
86
- emit(event: keyof E & EventName, ...args: E[keyof E & EventName]): void;
86
+ emit<K extends keyof E & EventName>(event: K, ...args: E[K]): void;
87
87
  /**
88
88
  * Emit an event and wait for all listeners (run in parallel).
89
89
  * Errors are isolated (ignored) unless `strict` is true.
90
90
  */
91
- emitAsync(event: keyof E & EventName, ...args: E[keyof E & EventName]): Promise<void>;
91
+ emitAsync<K extends keyof E & EventName>(event: K, ...args: E[K]): Promise<void>;
92
92
  /**
93
93
  * Returns true if there is at least one listener for the event.
94
94
  */
95
- has(event: keyof E & EventName): boolean;
95
+ has<K extends keyof E & EventName>(event: K): boolean;
96
96
  }
97
97
  export {};
package/eventful.js CHANGED
@@ -2,3 +2,7 @@ export {
2
2
  eventful,
3
3
  EventfulBase
4
4
  } from './dist/eventful.js';
5
+
6
+ export {
7
+ ListenerError
8
+ } from './dist/types.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "asljs-eventful",
3
- "version": "0.2.3",
3
+ "version": "0.3.0",
4
4
  "description": "Lightweight event helper adding on/off/emit to any object.",
5
5
  "files": [
6
6
  "dist/**",
@@ -37,6 +37,7 @@
37
37
  "doc": "docs"
38
38
  },
39
39
  "scripts": {
40
+ "clean": "node -e \"require('fs').rmSync('dist', { recursive: true, force: true })\"",
40
41
  "build": "tsc -p .",
41
42
  "build:tests": "tsc -p tsconfig.tests.json",
42
43
  "lint": "eslint .",