aveazul 1.0.2 → 2.0.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.
@@ -0,0 +1,610 @@
1
+ import * as xaa from "xaa";
2
+ import { promisify } from "./promisify.js";
3
+ import { promisifyAll } from "./promisify-all.js";
4
+ import { Disposer } from "./disposer.js";
5
+ import { using } from "./using.js";
6
+ import { isPromise, triggerUncaughtException, toArray } from "./util.js";
7
+ import { AggregateError } from "@jchip/error";
8
+ import { OperationalError, isOperationalError, isProgrammerError } from "./operational-error.js";
9
+ /**
10
+ * @fileoverview
11
+ * AveAzul ("Blue Bird" in Spanish) - Extended Promise class that provides Bluebird like utility methods
12
+ * This implementation is inspired by and provides similar APIs to the Bluebird Promise library,
13
+ * but built on top of native Promises. The name is a Spanish play on words referencing Bluebird.
14
+ * @extends Promise
15
+ */
16
+ class AveAzul extends Promise {
17
+ constructor(executor) {
18
+ super(executor);
19
+ }
20
+ /**
21
+ * Note: Per ECMAScript specification, when extending Promise, both .then() and static methods
22
+ * (resolve, reject, all, etc) must return instances of the derived class (AveAzul), so there's
23
+ * no need to explicitly wrap returns in new AveAzul(). This behavior is standard across all
24
+ * spec-compliant JS engines (V8, SpiderMonkey, JavaScriptCore, etc).
25
+ */
26
+ /**
27
+ * Bluebird-style tap() method that lets you perform side effects in a chain
28
+ * Similar to Bluebird's Promise.prototype.tap()
29
+ * @param fn - Function to execute with the resolved value
30
+ * @returns Promise that resolves with the original value
31
+ */
32
+ tap(fn) {
33
+ return this.then(async (value) => {
34
+ await fn(value);
35
+ return value;
36
+ });
37
+ }
38
+ /**
39
+ * Bluebird-style filter() method for array operations
40
+ * Similar to Bluebird's Promise.prototype.filter()
41
+ * @param fn - Filter function to apply to each element
42
+ * @returns Promise that resolves with the filtered array
43
+ */
44
+ filter(fn) {
45
+ return this.then((value) => xaa.filter(value, fn));
46
+ }
47
+ /**
48
+ * Bluebird-style map() method for array operations
49
+ * Similar to Bluebird's Promise.prototype.map()
50
+ * @param fn - Map function to apply to each element
51
+ * @returns Promise that resolves with the mapped array
52
+ */
53
+ map(fn, options = { concurrency: 50 }) {
54
+ return this.then((value) => xaa.map(value, fn, options));
55
+ }
56
+ /**
57
+ * Bluebird-style mapSeries() method for array operations
58
+ * Similar to Bluebird's Promise.prototype.mapSeries()
59
+ * @param fn - Map function to apply to each element
60
+ * @returns Promise that resolves with the mapped array
61
+ */
62
+ mapSeries(fn) {
63
+ return this.map(fn, { concurrency: 1 });
64
+ }
65
+ /**
66
+ * Bluebird-style return() method to inject a value into the chain
67
+ * Similar to Bluebird's Promise.prototype.return()
68
+ * @param value - Value to return
69
+ * @returns Promise that resolves with the new value
70
+ */
71
+ return(value) {
72
+ return this.then(() => value);
73
+ }
74
+ /**
75
+ * Bluebird-style any() method for waiting for any promises to resolve
76
+ * @returns Promise that resolves with the first resolved promise
77
+ */
78
+ any() {
79
+ return this.then((args) => {
80
+ return AveAzul.any(toArray(args));
81
+ });
82
+ }
83
+ /**
84
+ * Bluebird-style each() method for array iteration
85
+ * Similar to Bluebird's Promise.prototype.each()
86
+ * @param fn - Function to execute for each element
87
+ * @returns Promise that resolves when iteration is complete
88
+ */
89
+ each(fn) {
90
+ return this.then(async (value) => {
91
+ const arr = value;
92
+ const result = [];
93
+ for (let i = 0; i < arr.length; i++) {
94
+ let x = arr[i];
95
+ if (isPromise(x)) {
96
+ x = await x;
97
+ }
98
+ await fn(x, i, arr.length);
99
+ result.push(x);
100
+ }
101
+ return result;
102
+ });
103
+ }
104
+ /**
105
+ * Bluebird-style delay() method
106
+ * @param ms - Milliseconds to delay
107
+ * @returns Promise that resolves after the delay
108
+ */
109
+ delay(ms) {
110
+ return xaa.delay(ms);
111
+ }
112
+ /**
113
+ * Bluebird-style timeout() method
114
+ * @param ms - Milliseconds before timeout
115
+ * @param message - Optional error message
116
+ * @returns Promise that rejects if timeout occurs
117
+ */
118
+ timeout(ms, message = "operation timed out") {
119
+ return xaa
120
+ .timeout(ms, message, {
121
+ Promise: AveAzul,
122
+ TimeoutError: OperationalError,
123
+ })
124
+ .run(this);
125
+ }
126
+ /**
127
+ * Bluebird-style props() for object properties
128
+ * @returns Promise that resolves with an object of resolved values
129
+ */
130
+ props() {
131
+ return this.then((value) => {
132
+ const obj = value;
133
+ const keys = Object.keys(obj);
134
+ const values = keys.map((k) => obj[k]);
135
+ return AveAzul.all(values).then((results) => {
136
+ const resolved = {};
137
+ keys.forEach((k, i) => {
138
+ resolved[k] = results[i];
139
+ });
140
+ return resolved;
141
+ });
142
+ });
143
+ }
144
+ /**
145
+ * Bluebird-style tapCatch() for side effects on rejection
146
+ * @param fn - Function to execute on rejection
147
+ * @returns Promise that maintains the rejection
148
+ */
149
+ tapCatch(fn) {
150
+ return this.catch((err) => {
151
+ fn(err);
152
+ throw err;
153
+ });
154
+ }
155
+ /**
156
+ * Bluebird-style reduce() method for array reduction
157
+ * Similar to Bluebird's Promise.prototype.reduce()
158
+ * @param fn - Reducer function to apply to each element
159
+ * @param initialValue - Optional initial value
160
+ * @returns Promise that resolves with the final reduced value
161
+ */
162
+ reduce(fn, initialValue) {
163
+ const hasInitial = arguments.length > 1;
164
+ return this.then(async (array) => {
165
+ const arr = array;
166
+ const len = arr.length;
167
+ let value;
168
+ let idx;
169
+ if (hasInitial) {
170
+ idx = 0;
171
+ value = initialValue;
172
+ }
173
+ else {
174
+ idx = 1;
175
+ value = arr[0];
176
+ }
177
+ value = isPromise(value) ? await value : value;
178
+ for (; idx < len; idx++) {
179
+ let x = arr[idx];
180
+ if (isPromise(x)) {
181
+ x = await x;
182
+ }
183
+ value = await fn(value, x, idx, len);
184
+ }
185
+ return value;
186
+ });
187
+ }
188
+ /**
189
+ * Bluebird-style throw() that returns a rejected promise with the given reason
190
+ * @param reason - Value to reject the promise with
191
+ * @returns Promise that rejects with the given reason
192
+ */
193
+ throw(reason) {
194
+ return AveAzul.reject(reason);
195
+ }
196
+ /**
197
+ * Bluebird-style catchThrow() that catches an error and throws a new one
198
+ * @param reason - Value to reject the promise with
199
+ * @returns Promise that rejects with the new reason
200
+ */
201
+ catchThrow(reason) {
202
+ return this.catch(() => {
203
+ throw reason;
204
+ });
205
+ }
206
+ /**
207
+ * Bluebird-style catchReturn() that catches an error and returns a value instead
208
+ * @param value - Value to return
209
+ * @returns Promise that resolves with the given value
210
+ */
211
+ catchReturn(value) {
212
+ return this.catch(() => value);
213
+ }
214
+ /**
215
+ * Bluebird-style get() for retrieving a property value
216
+ * @param key - Key to retrieve
217
+ * @returns Promise that resolves with the property value
218
+ */
219
+ get(key) {
220
+ return this.then((value) => value[key]);
221
+ }
222
+ /**
223
+ * Bluebird-style disposer() for resource cleanup
224
+ * @param fn - Cleanup function
225
+ * @returns Disposer object
226
+ */
227
+ disposer(fn) {
228
+ if (typeof fn !== "function") {
229
+ throw new TypeError("Expected a function");
230
+ }
231
+ return new Disposer(fn, this);
232
+ }
233
+ /**
234
+ * Bluebird-style spread() method for handling array arguments
235
+ * Similar to Bluebird's Promise.prototype.spread()
236
+ * @param fn - Function to apply to the array arguments
237
+ * @returns Promise that resolves with the function's return value
238
+ */
239
+ spread(fn) {
240
+ if (typeof fn !== "function") {
241
+ return AveAzul.reject(new TypeError("expecting a function but got " + fn));
242
+ }
243
+ return this.then(async (args) => {
244
+ if (Array.isArray(args)) {
245
+ for (let i = 0; i < args.length; i++) {
246
+ if (isPromise(args[i])) {
247
+ args[i] = await args[i];
248
+ }
249
+ }
250
+ return fn(...args);
251
+ }
252
+ else {
253
+ return fn(args);
254
+ }
255
+ });
256
+ }
257
+ some(count) {
258
+ return this.then((args) => {
259
+ const arr = toArray(args);
260
+ return new AveAzul((resolve, reject) => {
261
+ // If too many promises are rejected so that the promise can never become fulfilled,
262
+ // it will be immediately rejected with an AggregateError of the rejection reasons
263
+ // in the order they were thrown in.
264
+ const errors = [];
265
+ // The fulfillment value is an array with count values
266
+ // in the order they were fulfilled.
267
+ const results = [];
268
+ const len = arr.length;
269
+ let settled = false;
270
+ const addDone = (result) => {
271
+ if (settled)
272
+ return;
273
+ results.push(result);
274
+ if (results.length >= count) {
275
+ settled = true;
276
+ // Resolve with exactly count results to match Bluebird's behavior
277
+ resolve(results.slice(0, count));
278
+ }
279
+ };
280
+ const addError = (err) => {
281
+ if (settled)
282
+ return;
283
+ errors.push(err);
284
+ if (len - errors.length < count) {
285
+ settled = true;
286
+ reject(new AggregateError(errors, `aggregate error`));
287
+ }
288
+ };
289
+ for (let i = 0; i < len; i++) {
290
+ const x = arr[i];
291
+ if (isPromise(x)) {
292
+ x.then(addDone, addError);
293
+ }
294
+ else {
295
+ addDone(x);
296
+ }
297
+ }
298
+ });
299
+ });
300
+ }
301
+ /**
302
+ * Bluebird-style all() method for array operations
303
+ * Similar to Promise.all() but operates on the resolved value of this promise
304
+ * @returns Promise that resolves when all items in the array resolve
305
+ */
306
+ all() {
307
+ return this.then((value) => {
308
+ return AveAzul.all(toArray(value));
309
+ });
310
+ }
311
+ /**
312
+ * Bluebird-style asCallback() method
313
+ * Attaches a callback to the promise and returns the promise.
314
+ * The callback is invoked when the promise is resolved or rejected.
315
+ *
316
+ * @param cb - Node.js-style callback function (err, value)
317
+ * @param options - Additional options
318
+ * @returns The same promise instance
319
+ */
320
+ asCallback(cb, options = {}) {
321
+ if (typeof cb !== "function") {
322
+ return this;
323
+ }
324
+ const spread = options && options.spread === true;
325
+ this.then((value) => {
326
+ try {
327
+ if (spread && Array.isArray(value)) {
328
+ cb(null, ...value);
329
+ }
330
+ else {
331
+ cb(null, value);
332
+ }
333
+ }
334
+ catch (err) {
335
+ AveAzul.___throwUncaughtError(err);
336
+ }
337
+ }, (reason) => {
338
+ try {
339
+ cb(reason);
340
+ }
341
+ catch (err) {
342
+ AveAzul.___throwUncaughtError(err);
343
+ }
344
+ });
345
+ return this;
346
+ }
347
+ nodeify(cb, options) {
348
+ return this.asCallback(cb, options);
349
+ }
350
+ /**
351
+ * Bluebird-style call() method for calling a method on the resolved value
352
+ * @param methodName - Name of the method to call
353
+ * @param args - Arguments to pass to the method
354
+ * @returns Promise that resolves with the method's return value
355
+ */
356
+ call(methodName, ...args) {
357
+ return this.then(function (obj) {
358
+ const method = obj[methodName];
359
+ if (typeof method === "function") {
360
+ return method.call(obj, ...args);
361
+ }
362
+ throw new TypeError(`${String(methodName)} is not a function`);
363
+ });
364
+ }
365
+ /**
366
+ * Catches only operational errors and passes them to the handler.
367
+ * Programmer errors (non-operational) are rethrown.
368
+ * @param handler - Function to handle operational errors
369
+ * @returns Promise with the error handled or rethrown
370
+ */
371
+ error(handler) {
372
+ return this.catch((err) => {
373
+ if (isOperationalError(err)) {
374
+ return handler(err);
375
+ }
376
+ throw err;
377
+ });
378
+ }
379
+ /**
380
+ * Static helper methods
381
+ */
382
+ /**
383
+ * Bluebird-style delay() that resolves after specified milliseconds
384
+ * @param ms - Milliseconds to delay
385
+ * @param value - Optional value to resolve with
386
+ * @returns Promise that resolves after the delay
387
+ */
388
+ static delay(ms, value) {
389
+ if (value === undefined) {
390
+ return AveAzul.resolve(xaa.delay(ms));
391
+ }
392
+ return AveAzul.resolve(xaa.delay(ms, value));
393
+ }
394
+ /**
395
+ * Bluebird-style map() for array operations
396
+ * @param value - Array to map over
397
+ * @param fn - Map function to apply to each element
398
+ * @returns Promise that resolves with the mapped array
399
+ */
400
+ static map(value, fn, options = { concurrency: 50 }) {
401
+ return AveAzul.resolve(value).map(fn, options);
402
+ }
403
+ /**
404
+ * Bluebird-style mapSeries() for array operations
405
+ * @param value - Array to map over
406
+ * @param fn - Map function to apply to each element
407
+ * @returns Promise that resolves with the mapped array
408
+ */
409
+ static mapSeries(value, fn) {
410
+ return AveAzul.map(value, fn, { concurrency: 1 });
411
+ }
412
+ /**
413
+ * Bluebird-style try() for wrapping sync/async functions
414
+ * @param fn - Function to execute
415
+ * @returns Promise that resolves with the function's return value
416
+ */
417
+ static try(fn) {
418
+ return AveAzul.resolve(xaa.wrap(fn));
419
+ }
420
+ /**
421
+ * Bluebird-style props() for object properties
422
+ * @param obj - Object with promise values
423
+ * @returns Promise that resolves with an object of resolved values
424
+ */
425
+ static props(obj) {
426
+ const keys = Object.keys(obj);
427
+ const values = keys.map((k) => obj[k]);
428
+ return AveAzul.all(values).then((results) => {
429
+ const resolved = {};
430
+ keys.forEach((k, i) => {
431
+ resolved[k] = results[i];
432
+ });
433
+ return resolved;
434
+ });
435
+ }
436
+ /**
437
+ * Bluebird-style defer() for creating a deferred promise
438
+ * @returns Deferred object with promise, resolve, and reject methods
439
+ */
440
+ static defer() {
441
+ return xaa.makeDefer(AveAzul);
442
+ }
443
+ /**
444
+ * Bluebird-style each() for array iteration
445
+ * @param items - Array to iterate over
446
+ * @param fn - Iterator function to call for each item
447
+ * @returns Promise that resolves when iteration is complete
448
+ */
449
+ static each(items, fn) {
450
+ return AveAzul.resolve(items).each(fn);
451
+ }
452
+ /**
453
+ * Bluebird-style reduce() for array reduction
454
+ * @param array - Array to reduce
455
+ * @param fn - Reducer function (value, item, index, length)
456
+ * @param initialValue - Optional initial value
457
+ * @returns Promise that resolves with the final reduced value
458
+ */
459
+ static reduce(array, fn, initialValue) {
460
+ if (arguments.length > 2) {
461
+ return AveAzul.resolve(array).reduce(fn, initialValue);
462
+ }
463
+ return AveAzul.resolve(array).reduce(fn);
464
+ }
465
+ /**
466
+ * Bluebird-style promisify() for converting callback-based functions to promises
467
+ * @param fn - Function to promisify
468
+ * @param options - Options object
469
+ * @returns Promisified function
470
+ */
471
+ static promisify(fn, options) {
472
+ return promisify(fn, {
473
+ ...options,
474
+ Promise: AveAzul,
475
+ });
476
+ }
477
+ /**
478
+ * Bluebird-style promisifyAll() for converting callback-based functions to promises
479
+ * @param target - Object to promisify
480
+ * @param options - Options object
481
+ * @returns Object with promisified methods
482
+ */
483
+ static promisifyAll(target, options) {
484
+ return promisifyAll(target, {
485
+ ...options,
486
+ Promise: AveAzul,
487
+ });
488
+ }
489
+ /**
490
+ * Bluebird-style method() for creating a method that returns a promise
491
+ * @param fn - Function to create a method for
492
+ * @returns Method function that returns a promise
493
+ */
494
+ static method(fn) {
495
+ return function (...args) {
496
+ return new AveAzul((resolve, reject) => {
497
+ try {
498
+ const result = fn.call(this, ...args);
499
+ resolve(result);
500
+ }
501
+ catch (error) {
502
+ reject(error);
503
+ }
504
+ });
505
+ };
506
+ }
507
+ /**
508
+ * Bluebird-style using() for resource management. There is only a static version of this method.
509
+ * After the handler finish and returns, regardless of whether it resolves or rejects, the resources will be disposed.
510
+ *
511
+ * @param resources - Resource disposers, either an array of disposers or a variadic argument list
512
+ * @param args - Handler function that will receive the resources as arguments
513
+ * @returns Promise that resolves with handler result
514
+ */
515
+ static using(resources, ...args) {
516
+ if (args.length === 0) {
517
+ throw new TypeError("resrouces and handler function required");
518
+ }
519
+ if (Array.isArray(resources)) {
520
+ if (args.length > 1) {
521
+ throw new TypeError("only two arguments are allowed when passing an array of resources");
522
+ }
523
+ return using(resources, args[0], AveAzul, true);
524
+ }
525
+ const handler = args.pop();
526
+ return using([resources, ...args], handler, AveAzul, false);
527
+ }
528
+ /**
529
+ * Bluebird-style join() for joining promises
530
+ *
531
+ * @param args - Promises to join
532
+ * @returns Promise that resolves with the handler's return value
533
+ */
534
+ static join(...args) {
535
+ if (args.length > 1 && typeof args[args.length - 1] === "function") {
536
+ const handler = args.pop();
537
+ return AveAzul.all(args).then((results) => handler(...results));
538
+ }
539
+ else {
540
+ return AveAzul.all(args);
541
+ }
542
+ }
543
+ /**
544
+ * Bluebird-style fromCallback() for converting callback-based functions to promises
545
+ * @param fn - Function to convert
546
+ * @param options - Options object
547
+ * @returns Promise that resolves with the function's return value
548
+ */
549
+ static fromCallback(fn, options) {
550
+ return new AveAzul((resolve, reject) => {
551
+ try {
552
+ fn((err, ...args) => {
553
+ if (err) {
554
+ reject(err);
555
+ }
556
+ else {
557
+ if (options && options.multiArgs) {
558
+ resolve(args);
559
+ }
560
+ else {
561
+ resolve(args[0]);
562
+ }
563
+ }
564
+ });
565
+ }
566
+ catch (err) {
567
+ reject(err);
568
+ }
569
+ });
570
+ }
571
+ /**
572
+ * Bluebird-style some() for waiting for some promises to resolve
573
+ * @param promises - Array or iterable of promises
574
+ * @param count - Number of promises that need to resolve
575
+ * @returns Promise that resolves when count promises have resolved
576
+ */
577
+ static some(promises, count) {
578
+ return AveAzul.resolve(promises).some(count);
579
+ }
580
+ /**
581
+ * Bluebird-style any() for waiting for any promise to resolve
582
+ * @param args - Array or iterable of promises
583
+ * @returns Promise that resolves with the first resolved value
584
+ */
585
+ /* v8 ignore next 4 */
586
+ static any(args) {
587
+ // Will be overwritten by addStaticAny
588
+ throw new Error("any not initialized");
589
+ }
590
+ }
591
+ AveAzul.fromNode = AveAzul.fromCallback;
592
+ /**
593
+ * When fatal error and AveAzul needs to crash the process,
594
+ * this method is used to throw the error.
595
+ *
596
+ * @param error - The error to throw.
597
+ */
598
+ AveAzul.___throwUncaughtError = triggerUncaughtException;
599
+ AveAzul.OperationalError = OperationalError;
600
+ AveAzul.isOperationalError = isOperationalError;
601
+ AveAzul.isProgrammerError = isProgrammerError;
602
+ AveAzul.Disposer = Disposer;
603
+ // Setup the any method
604
+ import { addStaticAny } from "./any.js";
605
+ addStaticAny(AveAzul);
606
+ // Setup the not implemented methods
607
+ import { setupNotImplemented } from "./not-implemented.js";
608
+ setupNotImplemented(AveAzul);
609
+ export { AveAzul };
610
+ export default AveAzul;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Disposer class for resource cleanup
3
+ * @private
4
+ */
5
+ export declare class Disposer<T> {
6
+ _data: (resource: T) => void | Promise<void>;
7
+ _promise: Promise<T>;
8
+ constructor(fn: (resource: T) => void | Promise<void>, promise: Promise<T>);
9
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Disposer class for resource cleanup
3
+ * @private
4
+ */
5
+ export class Disposer {
6
+ constructor(fn, promise) {
7
+ this._data = fn;
8
+ this._promise = promise;
9
+ }
10
+ }
@@ -0,0 +1,10 @@
1
+ import { AveAzul } from "./aveazul.js";
2
+ export { AveAzul };
3
+ export default AveAzul;
4
+ export type { MapOptions, AsCallbackOptions, FromCallbackOptions, Deferred, AveAzulClass, AveAzulInstance, } from "./aveazul.js";
5
+ export { Disposer } from "./disposer.js";
6
+ export { OperationalError, isOperationalError, isProgrammerError } from "./operational-error.js";
7
+ export { promisify } from "./promisify.js";
8
+ export type { PromisifyOptions } from "./promisify.js";
9
+ export { promisifyAll } from "./promisify-all.js";
10
+ export type { PromisifyAllOptions } from "./promisify-all.js";
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ import { AveAzul } from "./aveazul.js";
2
+ export { AveAzul };
3
+ export default AveAzul;
4
+ export { Disposer } from "./disposer.js";
5
+ export { OperationalError, isOperationalError, isProgrammerError } from "./operational-error.js";
6
+ export { promisify } from "./promisify.js";
7
+ export { promisifyAll } from "./promisify-all.js";
@@ -0,0 +1,4 @@
1
+ import type { AveAzulClass } from "./aveazul.js";
2
+ export declare function createInstanceNotImplemented(AveAzul: AveAzulClass): string[];
3
+ export declare function createStaticNotImplemented(AveAzul: AveAzulClass): string[];
4
+ export declare function setupNotImplemented(AveAzul: AveAzulClass): void;