aveazul 0.1.4 → 0.1.5
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 +15 -0
- package/lib/aveazul.js +80 -2
- package/lib/disposer.js +2 -2
- package/lib/not-implemented.js +97 -0
- package/lib/promisify-all.js +14 -17
- package/lib/using.js +28 -23
- package/lib/util.js +36 -31
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -58,6 +58,17 @@ AveAzul.using(getResource(), (resource) => {
|
|
|
58
58
|
console.log(result); // "operation completed"
|
|
59
59
|
// Resource is automatically closed here, even if an error occurred
|
|
60
60
|
});
|
|
61
|
+
|
|
62
|
+
// Using spread to apply array results as arguments
|
|
63
|
+
AveAzul.all([getUser(1), getPosts(1), getComments(1)]).spread(
|
|
64
|
+
(user, posts, comments) => {
|
|
65
|
+
// Instead of using .then(([user, posts, comments]) => {...})
|
|
66
|
+
console.log(
|
|
67
|
+
`User ${user.name} has ${posts.length} posts and ${comments.length} comments`
|
|
68
|
+
);
|
|
69
|
+
return { user, activity: { posts, comments } };
|
|
70
|
+
}
|
|
71
|
+
);
|
|
61
72
|
```
|
|
62
73
|
|
|
63
74
|
## API
|
|
@@ -72,6 +83,7 @@ AveAzul.using(getResource(), (resource) => {
|
|
|
72
83
|
- `delay(ms)` - Delay resolution
|
|
73
84
|
- `timeout(ms, message?)` - Reject after specified time
|
|
74
85
|
- `props(obj)` - Resolve object properties
|
|
86
|
+
- `spread(fn)` - Apply array values as arguments to function
|
|
75
87
|
- `tapCatch(fn)` - Execute side effects on rejection
|
|
76
88
|
- `reduce(fn, initialValue?)` - Reduce array elements
|
|
77
89
|
- `throw(reason)` - Return rejected promise
|
|
@@ -88,12 +100,15 @@ AveAzul.using(getResource(), (resource) => {
|
|
|
88
100
|
- `props(obj)` - Resolve object properties
|
|
89
101
|
- `defer()` - Create a deferred promise
|
|
90
102
|
- `promisify(fn, options?)` - Convert callback-style functions to promises (preserves original function properties)
|
|
103
|
+
- `fromNode(fn, options?)` - Convert Node-style callback functions to promise-returning functions
|
|
104
|
+
- `fromCallback(fn, options?)` - Alias for fromNode
|
|
91
105
|
- `each(items, fn)` - Iterate over array elements
|
|
92
106
|
- `reduce(array, fn, initialValue?)` - Reduce array elements
|
|
93
107
|
- `method(fn)` - Creates a method that returns a promise resolving to the value returned by the original function
|
|
94
108
|
- `throw(reason)` - Return rejected promise
|
|
95
109
|
- `promisifyAll(target, options?)` - Convert all methods of an object/class to promises
|
|
96
110
|
- `using(resources, fn)` - Manage resources with automatic cleanup
|
|
111
|
+
- `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
|
|
97
112
|
|
|
98
113
|
### PromisifyAll Options
|
|
99
114
|
|
package/lib/aveazul.js
CHANGED
|
@@ -6,6 +6,7 @@ const { promisifyAll } = require("./promisify-all");
|
|
|
6
6
|
const { Disposer } = require("./disposer");
|
|
7
7
|
const { using } = require("./using");
|
|
8
8
|
const { isPromise, triggerUncaughtException } = require("./util");
|
|
9
|
+
|
|
9
10
|
/**
|
|
10
11
|
* AveAzul ("Blue Bird" in Spanish) - Extended Promise class that provides Bluebird-like utility methods
|
|
11
12
|
* This implementation is inspired by and provides similar APIs to the Bluebird Promise library,
|
|
@@ -31,8 +32,8 @@ class AveAzul extends Promise {
|
|
|
31
32
|
* @returns {Promise} Promise that resolves with the original value
|
|
32
33
|
*/
|
|
33
34
|
tap(fn) {
|
|
34
|
-
return this.then((value) => {
|
|
35
|
-
fn(value);
|
|
35
|
+
return this.then(async (value) => {
|
|
36
|
+
await fn(value);
|
|
36
37
|
return value;
|
|
37
38
|
});
|
|
38
39
|
}
|
|
@@ -222,8 +223,36 @@ class AveAzul extends Promise {
|
|
|
222
223
|
if (typeof fn !== "function") {
|
|
223
224
|
throw new TypeError("Expected a function");
|
|
224
225
|
}
|
|
226
|
+
|
|
225
227
|
return new Disposer(fn, this);
|
|
226
228
|
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Bluebird-style spread() method for handling array arguments
|
|
232
|
+
* Similar to Bluebird's Promise.prototype.spread()
|
|
233
|
+
* @param {Function} fn - Function to apply to the array arguments
|
|
234
|
+
* @returns {Promise} Promise that resolves with the function's return value
|
|
235
|
+
*/
|
|
236
|
+
spread(fn) {
|
|
237
|
+
if (typeof fn !== "function") {
|
|
238
|
+
return AveAzul.reject(
|
|
239
|
+
new TypeError("expecting a function but got " + fn)
|
|
240
|
+
);
|
|
241
|
+
}
|
|
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
|
+
} else {
|
|
252
|
+
return fn(args);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
}
|
|
227
256
|
}
|
|
228
257
|
|
|
229
258
|
/**
|
|
@@ -371,6 +400,52 @@ AveAzul.using = (resources, ...args) => {
|
|
|
371
400
|
return using([resources, ...args], handler, AveAzul, false);
|
|
372
401
|
};
|
|
373
402
|
|
|
403
|
+
/**
|
|
404
|
+
* Bluebird-style join() for joining promises
|
|
405
|
+
*
|
|
406
|
+
* @param {...Promise} args - Promises to join
|
|
407
|
+
* @param {Function} handler - Handler function to apply to the joined results
|
|
408
|
+
* @returns {Promise} Promise that resolves with the handler's return value
|
|
409
|
+
*/
|
|
410
|
+
AveAzul.join = function (...args) {
|
|
411
|
+
if (args.length > 1 && typeof args.at(-1) === "function") {
|
|
412
|
+
const handler = args.pop();
|
|
413
|
+
return AveAzul.all(args).then((results) => handler(...results));
|
|
414
|
+
} else {
|
|
415
|
+
return AveAzul.all(args);
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
function fromCallback(fn, options) {
|
|
420
|
+
return new AveAzul((resolve, reject) => {
|
|
421
|
+
try {
|
|
422
|
+
fn((err, ...args) => {
|
|
423
|
+
if (err) {
|
|
424
|
+
reject(err);
|
|
425
|
+
} else {
|
|
426
|
+
if (options && options.multiArgs) {
|
|
427
|
+
resolve(args);
|
|
428
|
+
} else {
|
|
429
|
+
resolve(args[0]);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
} catch (err) {
|
|
434
|
+
reject(err);
|
|
435
|
+
}
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
AveAzul.fromNode = fromCallback;
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Bluebird-style fromCallback() for converting callback-based functions to promises
|
|
443
|
+
* @param {Function} fn - Function to convert
|
|
444
|
+
* @param {Object} [options] - Options object
|
|
445
|
+
* @returns {Promise} Promise that resolves with the function's return value
|
|
446
|
+
*/
|
|
447
|
+
AveAzul.fromCallback = fromCallback;
|
|
448
|
+
|
|
374
449
|
/**
|
|
375
450
|
* @description
|
|
376
451
|
* When fatal error and AveAzul needs to crash the process,
|
|
@@ -381,3 +456,6 @@ AveAzul.using = (resources, ...args) => {
|
|
|
381
456
|
AveAzul.___throwUncaughtError = triggerUncaughtException;
|
|
382
457
|
|
|
383
458
|
module.exports = AveAzul;
|
|
459
|
+
|
|
460
|
+
const { setupNotImplemented } = require("./not-implemented");
|
|
461
|
+
setupNotImplemented(AveAzul);
|
package/lib/disposer.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* @private
|
|
6
6
|
*/
|
|
7
7
|
class Disposer {
|
|
8
|
-
constructor(
|
|
9
|
-
this._data =
|
|
8
|
+
constructor(fn, promise) {
|
|
9
|
+
this._data = fn; // The cleanup function
|
|
10
10
|
this._promise = promise; // The promise that resolves to the resource
|
|
11
11
|
}
|
|
12
12
|
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
function createNotImplemented(name) {
|
|
4
|
+
return function () {
|
|
5
|
+
const msg = name + " Not implemented in aveazul";
|
|
6
|
+
console.error(msg);
|
|
7
|
+
throw new Error(msg);
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function createInstanceNotImplemented(AveAzul) {
|
|
12
|
+
const methods = [
|
|
13
|
+
"spread",
|
|
14
|
+
"error",
|
|
15
|
+
"bind",
|
|
16
|
+
"join",
|
|
17
|
+
"try",
|
|
18
|
+
"method",
|
|
19
|
+
"isFulfilled",
|
|
20
|
+
"isRejected",
|
|
21
|
+
"isPending",
|
|
22
|
+
"value",
|
|
23
|
+
"reason",
|
|
24
|
+
"props",
|
|
25
|
+
"any",
|
|
26
|
+
"some",
|
|
27
|
+
"map",
|
|
28
|
+
"reduce",
|
|
29
|
+
"filter",
|
|
30
|
+
"each",
|
|
31
|
+
"mapSeries",
|
|
32
|
+
"tap",
|
|
33
|
+
"tapCatch",
|
|
34
|
+
"catchThrow",
|
|
35
|
+
"catchReturn",
|
|
36
|
+
"get",
|
|
37
|
+
"throw",
|
|
38
|
+
"call",
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
const proto = AveAzul.prototype;
|
|
42
|
+
const ret = [];
|
|
43
|
+
for (const method of methods) {
|
|
44
|
+
if (!proto[method]) {
|
|
45
|
+
ret.push(method);
|
|
46
|
+
proto[method] = createNotImplemented("instance " + method);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return ret;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function createStaticNotImplemented(AveAzul) {
|
|
53
|
+
const methods = [
|
|
54
|
+
"join",
|
|
55
|
+
"try",
|
|
56
|
+
"method",
|
|
57
|
+
"resolve",
|
|
58
|
+
"reject",
|
|
59
|
+
"all",
|
|
60
|
+
"props",
|
|
61
|
+
"any",
|
|
62
|
+
"some",
|
|
63
|
+
"map",
|
|
64
|
+
"filter",
|
|
65
|
+
"each",
|
|
66
|
+
"mapSeries",
|
|
67
|
+
"race",
|
|
68
|
+
"promisify",
|
|
69
|
+
"promisifyAll",
|
|
70
|
+
"fromNode",
|
|
71
|
+
"fromCallback",
|
|
72
|
+
"delay",
|
|
73
|
+
"coroutine",
|
|
74
|
+
"config",
|
|
75
|
+
];
|
|
76
|
+
const ret = [];
|
|
77
|
+
for (const method of methods) {
|
|
78
|
+
if (!AveAzul[method]) {
|
|
79
|
+
ret.push(method);
|
|
80
|
+
AveAzul[method] = createNotImplemented("static " + method);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return ret;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function setupNotImplemented(AveAzul) {
|
|
87
|
+
const instance = createInstanceNotImplemented(AveAzul);
|
|
88
|
+
const staticMethods = createStaticNotImplemented(AveAzul);
|
|
89
|
+
AveAzul.__notImplementedInstance = instance;
|
|
90
|
+
AveAzul.__notImplementedStatic = staticMethods;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
module.exports = {
|
|
94
|
+
createInstanceNotImplemented,
|
|
95
|
+
createStaticNotImplemented,
|
|
96
|
+
setupNotImplemented,
|
|
97
|
+
};
|
package/lib/promisify-all.js
CHANGED
|
@@ -7,6 +7,7 @@ const {
|
|
|
7
7
|
isConstructor,
|
|
8
8
|
isPromisified,
|
|
9
9
|
getObjectKeys,
|
|
10
|
+
isExcludedPrototype,
|
|
10
11
|
} = require("./util");
|
|
11
12
|
|
|
12
13
|
const defaultSuffix = "Async";
|
|
@@ -22,12 +23,6 @@ const defaultPromisifier = (fn, _defaultPromisifier, options) => {
|
|
|
22
23
|
});
|
|
23
24
|
};
|
|
24
25
|
|
|
25
|
-
const excludedPrototypes = [
|
|
26
|
-
Object.getPrototypeOf(Array),
|
|
27
|
-
Object.getPrototypeOf(Object),
|
|
28
|
-
Object.getPrototypeOf(Function),
|
|
29
|
-
];
|
|
30
|
-
|
|
31
26
|
const excludedClasses = [Array, Object, Function];
|
|
32
27
|
|
|
33
28
|
// Helper function to determine if a class extends from any excluded class
|
|
@@ -54,17 +49,9 @@ function promisifyAll2(obj, options) {
|
|
|
54
49
|
return;
|
|
55
50
|
}
|
|
56
51
|
|
|
57
|
-
const allKeys = getObjectKeys(obj
|
|
52
|
+
const allKeys = getObjectKeys(obj);
|
|
58
53
|
|
|
59
54
|
for (const key of allKeys) {
|
|
60
|
-
if (key.endsWith(options.suffix)) {
|
|
61
|
-
throw new TypeError(
|
|
62
|
-
"Cannot promisify an API that has normal methods with '%s'-suffix\u000a\u000a See http://goo.gl/MqrFmX\u000a".replace(
|
|
63
|
-
"%s",
|
|
64
|
-
options.suffix
|
|
65
|
-
)
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
55
|
const value = obj[key];
|
|
69
56
|
const promisifiedKey = key + options.suffix;
|
|
70
57
|
const passesDefaultFilter =
|
|
@@ -78,6 +65,16 @@ function promisifyAll2(obj, options) {
|
|
|
78
65
|
) {
|
|
79
66
|
continue;
|
|
80
67
|
}
|
|
68
|
+
|
|
69
|
+
if (key.endsWith(options.suffix)) {
|
|
70
|
+
throw new TypeError(
|
|
71
|
+
"Cannot promisify an API that has normal methods with '%s'-suffix\u000a\u000a See http://goo.gl/MqrFmX\u000a".replace(
|
|
72
|
+
"%s",
|
|
73
|
+
options.suffix
|
|
74
|
+
)
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
81
78
|
obj[promisifiedKey] = options.promisifier(value, defaultPromisifier, {
|
|
82
79
|
context: obj,
|
|
83
80
|
copyProps: false,
|
|
@@ -110,7 +107,7 @@ function promisifyAll(target, _options) {
|
|
|
110
107
|
);
|
|
111
108
|
}
|
|
112
109
|
|
|
113
|
-
const allKeys = getObjectKeys(target
|
|
110
|
+
const allKeys = getObjectKeys(target);
|
|
114
111
|
|
|
115
112
|
for (const key of allKeys) {
|
|
116
113
|
const value = target[key];
|
|
@@ -121,7 +118,7 @@ function promisifyAll(target, _options) {
|
|
|
121
118
|
isClass(value)
|
|
122
119
|
) {
|
|
123
120
|
const proto = Object.getPrototypeOf(value);
|
|
124
|
-
if (!
|
|
121
|
+
if (!isExcludedPrototype(proto)) {
|
|
125
122
|
promisifyAll2(proto, options);
|
|
126
123
|
}
|
|
127
124
|
|
package/lib/using.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const { Disposer } = require("./disposer");
|
|
4
4
|
const { isPromise } = require("./util");
|
|
5
5
|
|
|
6
|
+
const SYM_FN_DISPOSE = Symbol("fnDispose");
|
|
6
7
|
/**
|
|
7
8
|
* @description
|
|
8
9
|
* The using function is a utility function that allows you to acquire resources,
|
|
@@ -37,10 +38,15 @@ function using(resources, handler, Promise, asArray) {
|
|
|
37
38
|
});
|
|
38
39
|
|
|
39
40
|
return Promise.map(promiseRes, async (resource) => {
|
|
40
|
-
if (
|
|
41
|
+
if (
|
|
42
|
+
resource &&
|
|
43
|
+
(resource instanceof Disposer ||
|
|
44
|
+
(resource._promise && typeof resource._data === "function"))
|
|
45
|
+
) {
|
|
41
46
|
try {
|
|
42
47
|
const res = await resource._promise;
|
|
43
48
|
resource._result = res;
|
|
49
|
+
resource[SYM_FN_DISPOSE] = resource._data;
|
|
44
50
|
} catch (error) {
|
|
45
51
|
acquisitionErrors.push(error);
|
|
46
52
|
resource._error = error;
|
|
@@ -68,18 +74,18 @@ function using(resources, handler, Promise, asArray) {
|
|
|
68
74
|
const errors = [];
|
|
69
75
|
return Promise.each(processedResources, async (resource) => {
|
|
70
76
|
// dispose all resources that were acquired without errors
|
|
71
|
-
if (
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
errors.push(error);
|
|
77
|
-
}
|
|
77
|
+
if (resource && resource[SYM_FN_DISPOSE]) {
|
|
78
|
+
try {
|
|
79
|
+
await resource[SYM_FN_DISPOSE](resource._result);
|
|
80
|
+
} catch (error) {
|
|
81
|
+
errors.push(error);
|
|
78
82
|
}
|
|
79
83
|
}
|
|
80
84
|
}).finally(() => {
|
|
81
85
|
if (errors.length > 0) {
|
|
82
|
-
Promise.___throwUncaughtError(
|
|
86
|
+
Promise.___throwUncaughtError(
|
|
87
|
+
new AggregateError(errors, "cleanup resources failed", errors)
|
|
88
|
+
);
|
|
83
89
|
}
|
|
84
90
|
});
|
|
85
91
|
};
|
|
@@ -97,26 +103,25 @@ function using(resources, handler, Promise, asArray) {
|
|
|
97
103
|
results.push(resource._result);
|
|
98
104
|
}
|
|
99
105
|
|
|
100
|
-
let
|
|
101
|
-
|
|
106
|
+
let handlerPromise;
|
|
107
|
+
|
|
102
108
|
try {
|
|
103
109
|
// now call the handler with the results
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
handlerResult = handler(...results);
|
|
108
|
-
}
|
|
110
|
+
handlerPromise = Promise.resolve(
|
|
111
|
+
asArray ? handler(results) : handler(...results)
|
|
112
|
+
);
|
|
109
113
|
} catch (error) {
|
|
110
114
|
// catch sync error from handler
|
|
111
|
-
|
|
115
|
+
handlerPromise = Promise.reject(error);
|
|
112
116
|
}
|
|
113
117
|
|
|
114
|
-
return
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
|
|
118
|
+
return handlerPromise
|
|
119
|
+
.tap(() => {
|
|
120
|
+
return disposeResources(processedResources);
|
|
121
|
+
})
|
|
122
|
+
.tapCatch(() => {
|
|
123
|
+
return disposeResources(processedResources);
|
|
124
|
+
});
|
|
120
125
|
});
|
|
121
126
|
}
|
|
122
127
|
|
package/lib/util.js
CHANGED
|
@@ -9,43 +9,34 @@
|
|
|
9
9
|
* @param {*} fn - The value to check
|
|
10
10
|
* @returns {boolean} - True if the function is a class, false otherwise
|
|
11
11
|
*/
|
|
12
|
+
const thisAssignmentPattern = /this\s*\.\s*\S+\s*=/;
|
|
12
13
|
function isClass(fn) {
|
|
13
|
-
// Early return for non-functions or null/undefined
|
|
14
|
-
if (!fn || typeof fn !== "function") return false;
|
|
15
|
-
|
|
16
|
-
// Method 1: Check for ES6 class syntax
|
|
17
|
-
// This detects class declarations and class expressions
|
|
18
14
|
try {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
if (typeof fn === "function") {
|
|
16
|
+
const keys = Object.getOwnPropertyNames(fn.prototype);
|
|
17
|
+
|
|
18
|
+
const fnStr = fn.toString();
|
|
19
|
+
const es6Class = fnStr.startsWith("class ") || /^class\s+/.test(fnStr);
|
|
20
|
+
const hasMethods = keys.length > 1;
|
|
21
|
+
const hasMethodsOtherThanConstructor =
|
|
22
|
+
keys.length > 0 && !(keys.length === 1 && keys[0] === "constructor");
|
|
23
|
+
const hasThisAssignmentAndStaticMethods =
|
|
24
|
+
thisAssignmentPattern.test(fnStr) &&
|
|
25
|
+
Object.getOwnPropertyNames(fn).length > 0;
|
|
26
|
+
|
|
27
|
+
if (
|
|
28
|
+
es6Class ||
|
|
29
|
+
hasMethods ||
|
|
30
|
+
hasMethodsOtherThanConstructor ||
|
|
31
|
+
hasThisAssignmentAndStaticMethods
|
|
32
|
+
) {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
22
35
|
}
|
|
36
|
+
return false;
|
|
23
37
|
} catch (e) {
|
|
24
|
-
// Ignore errors that might occur when calling toString()
|
|
25
|
-
// Some objects might have custom toString implementations that throw
|
|
26
38
|
return false;
|
|
27
39
|
}
|
|
28
|
-
|
|
29
|
-
// Method 2: Check for constructor functions (ES5 class pattern)
|
|
30
|
-
// A proper constructor has its .prototype.constructor pointing back to itself
|
|
31
|
-
if (fn.prototype && fn.prototype.constructor === fn) {
|
|
32
|
-
// Additional validation to filter out regular functions
|
|
33
|
-
// that happen to have the correct prototype structure
|
|
34
|
-
|
|
35
|
-
// Check if the prototype has any methods other than constructor
|
|
36
|
-
// This is a strong indicator of a class-like structure
|
|
37
|
-
const hasOwnMethods = Object.getOwnPropertyNames(fn.prototype).some(
|
|
38
|
-
(name) =>
|
|
39
|
-
name !== "constructor" && typeof fn.prototype[name] === "function"
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
// If it has prototype methods OR has static properties/methods
|
|
43
|
-
// Either condition suggests it's being used as a class
|
|
44
|
-
return hasOwnMethods || Object.getOwnPropertyNames(fn).length > 0;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Not a class by any of our detection methods
|
|
48
|
-
return false;
|
|
49
40
|
}
|
|
50
41
|
|
|
51
42
|
const rident = /^[a-z$_][a-z$_0-9]*$/i;
|
|
@@ -127,12 +118,25 @@ function isPromise(obj) {
|
|
|
127
118
|
);
|
|
128
119
|
}
|
|
129
120
|
|
|
121
|
+
// istanbul ignore next
|
|
122
|
+
const emptyFatArrow = () => {};
|
|
123
|
+
// istanbul ignore next
|
|
124
|
+
const emptyFunction = function () {};
|
|
125
|
+
|
|
130
126
|
const defaultExcluded = [
|
|
131
127
|
Object.getPrototypeOf(Array), // Array.prototype
|
|
132
128
|
Object.getPrototypeOf(Object), // Object.prototype
|
|
133
129
|
Object.getPrototypeOf(Function), // Function.prototype
|
|
130
|
+
Object.getPrototypeOf([]),
|
|
131
|
+
Object.getPrototypeOf({}),
|
|
132
|
+
Object.getPrototypeOf(emptyFatArrow),
|
|
133
|
+
Object.getPrototypeOf(emptyFunction),
|
|
134
134
|
];
|
|
135
135
|
|
|
136
|
+
function isExcludedPrototype(proto) {
|
|
137
|
+
return defaultExcluded.includes(proto);
|
|
138
|
+
}
|
|
139
|
+
|
|
136
140
|
/**
|
|
137
141
|
* Gets all property keys from an object and its prototype chain, excluding standard
|
|
138
142
|
* prototypes like Object.prototype, Array.prototype, and Function.prototype
|
|
@@ -187,3 +191,4 @@ module.exports.isPromisified = isPromisified;
|
|
|
187
191
|
module.exports.isPromise = isPromise;
|
|
188
192
|
module.exports.triggerUncaughtException = triggerUncaughtException;
|
|
189
193
|
module.exports.getObjectKeys = getObjectKeys;
|
|
194
|
+
module.exports.isExcludedPrototype = isExcludedPrototype;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aveazul",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Bluebird-like APIs in extended native Promise",
|
|
5
5
|
"main": "lib/aveazul.js",
|
|
6
6
|
"homepage": "https://github.com/jchip/aveazul",
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
"test:coverage": "jest test --coverage",
|
|
12
12
|
"test:bluebird": "USE_BLUEBIRD=true jest test",
|
|
13
13
|
"test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand --no-coverage",
|
|
14
|
-
"test:debug:bluebird": "USE_BLUEBIRD=true node --inspect-brk node_modules/.bin/jest --runInBand --no-coverage"
|
|
14
|
+
"test:debug:bluebird": "USE_BLUEBIRD=true node --inspect-brk node_modules/.bin/jest --runInBand --no-coverage",
|
|
15
|
+
"jest": "jest --no-coverage",
|
|
16
|
+
"jest:bluebird": "USE_BLUEBIRD=true jest --no-coverage"
|
|
15
17
|
},
|
|
16
18
|
"author": "Joel Chen",
|
|
17
19
|
"files": [
|