aveazul 1.0.0 → 1.0.2
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/README.md +10 -1
- package/lib/any.js +55 -0
- package/lib/aveazul.js +40 -43
- package/lib/not-implemented.js +0 -1
- package/lib/operational-error.js +46 -0
- package/lib/promisify-all.js +9 -48
- package/lib/promisify.js +2 -2
- package/lib/using.js +29 -15
- package/lib/util.js +86 -81
- package/package.json +10 -4
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# AveAzul
|
|
1
|
+
# AveAzul.js
|
|
2
2
|
|
|
3
3
|
AveAzul ("Blue Bird" in Spanish) serves as a near drop-in replacement for Bluebird. It's built on native Promise, by extending it with the familiar utility methods from Bluebird.
|
|
4
4
|
|
|
@@ -14,6 +14,10 @@ Further, if you like Bluebird's API but want to use native Promises, AveAzul giv
|
|
|
14
14
|
- Implements most commonly used Bluebird methods
|
|
15
15
|
- Comprehensive test suite ensuring compatibility
|
|
16
16
|
|
|
17
|
+
## Requirements
|
|
18
|
+
|
|
19
|
+
- node.js version >= 12
|
|
20
|
+
|
|
17
21
|
## Installation
|
|
18
22
|
|
|
19
23
|
```bash
|
|
@@ -143,6 +147,7 @@ Key differences to be aware of:
|
|
|
143
147
|
- `all()` - Like Promise.all(), resolves when all promises resolve, rejects if any reject
|
|
144
148
|
- `call(propertyName, ...args)` - Call a method on the resolved value with the provided arguments
|
|
145
149
|
- `asCallback(callback, options?)` - Register a Node-style callback that handles the resolution or rejection
|
|
150
|
+
- `error(handler)` - Like catch(), but only catches operational errors, letting programmer errors bubble up
|
|
146
151
|
|
|
147
152
|
### Static Methods
|
|
148
153
|
|
|
@@ -164,6 +169,10 @@ Key differences to be aware of:
|
|
|
164
169
|
- `using(resources, fn)` - Manage resources with automatic cleanup
|
|
165
170
|
- `join(...values, handler?)` - Wait for multiple promises and pass their resolved values as separate arguments to the handler function. If no handler is provided, behaves like Promise.all
|
|
166
171
|
|
|
172
|
+
### Error Types
|
|
173
|
+
|
|
174
|
+
- `AveAzul.OperationalError` - Error type for representing expected operational errors (network failures, validation errors, etc.)
|
|
175
|
+
|
|
167
176
|
### PromisifyAll Options
|
|
168
177
|
|
|
169
178
|
- `suffix` (default: 'Async') - Suffix to append to promisified method names
|
package/lib/any.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { toArray, isPromise } = require("./util");
|
|
4
|
+
const { AggregateError } = require("@jchip/error");
|
|
5
|
+
|
|
6
|
+
function addStaticAny(AveAzul, force = false) {
|
|
7
|
+
if (force || !AveAzul.any) {
|
|
8
|
+
AveAzul.any = function (args) {
|
|
9
|
+
try {
|
|
10
|
+
args = toArray(args);
|
|
11
|
+
} catch (error) {
|
|
12
|
+
return AveAzul.reject(error);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (args.length === 0) {
|
|
16
|
+
return AveAzul.reject(
|
|
17
|
+
new RangeError(
|
|
18
|
+
"Input array must contain at least 1 items but contains only 0 items"
|
|
19
|
+
)
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return new AveAzul((resolve, reject) => {
|
|
24
|
+
const len = args.length;
|
|
25
|
+
let settled = false;
|
|
26
|
+
const errors = [];
|
|
27
|
+
|
|
28
|
+
const doFinish = (value) => {
|
|
29
|
+
if (settled) return;
|
|
30
|
+
settled = true;
|
|
31
|
+
resolve(value);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const addError = (err) => {
|
|
35
|
+
errors.push(err);
|
|
36
|
+
if (!settled && errors.length >= len) {
|
|
37
|
+
settled = true;
|
|
38
|
+
reject(new AggregateError(errors));
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
for (let i = 0; i < len; i++) {
|
|
43
|
+
const arg = args[i];
|
|
44
|
+
if (isPromise(arg)) {
|
|
45
|
+
arg.then(doFinish, addError);
|
|
46
|
+
} else {
|
|
47
|
+
doFinish(arg);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
module.exports.addStaticAny = addStaticAny;
|
package/lib/aveazul.js
CHANGED
|
@@ -5,8 +5,9 @@ const { promisify } = require("./promisify");
|
|
|
5
5
|
const { promisifyAll } = require("./promisify-all");
|
|
6
6
|
const { Disposer } = require("./disposer");
|
|
7
7
|
const { using } = require("./using");
|
|
8
|
-
const { isPromise, triggerUncaughtException } = require("./util");
|
|
9
|
-
|
|
8
|
+
const { isPromise, triggerUncaughtException, toArray } = require("./util");
|
|
9
|
+
const { AggregateError } = require("@jchip/error");
|
|
10
|
+
const { OperationalError, isOperationalError } = require("./operational-error");
|
|
10
11
|
/**
|
|
11
12
|
* @fileoverview
|
|
12
13
|
* AveAzul ("Blue Bird" in Spanish) - Extended Promise class that provides Bluebird like utility methods
|
|
@@ -86,20 +87,7 @@ class AveAzul extends Promise {
|
|
|
86
87
|
*/
|
|
87
88
|
any() {
|
|
88
89
|
return this.then((args) => {
|
|
89
|
-
|
|
90
|
-
// Check if args is iterable
|
|
91
|
-
if (args != null && typeof args[Symbol.iterator] === "function") {
|
|
92
|
-
// Convert iterable to array, must do this to get the length, in order
|
|
93
|
-
// to detect if too many errors occurred and completion is impossible.
|
|
94
|
-
args = Array.from(args);
|
|
95
|
-
} else {
|
|
96
|
-
throw new TypeError(
|
|
97
|
-
"expecting an array or an iterable object but got " + args
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return AveAzul.any(args);
|
|
90
|
+
return AveAzul.any(toArray(args));
|
|
103
91
|
});
|
|
104
92
|
}
|
|
105
93
|
|
|
@@ -140,7 +128,12 @@ class AveAzul extends Promise {
|
|
|
140
128
|
* @returns {Promise} Promise that rejects if timeout occurs
|
|
141
129
|
*/
|
|
142
130
|
timeout(ms, message = "operation timed out") {
|
|
143
|
-
return
|
|
131
|
+
return xaa
|
|
132
|
+
.timeout(ms, message, {
|
|
133
|
+
Promise: AveAzul,
|
|
134
|
+
TimeoutError: OperationalError,
|
|
135
|
+
})
|
|
136
|
+
.run(this);
|
|
144
137
|
}
|
|
145
138
|
|
|
146
139
|
/**
|
|
@@ -291,18 +284,7 @@ class AveAzul extends Promise {
|
|
|
291
284
|
|
|
292
285
|
some(count) {
|
|
293
286
|
return this.then((args) => {
|
|
294
|
-
|
|
295
|
-
// Check if args is iterable
|
|
296
|
-
if (args != null && typeof args[Symbol.iterator] === "function") {
|
|
297
|
-
// Convert iterable to array, must do this to get the length, in order
|
|
298
|
-
// to detect if too many errors occurred and completion is impossible.
|
|
299
|
-
args = Array.from(args);
|
|
300
|
-
} else {
|
|
301
|
-
throw new TypeError(
|
|
302
|
-
"expecting an array or an iterable object but got " + args
|
|
303
|
-
);
|
|
304
|
-
}
|
|
305
|
-
}
|
|
287
|
+
args = toArray(args);
|
|
306
288
|
|
|
307
289
|
return new AveAzul((resolve, reject) => {
|
|
308
290
|
// If too many promises are rejected so that the promise can never become fulfilled,
|
|
@@ -314,17 +296,23 @@ class AveAzul extends Promise {
|
|
|
314
296
|
const results = [];
|
|
315
297
|
const len = args.length;
|
|
316
298
|
|
|
299
|
+
let settled = false;
|
|
300
|
+
|
|
317
301
|
const addDone = (result) => {
|
|
302
|
+
if (settled) return;
|
|
318
303
|
results.push(result);
|
|
319
304
|
if (results.length >= count) {
|
|
305
|
+
settled = true;
|
|
320
306
|
// Resolve with exactly count results to match Bluebird's behavior
|
|
321
307
|
resolve(results.slice(0, count));
|
|
322
308
|
}
|
|
323
309
|
};
|
|
324
310
|
|
|
325
311
|
const addError = (err) => {
|
|
312
|
+
if (settled) return;
|
|
326
313
|
errors.push(err);
|
|
327
314
|
if (len - errors.length < count) {
|
|
315
|
+
settled = true;
|
|
328
316
|
reject(new AggregateError(errors, `aggregate error`));
|
|
329
317
|
}
|
|
330
318
|
};
|
|
@@ -348,19 +336,7 @@ class AveAzul extends Promise {
|
|
|
348
336
|
*/
|
|
349
337
|
all() {
|
|
350
338
|
return this.then((value) => {
|
|
351
|
-
|
|
352
|
-
// Check if value is iterable
|
|
353
|
-
if (value != null && typeof value[Symbol.iterator] === "function") {
|
|
354
|
-
// Convert iterable to array
|
|
355
|
-
value = Array.from(value);
|
|
356
|
-
} else {
|
|
357
|
-
throw new TypeError(
|
|
358
|
-
"expecting an array or an iterable object but got " + value
|
|
359
|
-
);
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
return AveAzul.all(value);
|
|
339
|
+
return AveAzul.all(toArray(value));
|
|
364
340
|
});
|
|
365
341
|
}
|
|
366
342
|
|
|
@@ -420,6 +396,21 @@ class AveAzul extends Promise {
|
|
|
420
396
|
return obj[methodName].call(obj, ...args);
|
|
421
397
|
});
|
|
422
398
|
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Catches only operational errors and passes them to the handler.
|
|
402
|
+
* Programmer errors (non-operational) are rethrown.
|
|
403
|
+
* @param {Function} handler - Function to handle operational errors
|
|
404
|
+
* @returns {Promise} - Promise with the error handled or rethrown
|
|
405
|
+
*/
|
|
406
|
+
error(handler) {
|
|
407
|
+
return this.catch((err) => {
|
|
408
|
+
if (isOperationalError(err)) {
|
|
409
|
+
return handler(err);
|
|
410
|
+
}
|
|
411
|
+
throw err;
|
|
412
|
+
});
|
|
413
|
+
}
|
|
423
414
|
}
|
|
424
415
|
|
|
425
416
|
/**
|
|
@@ -584,7 +575,7 @@ AveAzul.using = (resources, ...args) => {
|
|
|
584
575
|
* @returns {Promise} Promise that resolves with the handler's return value
|
|
585
576
|
*/
|
|
586
577
|
AveAzul.join = function (...args) {
|
|
587
|
-
if (args.length > 1 && typeof args.
|
|
578
|
+
if (args.length > 1 && typeof args[args.length - 1] === "function") {
|
|
588
579
|
const handler = args.pop();
|
|
589
580
|
return AveAzul.all(args).then((results) => handler(...results));
|
|
590
581
|
} else {
|
|
@@ -641,8 +632,14 @@ AveAzul.some = function (promises, count) {
|
|
|
641
632
|
return AveAzul.resolve(promises).some(count);
|
|
642
633
|
};
|
|
643
634
|
|
|
635
|
+
const { addStaticAny } = require("./any");
|
|
636
|
+
addStaticAny(AveAzul);
|
|
637
|
+
|
|
644
638
|
// Setup the not implemented methods
|
|
645
639
|
const { setupNotImplemented } = require("./not-implemented");
|
|
646
640
|
setupNotImplemented(AveAzul);
|
|
647
641
|
|
|
642
|
+
// Add these static properties after the class definition
|
|
643
|
+
AveAzul.OperationalError = OperationalError;
|
|
644
|
+
|
|
648
645
|
module.exports = AveAzul;
|
package/lib/not-implemented.js
CHANGED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* OperationalError class for representing errors that are expected during normal operation
|
|
5
|
+
* Similar to Bluebird's OperationalError
|
|
6
|
+
*/
|
|
7
|
+
class OperationalError extends Error {
|
|
8
|
+
constructor(message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = "OperationalError";
|
|
11
|
+
this.isOperational = true;
|
|
12
|
+
|
|
13
|
+
// Capture stack trace
|
|
14
|
+
if (Error.captureStackTrace) {
|
|
15
|
+
Error.captureStackTrace(this, this.constructor);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Check if an error is an operational error
|
|
22
|
+
* @param {*} error - Error to check
|
|
23
|
+
* @returns {boolean} True if the error is operational
|
|
24
|
+
*/
|
|
25
|
+
function isOperationalError(error) {
|
|
26
|
+
if (!error || typeof error !== "object") return false;
|
|
27
|
+
return error instanceof OperationalError || error.isOperational === true;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Check if an error is a programmer error (unexpected, likely a bug)
|
|
32
|
+
* @param {*} error - Error to check
|
|
33
|
+
* @returns {boolean} True if the error is a programmer error
|
|
34
|
+
*/
|
|
35
|
+
function isProgrammerError(error) {
|
|
36
|
+
if (!error || typeof error !== "object") return false;
|
|
37
|
+
return !isOperationalError(error);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Only export the OperationalError class
|
|
41
|
+
module.exports = {
|
|
42
|
+
OperationalError,
|
|
43
|
+
// Internal utilities used by AveAzul.prototype.error
|
|
44
|
+
isOperationalError,
|
|
45
|
+
isProgrammerError,
|
|
46
|
+
};
|
package/lib/promisify-all.js
CHANGED
|
@@ -4,16 +4,14 @@ const { promisify } = require("./promisify");
|
|
|
4
4
|
const {
|
|
5
5
|
isIdentifier,
|
|
6
6
|
isClass,
|
|
7
|
-
isConstructor,
|
|
8
7
|
isPromisified,
|
|
9
|
-
|
|
10
|
-
isExcludedPrototype,
|
|
8
|
+
getObjectDataKeys,
|
|
11
9
|
} = require("./util");
|
|
12
10
|
|
|
13
11
|
const defaultSuffix = "Async";
|
|
14
12
|
|
|
15
13
|
const defaultFilter = function (name) {
|
|
16
|
-
return isIdentifier(name) && name.charAt(0) !== "_" && name !== "constructor";
|
|
14
|
+
return isIdentifier(name) && name.charAt(0) !== "_" && name !== "constructor" && !name.endsWith("Sync");
|
|
17
15
|
};
|
|
18
16
|
|
|
19
17
|
const defaultPromisifier = (fn, _defaultPromisifier, options) => {
|
|
@@ -23,33 +21,9 @@ const defaultPromisifier = (fn, _defaultPromisifier, options) => {
|
|
|
23
21
|
});
|
|
24
22
|
};
|
|
25
23
|
|
|
26
|
-
const excludedClasses = [Array, Object, Function];
|
|
27
|
-
|
|
28
|
-
// Helper function to determine if a class extends from any excluded class
|
|
29
|
-
function isExcludedClass(obj) {
|
|
30
|
-
if (excludedClasses.includes(obj)) {
|
|
31
|
-
return true;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Check if obj extends from any excluded class using instanceof
|
|
35
|
-
if (typeof obj === "function" && obj.prototype) {
|
|
36
|
-
// Check if prototype is instance of any excluded class
|
|
37
|
-
for (const excludedClass of excludedClasses) {
|
|
38
|
-
if (obj.prototype instanceof excludedClass) {
|
|
39
|
-
return true;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return false;
|
|
45
|
-
}
|
|
46
24
|
|
|
47
25
|
function promisifyAll2(obj, options) {
|
|
48
|
-
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const allKeys = getObjectKeys(obj);
|
|
26
|
+
const allKeys = getObjectDataKeys(obj);
|
|
53
27
|
|
|
54
28
|
for (const key of allKeys) {
|
|
55
29
|
const value = obj[key];
|
|
@@ -57,7 +31,6 @@ function promisifyAll2(obj, options) {
|
|
|
57
31
|
const passesDefaultFilter =
|
|
58
32
|
options.filter === defaultFilter ? true : defaultFilter(key, value, obj);
|
|
59
33
|
if (
|
|
60
|
-
isConstructor(value) ||
|
|
61
34
|
typeof value !== "function" ||
|
|
62
35
|
isPromisified(value) ||
|
|
63
36
|
obj[promisifiedKey] ||
|
|
@@ -76,19 +49,16 @@ function promisifyAll2(obj, options) {
|
|
|
76
49
|
}
|
|
77
50
|
|
|
78
51
|
obj[promisifiedKey] = options.promisifier(value, defaultPromisifier, {
|
|
79
|
-
context: obj,
|
|
52
|
+
// context: obj, // promisified function should get the binded object using this
|
|
80
53
|
copyProps: false,
|
|
81
|
-
|
|
82
|
-
Promise: options.Promise,
|
|
54
|
+
...options
|
|
83
55
|
});
|
|
84
56
|
}
|
|
85
57
|
}
|
|
86
58
|
|
|
87
59
|
function promisifyAll(target, _options) {
|
|
88
60
|
if (typeof target !== "function" && typeof target !== "object") {
|
|
89
|
-
throw new TypeError(
|
|
90
|
-
"the target of promisifyAll must be an object or a function"
|
|
91
|
-
);
|
|
61
|
+
throw new TypeError("the target of promisifyAll must be an object or a function");
|
|
92
62
|
}
|
|
93
63
|
|
|
94
64
|
const options = {
|
|
@@ -107,21 +77,12 @@ function promisifyAll(target, _options) {
|
|
|
107
77
|
);
|
|
108
78
|
}
|
|
109
79
|
|
|
110
|
-
const allKeys =
|
|
80
|
+
const allKeys = getObjectDataKeys(target);
|
|
111
81
|
|
|
112
82
|
for (const key of allKeys) {
|
|
113
83
|
const value = target[key];
|
|
114
|
-
if (
|
|
115
|
-
value
|
|
116
|
-
key !== "constructor" &&
|
|
117
|
-
!key.startsWith("_") &&
|
|
118
|
-
isClass(value)
|
|
119
|
-
) {
|
|
120
|
-
const proto = Object.getPrototypeOf(value);
|
|
121
|
-
if (!isExcludedPrototype(proto)) {
|
|
122
|
-
promisifyAll2(proto, options);
|
|
123
|
-
}
|
|
124
|
-
|
|
84
|
+
if (value && key !== "constructor" && !key.startsWith("_") && isClass(value)) {
|
|
85
|
+
promisifyAll2(value.prototype, options);
|
|
125
86
|
promisifyAll2(value, options);
|
|
126
87
|
}
|
|
127
88
|
}
|
package/lib/promisify.js
CHANGED
|
@@ -22,7 +22,7 @@ module.exports.promisify = function promisify(fn, _options) {
|
|
|
22
22
|
const Promise = options.Promise;
|
|
23
23
|
const multiArgs = !!options.multiArgs;
|
|
24
24
|
|
|
25
|
-
const promisifiedFn = (...args)
|
|
25
|
+
const promisifiedFn = function (...args) {
|
|
26
26
|
return new Promise((resolve, reject) => {
|
|
27
27
|
// add a callback to the end of the arguments to transfer the result to the promise
|
|
28
28
|
args.push((err, ...values) => {
|
|
@@ -37,7 +37,7 @@ module.exports.promisify = function promisify(fn, _options) {
|
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
// call the original function with the updated args
|
|
40
|
-
fn.call(options.context, ...args);
|
|
40
|
+
fn.call(options.context || this, ...args);
|
|
41
41
|
});
|
|
42
42
|
};
|
|
43
43
|
|
package/lib/using.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { Disposer } = require("./disposer");
|
|
4
4
|
const { isPromise } = require("./util");
|
|
5
|
+
const { AggregateError } = require("@jchip/error");
|
|
5
6
|
|
|
6
7
|
const SYM_FN_DISPOSE = Symbol("fnDispose");
|
|
7
8
|
/**
|
|
@@ -28,6 +29,25 @@ function using(resources, handler, Promise, asArray) {
|
|
|
28
29
|
// Expect Promise to be AveAzul or Bluebird that has map method
|
|
29
30
|
const acquisitionErrors = [];
|
|
30
31
|
|
|
32
|
+
// Helper function to process a disposer
|
|
33
|
+
const processDisposer = async (resource, disposer) => {
|
|
34
|
+
try {
|
|
35
|
+
const res = await disposer._promise;
|
|
36
|
+
resource._result = res;
|
|
37
|
+
resource[SYM_FN_DISPOSE] = disposer._data;
|
|
38
|
+
} catch (error) {
|
|
39
|
+
acquisitionErrors.push(error);
|
|
40
|
+
resource._error = error;
|
|
41
|
+
}
|
|
42
|
+
return resource;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Helper to check if something is a disposer
|
|
46
|
+
const isDisposer = (obj) =>
|
|
47
|
+
obj &&
|
|
48
|
+
(obj instanceof Disposer ||
|
|
49
|
+
(obj._promise && typeof obj._data === "function"));
|
|
50
|
+
|
|
31
51
|
const acquireResources = () => {
|
|
32
52
|
const promiseRes = resources.map((resource) => {
|
|
33
53
|
// if it's a promise-like, wait for its resolved value
|
|
@@ -38,27 +58,21 @@ function using(resources, handler, Promise, asArray) {
|
|
|
38
58
|
});
|
|
39
59
|
|
|
40
60
|
return Promise.map(promiseRes, async (resource) => {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
(resource
|
|
44
|
-
(resource._promise && typeof resource._data === "function"))
|
|
45
|
-
) {
|
|
46
|
-
try {
|
|
47
|
-
const res = await resource._promise;
|
|
48
|
-
resource._result = res;
|
|
49
|
-
resource[SYM_FN_DISPOSE] = resource._data;
|
|
50
|
-
} catch (error) {
|
|
51
|
-
acquisitionErrors.push(error);
|
|
52
|
-
resource._error = error;
|
|
53
|
-
}
|
|
54
|
-
return resource;
|
|
61
|
+
// If it's directly a disposer
|
|
62
|
+
if (isDisposer(resource)) {
|
|
63
|
+
return processDisposer(resource, resource);
|
|
55
64
|
}
|
|
56
65
|
|
|
57
66
|
// if it's a promise like, wait for its resolved value
|
|
58
67
|
if (resource && resource.___promise) {
|
|
59
68
|
try {
|
|
60
69
|
const res = await resource.___promise;
|
|
61
|
-
|
|
70
|
+
// Check if the resolved value is a disposer
|
|
71
|
+
if (isDisposer(res)) {
|
|
72
|
+
return processDisposer(resource, res);
|
|
73
|
+
} else {
|
|
74
|
+
resource._result = res;
|
|
75
|
+
}
|
|
62
76
|
} catch (error) {
|
|
63
77
|
acquisitionErrors.push(error);
|
|
64
78
|
resource._error = error;
|
package/lib/util.js
CHANGED
|
@@ -11,32 +11,25 @@
|
|
|
11
11
|
*/
|
|
12
12
|
const thisAssignmentPattern = /this\s*\.\s*\S+\s*=/;
|
|
13
13
|
function isClass(fn) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
) {
|
|
33
|
-
return true;
|
|
34
|
-
}
|
|
14
|
+
try {
|
|
15
|
+
if (typeof fn === "function") {
|
|
16
|
+
const keys = Object.getOwnPropertyNames(fn.prototype);
|
|
17
|
+
|
|
18
|
+
const hasMethods = keys.length > 1;
|
|
19
|
+
const hasMethodsOtherThanConstructor = keys.length > 0 &&
|
|
20
|
+
!(keys.length === 1 && keys[0] === "constructor");
|
|
21
|
+
const hasThisAssignmentAndStaticMethods =
|
|
22
|
+
thisAssignmentPattern.test(fn + "") && Object.getOwnPropertyNames (fn).length > 0;
|
|
23
|
+
|
|
24
|
+
if (hasMethods || hasMethodsOtherThanConstructor ||
|
|
25
|
+
hasThisAssignmentAndStaticMethods) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return false;
|
|
30
|
+
} catch (e) {
|
|
31
|
+
return false;
|
|
35
32
|
}
|
|
36
|
-
return false;
|
|
37
|
-
} catch (e) {
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
40
33
|
}
|
|
41
34
|
|
|
42
35
|
const rident = /^[a-z$_][a-z$_0-9]*$/i;
|
|
@@ -44,18 +37,6 @@ function isIdentifier(str) {
|
|
|
44
37
|
return rident.test(str);
|
|
45
38
|
}
|
|
46
39
|
|
|
47
|
-
function isConstructor(func) {
|
|
48
|
-
if (!func) {
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
const proto = func.prototype;
|
|
52
|
-
return (
|
|
53
|
-
!!proto &&
|
|
54
|
-
!!proto.constructor &&
|
|
55
|
-
!!proto.constructor.name &&
|
|
56
|
-
proto.constructor.name === func.name
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
40
|
|
|
60
41
|
/**
|
|
61
42
|
* Prop filtering code copied from bluebird/js/release
|
|
@@ -81,11 +62,7 @@ function copyOwnProperties(source, target, filter = propsFilter) {
|
|
|
81
62
|
|
|
82
63
|
for (const name of names) {
|
|
83
64
|
if (filter(name)) {
|
|
84
|
-
Object.defineProperty(
|
|
85
|
-
target,
|
|
86
|
-
name,
|
|
87
|
-
Object.getOwnPropertyDescriptor(source, name)
|
|
88
|
-
);
|
|
65
|
+
Object.defineProperty(target, name, Object.getOwnPropertyDescriptor(source, name));
|
|
89
66
|
}
|
|
90
67
|
}
|
|
91
68
|
}
|
|
@@ -118,52 +95,66 @@ function isPromise(obj) {
|
|
|
118
95
|
);
|
|
119
96
|
}
|
|
120
97
|
|
|
121
|
-
// istanbul ignore next
|
|
122
|
-
const emptyFatArrow = () => {};
|
|
123
|
-
// istanbul ignore next
|
|
124
|
-
const emptyFunction = function () {};
|
|
125
|
-
|
|
126
|
-
const defaultExcluded = [
|
|
127
|
-
Object.getPrototypeOf(Array), // Array.prototype
|
|
128
|
-
Object.getPrototypeOf(Object), // Object.prototype
|
|
129
|
-
Object.getPrototypeOf(Function), // Function.prototype
|
|
130
|
-
Object.getPrototypeOf([]),
|
|
131
|
-
Object.getPrototypeOf({}),
|
|
132
|
-
Object.getPrototypeOf(emptyFatArrow),
|
|
133
|
-
Object.getPrototypeOf(emptyFunction),
|
|
134
|
-
];
|
|
135
|
-
|
|
136
|
-
function isExcludedPrototype(proto) {
|
|
137
|
-
return defaultExcluded.includes(proto);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
98
|
/**
|
|
141
99
|
* Gets all property keys from an object and its prototype chain, excluding standard
|
|
142
100
|
* prototypes like Object.prototype, Array.prototype, and Function.prototype
|
|
143
101
|
*
|
|
144
|
-
* @param {Object}
|
|
102
|
+
* @param {Object} obj - The target object to get keys from
|
|
145
103
|
* @param {Array} [excludedPrototypes=[]] - An array of prototype objects to exclude keys from
|
|
146
104
|
* @returns {Array<string>} - Array of property keys
|
|
147
105
|
*/
|
|
148
|
-
function
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
106
|
+
function getObjectDataKeys(obj, excludedProtos = []) {
|
|
107
|
+
const excludedPrototypes = [
|
|
108
|
+
Array.prototype,
|
|
109
|
+
Object.prototype,
|
|
110
|
+
Function.prototype,
|
|
111
|
+
...excludedProtos,
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
const isExcludedProto = function (val) {
|
|
115
|
+
for (const protoVal of excludedPrototypes) {
|
|
116
|
+
if (protoVal === val) {
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return false;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const ret = [];
|
|
124
|
+
const visitedKeys = Object.create(null);
|
|
125
|
+
|
|
126
|
+
/* copied from bluebird/js/release/util.js and modified */
|
|
127
|
+
while (obj && !isExcludedProto(obj)) {
|
|
128
|
+
let keys;
|
|
129
|
+
try {
|
|
130
|
+
keys = Object.getOwnPropertyNames(obj);
|
|
131
|
+
} catch (e) {
|
|
132
|
+
/* istanbul ignore next */
|
|
133
|
+
return ret;
|
|
134
|
+
}
|
|
158
135
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
136
|
+
for (const key of keys) {
|
|
137
|
+
/* istanbul ignore if */
|
|
138
|
+
if (visitedKeys[key]) {
|
|
139
|
+
/* istanbul ignore next */
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
visitedKeys[key] = true;
|
|
143
|
+
const desc = Object.getOwnPropertyDescriptor(obj, key);
|
|
144
|
+
/**
|
|
145
|
+
* When desc.get && desc.set are falsy, it means the property is a data
|
|
146
|
+
* property that holds an actual value, rather than being computed dynamically
|
|
147
|
+
* through getter/setter functions.
|
|
148
|
+
*/
|
|
149
|
+
/* istanbul ignore next */
|
|
150
|
+
if (desc && !desc.get && !desc.set) {
|
|
151
|
+
ret.push(key);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
obj = Object.getPrototypeOf(obj);
|
|
163
155
|
}
|
|
164
156
|
|
|
165
|
-
|
|
166
|
-
return [...protoKeys, ...ownKeys];
|
|
157
|
+
return ret;
|
|
167
158
|
}
|
|
168
159
|
|
|
169
160
|
/**
|
|
@@ -183,12 +174,26 @@ function triggerUncaughtException(error) {
|
|
|
183
174
|
}, 0);
|
|
184
175
|
}
|
|
185
176
|
|
|
177
|
+
function toArray(args) {
|
|
178
|
+
if (!Array.isArray(args)) {
|
|
179
|
+
// Check if args is iterable
|
|
180
|
+
if (args != null && typeof args[Symbol.iterator] === "function") {
|
|
181
|
+
// Convert iterable to array, must do this to get the length, in order
|
|
182
|
+
// to detect if too many errors occurred and completion is impossible.
|
|
183
|
+
args = Array.from(args);
|
|
184
|
+
} else {
|
|
185
|
+
throw new TypeError("expecting an array or an iterable object but got " + args);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return args;
|
|
190
|
+
}
|
|
191
|
+
|
|
186
192
|
module.exports.copyOwnProperties = copyOwnProperties;
|
|
187
193
|
module.exports.isClass = isClass;
|
|
188
194
|
module.exports.isIdentifier = isIdentifier;
|
|
189
|
-
module.exports.isConstructor = isConstructor;
|
|
190
195
|
module.exports.isPromisified = isPromisified;
|
|
191
196
|
module.exports.isPromise = isPromise;
|
|
192
197
|
module.exports.triggerUncaughtException = triggerUncaughtException;
|
|
193
|
-
module.exports.
|
|
194
|
-
module.exports.
|
|
198
|
+
module.exports.getObjectDataKeys = getObjectDataKeys;
|
|
199
|
+
module.exports.toArray = toArray;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aveazul",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Bluebird drop-in replacement built on native Promise",
|
|
5
5
|
"main": "lib/aveazul.js",
|
|
6
6
|
"homepage": "https://github.com/jchip/aveazul",
|
|
@@ -53,18 +53,24 @@
|
|
|
53
53
|
"any",
|
|
54
54
|
"props",
|
|
55
55
|
"filter",
|
|
56
|
-
"reduce"
|
|
56
|
+
"reduce",
|
|
57
|
+
"aveazul",
|
|
58
|
+
"aveazul.js"
|
|
57
59
|
],
|
|
58
60
|
"repository": {
|
|
59
61
|
"type": "git",
|
|
60
62
|
"url": "git+https://github.com/jchip/aveazul.git"
|
|
61
63
|
},
|
|
62
64
|
"dependencies": {
|
|
63
|
-
"
|
|
65
|
+
"@jchip/error": "^1.0.3",
|
|
66
|
+
"xaa": "^1.8.0"
|
|
64
67
|
},
|
|
65
68
|
"devDependencies": {
|
|
66
69
|
"bluebird": "^3.7.2",
|
|
67
|
-
"jest": "^
|
|
70
|
+
"jest": "^28.0.0",
|
|
68
71
|
"rimraf": "^3.0.1"
|
|
72
|
+
},
|
|
73
|
+
"engines": {
|
|
74
|
+
"node": ">=12.0.0"
|
|
69
75
|
}
|
|
70
76
|
}
|