@gesslar/toolkit 0.0.5 → 0.0.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gesslar/toolkit",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "Get in, bitches, we're going toolkitting.",
5
5
  "main": "./src/index.js",
6
6
  "type": "module",
package/src/lib/Data.js CHANGED
@@ -1,6 +1,9 @@
1
1
  /**
2
- * @file Data utility functions for type checking, object manipulation, and array operations.
3
- * Provides comprehensive utilities for working with JavaScript data types and structures.
2
+ * @file Data utility functions for type checking, object manipulation, and
3
+ * array operations.
4
+ *
5
+ * Provides comprehensive utilities for working with JavaScript data types and
6
+ * structures.
4
7
  */
5
8
 
6
9
  import Sass from "./Sass.js"
@@ -54,7 +57,9 @@ export default class Data {
54
57
  ])
55
58
 
56
59
  /**
57
- * Combined array of all supported data types (primitives and constructors in lowercase).
60
+ * Combined array of all supported data types (primitives and constructors in
61
+ * lowercase).
62
+ *
58
63
  * Used for type validation throughout the utility functions.
59
64
  *
60
65
  * @type {Array<string>}
@@ -530,4 +535,27 @@ export default class Data {
530
535
  return arr.filter((_, index) => results[index])
531
536
  }
532
537
 
538
+ /**
539
+ * Ensures a value is within a specified range.
540
+ *
541
+ * @param {number} val - The value to check.
542
+ * @param {number} min - The minimum value.
543
+ * @param {number} max - The maximum value.
544
+ * @returns {number} The value, constrained within the range of `min` to `max`.
545
+ */
546
+ static clamp(val, min, max) {
547
+ return val >= min ? val <= max ? val : max : min
548
+ }
549
+
550
+ /**
551
+ * Checks if a value is within a specified range (inclusive).
552
+ *
553
+ * @param {number} val - The value to check.
554
+ * @param {number} min - The minimum value (inclusive).
555
+ * @param {number} max - The maximum value (inclusive).
556
+ * @returns {boolean} True if the value is within the range, false otherwise.
557
+ */
558
+ static clamped(val, min, max) {
559
+ return val >= min && val <= max
560
+ }
533
561
  }
package/src/lib/Util.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import {createHash} from "node:crypto"
2
2
  import {performance} from "node:perf_hooks"
3
+ import {EventEmitter} from "node:events"
4
+ import Sass from "./Sass.js"
3
5
 
