aveazul 0.1.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 ADDED
@@ -0,0 +1,17 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ Copyright 2025 Joel Chen
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,87 @@
1
+ # AveAzul
2
+
3
+ AveAzul ("Blue Bird" in Spanish) is a Promise extension library that provides Bluebird-like utility methods built on top of native Promises. The name is a Spanish play on words referencing Bluebird.
4
+
5
+ ## Requirements
6
+
7
+ - Node.js 16 or higher
8
+
9
+ ## Features
10
+
11
+ - Extends native Promise with Bluebird-like utility methods
12
+ - Built on top of the efficient `xaa` library for async operations
13
+ - Zero external runtime dependencies (other than `xaa`)
14
+ - TypeScript-friendly
15
+ - Familiar Bluebird-style API
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install aveazul
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ```javascript
26
+ const AveAzul = require('aveazul');
27
+
28
+ // Create a new promise
29
+ const promise = new AveAzul((resolve, reject) => {
30
+ setTimeout(() => resolve('result'), 1000);
31
+ });
32
+
33
+ // Use Bluebird-style methods
34
+ promise
35
+ .tap(value => console.log('Got:', value))
36
+ .delay(500)
37
+ .then(value => console.log('After delay:', value));
38
+
39
+ // Static helpers
40
+ AveAzul.delay(1000, 'hello')
41
+ .then(value => console.log(value));
42
+
43
+ // Array operations
44
+ AveAzul.resolve([1, 2, 3])
45
+ .map(x => x * 2)
46
+ .filter(x => x > 4)
47
+ .then(result => console.log(result)); // [6]
48
+ ```
49
+
50
+ ## API
51
+
52
+ ### Instance Methods
53
+
54
+ - `tap(fn)` - Execute side effects in a chain
55
+ - `filter(fn)` - Filter array elements
56
+ - `map(fn)` - Map array elements
57
+ - `return(value)` - Inject a value into the chain
58
+ - `each(fn)` - Iterate over array elements
59
+ - `delay(ms)` - Delay execution
60
+ - `timeout(ms, message?)` - Set operation timeout
61
+ - `try(fn)` - Wrap sync/async functions
62
+ - `props(obj)` - Handle object properties
63
+ - `reduce(fn, initialValue?)` - Reduce array
64
+ - `throw(reason)` - Return rejected promise
65
+ - `catchThrow(reason)` - Catch and throw new error
66
+ - `catchReturn(value)` - Catch and return value
67
+ - `get(propertyPath)` - Get nested property
68
+
69
+ ### Static Methods
70
+
71
+ - `AveAzul.delay(ms, value?)` - Create delayed promise
72
+ - `AveAzul.map(array, fn)` - Map array elements
73
+ - `AveAzul.try(fn)` - Wrap function execution
74
+ - `AveAzul.props(obj)` - Handle object properties
75
+ - `AveAzul.defer()` - Create deferred promise
76
+ - `AveAzul.promisify(fn, options?)` - Promisify callback functions
77
+ - `AveAzul.each(items, fn)` - Iterate over items
78
+ - `AveAzul.reduce(array, fn, initialValue?)` - Reduce array
79
+ - `AveAzul.throw(reason)` - Create rejected promise
80
+
81
+ ## License
82
+
83
+ Apache 2.0
84
+
85
+ ## Dependencies
86
+
87
+ - [xaa](https://github.com/jchip/xaa) - Efficient async/await helpers
package/lib/aveazul.js ADDED
@@ -0,0 +1,356 @@
1
+ "use strict";
2
+
3
+ const xaa = require("xaa");
4
+ const { promisify: nodePromisify } = require("node:util");
5
+
6
+ /**
7
+ * AveAzul ("Blue Bird" in Spanish) - Extended Promise class that provides Bluebird-like utility methods
8
+ * This implementation is inspired by and provides similar APIs to the Bluebird Promise library,
9
+ * but built on top of native Promises. The name is a Spanish play on words referencing Bluebird.
10
+ * @extends Promise
11
+ */
12
+ class AveAzul extends Promise {
13
+ constructor(executor) {
14
+ super(executor);
15
+ }
16
+
17
+ /**
18
+ * Note: Per ECMAScript specification, when extending Promise, both .then() and static methods
19
+ * (resolve, reject, all, etc) must return instances of the derived class (AveAzul), so there's
20
+ * no need to explicitly wrap returns in new AveAzul(). This behavior is standard across all
21
+ * spec-compliant JS engines (V8, SpiderMonkey, JavaScriptCore, etc).
22
+ */
23
+
24
+ /**
25
+ * Bluebird-style tap() method that lets you perform side effects in a chain
26
+ * Similar to Bluebird's Promise.prototype.tap()
27
+ * @param {Function} fn - Function to execute with the resolved value
28
+ * @returns {Promise} Promise that resolves with the original value
29
+ */
30
+ tap(fn) {
31
+ return this.then(value => {
32
+ fn(value);
33
+ return value;
34
+ });
35
+ }
36
+
37
+ /**
38
+ * Bluebird-style filter() method for array operations
39
+ * Similar to Bluebird's Promise.prototype.filter()
40
+ * @param {Function} fn - Filter function to apply to each element
41
+ * @returns {Promise} Promise that resolves with the filtered array
42
+ */
43
+ filter(fn) {
44
+ return this.then(value => xaa.filter(value, fn));
45
+ }
46
+
47
+ /**
48
+ * Bluebird-style map() method for array operations
49
+ * Similar to Bluebird's Promise.prototype.map()
50
+ * @param {Function} fn - Map function to apply to each element
51
+ * @returns {Promise} Promise that resolves with the mapped array
52
+ */
53
+ map(fn) {
54
+ return this.then(value => xaa.map(value, fn));
55
+ }
56
+
57
+ /**
58
+ * Bluebird-style return() method to inject a value into the chain
59
+ * Similar to Bluebird's Promise.prototype.return()
60
+ * @param {*} value - Value to return
61
+ * @returns {Promise} Promise that resolves with the new value
62
+ */
63
+ return(value) {
64
+ return this.then(() => value);
65
+ }
66
+
67
+ /**
68
+ * Bluebird-style each() method for array iteration
69
+ * Similar to Bluebird's Promise.prototype.each()
70
+ * @param {Function} fn - Function to execute for each element
71
+ * @returns {Promise} Promise that resolves when iteration is complete
72
+ */
73
+ each(fn) {
74
+ return this.then(value => xaa.each(value, fn));
75
+ }
76
+
77
+ /**
78
+ * Bluebird-style delay() method
79
+ * @param {number} ms - Milliseconds to delay
80
+ * @returns {Promise} Promise that resolves after the delay
81
+ */
82
+ delay(ms) {
83
+ return this.then(value => xaa.delay(ms, value));
84
+ }
85
+
86
+ /**
87
+ * Bluebird-style timeout() method
88
+ * @param {number} ms - Milliseconds before timeout
89
+ * @param {string} [message] - Optional error message
90
+ * @returns {Promise} Promise that rejects if timeout occurs
91
+ */
92
+ timeout(ms, message = "Operation timed out") {
93
+ return new AveAzul((resolve, reject) => {
94
+ const timer = setTimeout(() => {
95
+ reject(new Error(message));
96
+ }, ms);
97
+
98
+ this.then(
99
+ value => {
100
+ clearTimeout(timer);
101
+ resolve(value);
102
+ },
103
+ err => {
104
+ clearTimeout(timer);
105
+ reject(err);
106
+ }
107
+ );
108
+ });
109
+ }
110
+
111
+ /**
112
+ * Bluebird-style try() for wrapping sync/async functions
113
+ * @param {Function} fn - Function to execute
114
+ * @returns {Promise} Promise that resolves with the function's return value
115
+ */
116
+ try(fn) {
117
+ return new AveAzul((resolve, reject) => {
118
+ try {
119
+ const result = fn();
120
+ if (result && typeof result.then === "function") {
121
+ result.then(resolve, reject);
122
+ } else {
123
+ resolve(result);
124
+ }
125
+ } catch (err) {
126
+ reject(err);
127
+ }
128
+ });
129
+ }
130
+
131
+ /**
132
+ * Bluebird-style props() for object properties
133
+ * @param {Object} obj - Object with promise values
134
+ * @returns {Promise} Promise that resolves with an object of resolved values
135
+ */
136
+ props(obj) {
137
+ const keys = Object.keys(obj);
138
+ const values = keys.map(k => obj[k]);
139
+
140
+ return AveAzul.all(values).then(results => {
141
+ const resolved = {};
142
+ keys.forEach((k, i) => {
143
+ resolved[k] = results[i];
144
+ });
145
+ return resolved;
146
+ });
147
+ }
148
+
149
+ /**
150
+ * Bluebird-style catchIf() with predicate matching
151
+ * @param {Function|Error} predicate - Error class or predicate function
152
+ * @param {Function} fn - Handler function
153
+ * @returns {Promise} Promise with conditional catch handler
154
+ */
155
+ catchIf(predicate, fn) {
156
+ return this.catch(err => {
157
+ if (
158
+ (typeof predicate === "function" && !predicate.prototype && predicate(err)) ||
159
+ (typeof predicate === "function" && predicate.prototype && err instanceof predicate)
160
+ ) {
161
+ return fn(err);
162
+ }
163
+ throw err;
164
+ });
165
+ }
166
+
167
+ /**
168
+ * Bluebird-style tapCatch() for side effects on rejection
169
+ * @param {Function} fn - Function to execute on rejection
170
+ * @returns {Promise} Promise that maintains the rejection
171
+ */
172
+ tapCatch(fn) {
173
+ return this.catch(err => {
174
+ fn(err);
175
+ throw err;
176
+ });
177
+ }
178
+
179
+ /**
180
+ * Bluebird-style reduce() method for array reduction
181
+ * Similar to Bluebird's Promise.prototype.reduce()
182
+ * @param {Function} fn - Reducer function to apply to each element
183
+ * @param {*} [initialValue] - Optional initial value
184
+ * @returns {Promise} Promise that resolves with the final reduced value
185
+ */
186
+ reduce(fn, initialValue) {
187
+ return this.then(array => AveAzul.reduce(array, fn, initialValue));
188
+ }
189
+
190
+ /**
191
+ * Bluebird-style throw() that returns a rejected promise with the given reason
192
+ * @param {*} reason - Value to reject the promise with
193
+ * @returns {Promise} Promise that rejects with the given reason
194
+ */
195
+ throw(reason) {
196
+ return AveAzul.reject(reason);
197
+ }
198
+
199
+ /**
200
+ * Bluebird-style catchThrow() that catches an error and throws a new one
201
+ * @param {*} reason - Value to reject the promise with
202
+ * @returns {Promise} Promise that rejects with the new reason
203
+ */
204
+ catchThrow(reason) {
205
+ return this.catch(() => AveAzul.throw(reason));
206
+ }
207
+
208
+ /**
209
+ * Bluebird-style catchReturn() that catches an error and returns a value instead
210
+ * @param {*} value - Value to return
211
+ * @returns {Promise} Promise that resolves with the given value
212
+ */
213
+ catchReturn(value) {
214
+ return this.catch(() => value);
215
+ }
216
+
217
+ /**
218
+ * Bluebird-style get() for retrieving a property value
219
+ * @param {string|number} propertyPath - Path to the property (can be nested using dot notation)
220
+ * @returns {Promise} Promise that resolves with the property value
221
+ */
222
+ get(propertyPath) {
223
+ return this.then(value => {
224
+ if (value == null) {
225
+ throw new TypeError("Cannot read property '" + propertyPath + "' of " + value);
226
+ }
227
+
228
+ let result = value;
229
+ const props = String(propertyPath).split(".");
230
+
231
+ for (const prop of props) {
232
+ if (result == null) {
233
+ throw new TypeError("Cannot read property '" + prop + "' of " + result);
234
+ }
235
+ result = result[prop];
236
+ }
237
+
238
+ return result;
239
+ });
240
+ }
241
+ }
242
+
243
+ /**
244
+ * Static helper methods
245
+ */
246
+
247
+ /**
248
+ * Bluebird-style delay() that resolves after specified milliseconds
249
+ * @param {number} ms - Milliseconds to delay
250
+ * @param {*} [value] - Optional value to resolve with
251
+ * @returns {Promise} Promise that resolves after the delay
252
+ */
253
+ AveAzul.delay = (ms, value) => {
254
+ if (value === undefined) {
255
+ return AveAzul.resolve(xaa.delay(ms));
256
+ }
257
+ return AveAzul.resolve(xaa.delay(ms, value));
258
+ };
259
+
260
+ /**
261
+ * Bluebird-style map() for array operations
262
+ * @param {Array} value - Array to map over
263
+ * @param {Function} fn - Map function to apply to each element
264
+ * @returns {Promise} Promise that resolves with the mapped array
265
+ */
266
+ AveAzul.map = (value, fn) => AveAzul.resolve(xaa.map(value, fn));
267
+
268
+ /**
269
+ * Bluebird-style try() for wrapping sync/async functions
270
+ * @param {Function} fn - Function to execute
271
+ * @returns {Promise} Promise that resolves with the function's return value
272
+ */
273
+ AveAzul.try = fn => AveAzul.resolve(xaa.wrap(fn));
274
+
275
+ /**
276
+ * Bluebird-style props() for object properties
277
+ * @param {Object} obj - Object with promise values
278
+ * @returns {Promise} Promise that resolves with an object of resolved values
279
+ */
280
+ AveAzul.props = obj => {
281
+ const keys = Object.keys(obj);
282
+ const values = keys.map(k => obj[k]);
283
+
284
+ return AveAzul.all(values).then(results => {
285
+ const resolved = {};
286
+ keys.forEach((k, i) => {
287
+ resolved[k] = results[i];
288
+ });
289
+ return resolved;
290
+ });
291
+ };
292
+
293
+ /**
294
+ * Bluebird-style defer() for creating a deferred promise
295
+ * @returns {Object} Deferred object with promise, resolve, and reject methods
296
+ */
297
+ AveAzul.defer = () => {
298
+ const deferred = xaa.makeDefer();
299
+ deferred.promise = AveAzul.resolve(deferred.promise);
300
+ return deferred;
301
+ };
302
+
303
+ /**
304
+ * Bluebird-style promisify() for converting callback-style functions to promises
305
+ * @param {Function} fn - Function to promisify
306
+ * @param {Object} [options] - Options object
307
+ * @param {Object} [options.context] - `this` context to bind the function to
308
+ * @returns {Function} Promisified function that returns an AveAzul promise
309
+ */
310
+ AveAzul.promisify = (fn, options = {}) => {
311
+ const promisified = nodePromisify(fn);
312
+ if (options.context) {
313
+ return (...args) => AveAzul.resolve(promisified.apply(options.context, args));
314
+ }
315
+ return (...args) => AveAzul.resolve(promisified(...args));
316
+ };
317
+
318
+ /**
319
+ * Bluebird-style each() for array iteration
320
+ * @param {Array} items - Array to iterate over
321
+ * @param {Function} fn - Iterator function to call for each item
322
+ * @returns {Promise} Promise that resolves when iteration is complete
323
+ */
324
+ AveAzul.each = (items, fn) => AveAzul.resolve(xaa.each(items, fn));
325
+
326
+ /**
327
+ * Bluebird-style reduce() for array reduction
328
+ * @param {Array} array - Array to reduce
329
+ * @param {Function} fn - Reducer function (value, item, index, length)
330
+ * @param {*} [initialValue] - Optional initial value
331
+ * @returns {Promise} Promise that resolves with the final reduced value
332
+ */
333
+ AveAzul.reduce = (array, fn, initialValue) => {
334
+ const hasInitial = arguments.length > 2;
335
+ const len = array.length;
336
+
337
+ return AveAzul.resolve().then(async () => {
338
+ let value = hasInitial ? initialValue : array[0];
339
+ const start = hasInitial ? 0 : 1;
340
+
341
+ for (let i = start; i < len; i++) {
342
+ value = await fn(value, array[i], i, len);
343
+ }
344
+
345
+ return value;
346
+ });
347
+ };
348
+
349
+ /**
350
+ * Bluebird-style throw() that returns a rejected promise with the given reason
351
+ * @param {*} reason - Value to reject the promise with
352
+ * @returns {Promise} Promise that rejects with the given reason
353
+ */
354
+ AveAzul.throw = reason => AveAzul.reject(reason);
355
+
356
+ module.exports = AveAzul;
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "aveazul",
3
+ "version": "0.1.0",
4
+ "description": "Extend native Promise with bluebird like APIs",
5
+ "main": "lib/aveazul.js",
6
+ "homepage": "",
7
+ "license": "Apache-2.0",
8
+ "scripts": {
9
+ "test": "jest test",
10
+ "test:watch": "jest test --watch",
11
+ "test:coverage": "jest test --coverage"
12
+ },
13
+ "author": "Joel Chen",
14
+ "files": [
15
+ "lib"
16
+ ],
17
+ "keywords": [
18
+ "promise",
19
+ "async",
20
+ "bluebird",
21
+ "nodejs"
22
+ ],
23
+ "repository": {
24
+ "type": "git",
25
+ "url": ""
26
+ },
27
+ "dependencies": {
28
+ "xaa": "^1.7.3"
29
+ },
30
+ "devDependencies": {
31
+ "jest": "^29.7.0"
32
+ }
33
+ }