4
6
  /**
5
7
  * Utility class providing common helper functions for string manipulation,
@@ -131,4 +133,91 @@ export default class Util {
131
133
  static async race(promises) {
132
134
  return await Promise.race(promises)
133
135
  }
136
+
137
+ /**
138
+ * Private method that performs the actual async emission logic.
139
+ * Handles listener execution, error aggregation, and result processing.
140
+ *
141
+ * @param {object} emitter - The emitter object (already validated)
142
+ * @param {string} event - The event name to emit
143
+ * @param {...unknown} args - Arguments to pass to event listeners
144
+ * @returns {Promise<void>} Resolves when all listeners have completed
145
+ */
146
+ static async #performAsyncEmit(emitter, event, ...args) {
147
+ const listeners = emitter.listeners(event)
148
+
149
+ if(listeners.length === 0)
150
+ return // No listeners, nothing to do
151
+
152
+ const settled =
153
+ await Promise.allSettled(listeners.map(listener => listener(...args)))
154
+
155
+ const rejected = settled.filter(result => result.status === "rejected")
156
+
157
+ if(rejected.length > 0) {
158
+ if(rejected[0].reason instanceof Error)
159
+ throw rejected[0].reason
160
+ else
161
+ throw Sass.new(rejected[0].reason)
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Emits an event asynchronously and waits for all listeners to complete.
167
+ * Unlike the standard EventEmitter.emit() which is synchronous, this method
168
+ * properly handles async event listeners by waiting for all of them to
169
+ * resolve or reject using Promise.allSettled().
170
+ *
171
+ * Uses strict instanceof checking to ensure the emitter is a genuine EventEmitter.
172
+ *
173
+ * @param {EventEmitter} emitter - The EventEmitter instance to emit on
174
+ * @param {string} event - The event name to emit
175
+ * @param {...unknown} args - Arguments to pass to event listeners
176
+ * @returns {Promise<void>} Resolves when all listeners have completed
177
+ */
178
+ static async asyncEmit(emitter, event, ...args) {
179
+ try {
180
+ if(!(emitter instanceof EventEmitter))
181
+ throw Sass.new("First argument must be an EventEmitter instance")
182
+
183
+ await this.#performAsyncEmit(emitter, event, ...args)
184
+ } catch(error) {
185
+ const argsDesc = args.length > 0 ? `with arguments: ${args.map(String).join(", ")}` : "with no arguments"
186
+
187
+ throw Sass.new(
188
+ `Processing '${event}' event ${argsDesc}.`,
189
+ error
190
+ )
191
+ }
192
+ }
193
+
194
+ /**
195
+ * Emits an event asynchronously and waits for all listeners to complete.
196
+ * Like asyncEmit, but uses duck typing for more flexible emitter validation.
197
+ * Accepts any object that has the required EventEmitter-like methods.
198
+ *
199
+ * @param {object} emitter - Any object with EventEmitter-like interface
200
+ * @param {string} event - The event name to emit
201
+ * @param {...unknown} args - Arguments to pass to event listeners
202
+ * @returns {Promise<void>} Resolves when all listeners have completed
203
+ */
204
+ static async asyncEmitAnon(emitter, event, ...args) {
205
+ try {
206
+ if(!emitter ||
207
+ typeof emitter.listeners !== "function" ||
208
+ typeof emitter.on !== "function" ||
209
+ typeof emitter.emit !== "function") {
210
+ throw Sass.new("First argument must be an EventEmitter-like object")
211
+ }
212
+
213
+ await this.#performAsyncEmit(emitter, event, ...args)
214
+ } catch(error) {
215
+ const argsDesc = args.length > 0 ? `with arguments: ${args.map(String).join(", ")}` : "with no arguments"
216
+
217
+ throw Sass.new(
218
+ `Processing '${event}' event ${argsDesc}.`,
219
+ error
220
+ )
221
+ }
222
+ }
134
223
  }
@@ -94,4 +94,10 @@ export default class Data {
94
94
 
95
95
  /** Filter an array asynchronously */
96
96
  static asyncFilter<T>(arr: Array<T>, predicate: (item: T) => Promise<boolean>): Promise<Array<T>>
97
- }
97
+
98
+ /** Ensures a value is within a specified range */
99
+ static clamp(val: number, min: number, max: number): number
100
+
101
+ /** Checks if a value is within a specified range (inclusive) */
102
+ static clamped(val: number, min: number, max: number): boolean
103
+ }
@@ -81,6 +81,33 @@ declare class Util {
81
81
  * @returns Result of the first settled promise
82
82
  */
83
83
  static race<T>(promises: Array<Promise<T>>): Promise<T>
84
+
85
+ /**
86
+ * Emits an event asynchronously and waits for all listeners to complete.
87
+ * Unlike the standard EventEmitter.emit() which is synchronous, this method
88
+ * properly handles async event listeners by waiting for all of them to
89
+ * resolve or reject using Promise.allSettled().
90
+ *
91
+ * Uses strict instanceof checking to ensure the emitter is a genuine EventEmitter.
92
+ *
93
+ * @param emitter - The EventEmitter instance to emit on
94
+ * @param event - The event name to emit
95
+ * @param args - Arguments to pass to event listeners
96
+ * @returns Resolves when all listeners have completed
97
+ */
98
+ static asyncEmit(emitter: import('events').EventEmitter, event: string, ...args: unknown[]): Promise<void>
99
+
100
+ /**
101
+ * Emits an event asynchronously and waits for all listeners to complete.
102
+ * Like asyncEmit, but uses duck typing for more flexible emitter validation.
103
+ * Accepts any object that has the required EventEmitter-like methods.
104
+ *
105
+ * @param emitter - Any object with EventEmitter-like interface
106
+ * @param event - The event name to emit
107
+ * @param args - Arguments to pass to event listeners
108
+ * @returns Resolves when all listeners have completed
109
+ */
110
+ static asyncEmitAnon(emitter: { listeners(event: string): Function[], on(event: string, listener: Function): any, emit(event: string, ...args: unknown[]): any }, event: string, ...args: unknown[]): Promise<void>
84
111
  }
85
112
 
86
113
  export default Util