kareem 2.3.2 → 2.3.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/CHANGELOG.md +10 -0
- package/index.js +54 -62
- package/package.json +3 -3
- package/test/wrap.test.js +24 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
<a name="2.3.4"></a>
|
|
4
|
+
## 2.3.4 (2022-02-10)
|
|
5
|
+
|
|
6
|
+
* perf: various performance improvements #27 #24 #23 #22 #21 #20
|
|
7
|
+
|
|
8
|
+
<a name="2.3.3"></a>
|
|
9
|
+
## 2.3.3 (2021-12-26)
|
|
10
|
+
|
|
11
|
+
* fix: handle sync errors in `wrap()`
|
|
12
|
+
|
|
3
13
|
<a name="2.3.2"></a>
|
|
4
14
|
## 2.3.2 (2020-12-08)
|
|
5
15
|
|
package/index.js
CHANGED
|
@@ -10,7 +10,7 @@ Kareem.prototype.execPre = function(name, context, args, callback) {
|
|
|
10
10
|
callback = args;
|
|
11
11
|
args = [];
|
|
12
12
|
}
|
|
13
|
-
var pres =
|
|
13
|
+
var pres = this._pres.get(name) || [];
|
|
14
14
|
var numPres = pres.length;
|
|
15
15
|
var numAsyncPres = pres.numAsync || 0;
|
|
16
16
|
var currentPre = 0;
|
|
@@ -19,7 +19,7 @@ Kareem.prototype.execPre = function(name, context, args, callback) {
|
|
|
19
19
|
var $args = args;
|
|
20
20
|
|
|
21
21
|
if (!numPres) {
|
|
22
|
-
return
|
|
22
|
+
return nextTick(function() {
|
|
23
23
|
callback(null);
|
|
24
24
|
});
|
|
25
25
|
}
|
|
@@ -57,24 +57,24 @@ Kareem.prototype.execPre = function(name, context, args, callback) {
|
|
|
57
57
|
|
|
58
58
|
callMiddlewareFunction(pre.fn, context, args, args[0]);
|
|
59
59
|
} else {
|
|
60
|
-
let
|
|
60
|
+
let maybePromiseLike = null;
|
|
61
61
|
try {
|
|
62
|
-
|
|
62
|
+
maybePromiseLike = pre.fn.call(context);
|
|
63
63
|
} catch (err) {
|
|
64
64
|
if (err != null) {
|
|
65
65
|
return callback(err);
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
if (
|
|
70
|
-
|
|
69
|
+
if (isPromiseLike(maybePromiseLike)) {
|
|
70
|
+
maybePromiseLike.then(() => _next(), err => _next(err));
|
|
71
71
|
} else {
|
|
72
72
|
if (++currentPre >= numPres) {
|
|
73
73
|
if (asyncPresLeft > 0) {
|
|
74
74
|
// Leave parallel hooks to run
|
|
75
75
|
return;
|
|
76
76
|
} else {
|
|
77
|
-
return
|
|
77
|
+
return nextTick(function() {
|
|
78
78
|
callback(null);
|
|
79
79
|
});
|
|
80
80
|
}
|
|
@@ -109,7 +109,7 @@ Kareem.prototype.execPre = function(name, context, args, callback) {
|
|
|
109
109
|
};
|
|
110
110
|
|
|
111
111
|
Kareem.prototype.execPreSync = function(name, context, args) {
|
|
112
|
-
var pres =
|
|
112
|
+
var pres = this._pres.get(name) || [];
|
|
113
113
|
var numPres = pres.length;
|
|
114
114
|
|
|
115
115
|
for (var i = 0; i < numPres; ++i) {
|
|
@@ -122,7 +122,7 @@ Kareem.prototype.execPost = function(name, context, args, options, callback) {
|
|
|
122
122
|
callback = options;
|
|
123
123
|
options = null;
|
|
124
124
|
}
|
|
125
|
-
var posts =
|
|
125
|
+
var posts = this._posts.get(name) || [];
|
|
126
126
|
var numPosts = posts.length;
|
|
127
127
|
var currentPost = 0;
|
|
128
128
|
|
|
@@ -132,7 +132,7 @@ Kareem.prototype.execPost = function(name, context, args, options, callback) {
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
if (!numPosts) {
|
|
135
|
-
return
|
|
135
|
+
return nextTick(function() {
|
|
136
136
|
callback.apply(null, [firstError].concat(args));
|
|
137
137
|
});
|
|
138
138
|
}
|
|
@@ -151,7 +151,7 @@ Kareem.prototype.execPost = function(name, context, args, options, callback) {
|
|
|
151
151
|
|
|
152
152
|
if (firstError) {
|
|
153
153
|
if (post.length === numArgs + 2) {
|
|
154
|
-
|
|
154
|
+
const _cb = decorateNextFn(function(error) {
|
|
155
155
|
if (error) {
|
|
156
156
|
firstError = error;
|
|
157
157
|
}
|
|
@@ -194,23 +194,23 @@ Kareem.prototype.execPost = function(name, context, args, options, callback) {
|
|
|
194
194
|
callMiddlewareFunction(post, context, newArgs.concat([_cb]), _cb);
|
|
195
195
|
} else {
|
|
196
196
|
let error;
|
|
197
|
-
let
|
|
197
|
+
let maybePromiseLike;
|
|
198
198
|
try {
|
|
199
|
-
|
|
199
|
+
maybePromiseLike = post.apply(context, newArgs);
|
|
200
200
|
} catch (err) {
|
|
201
201
|
error = err;
|
|
202
202
|
firstError = err;
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
-
if (
|
|
206
|
-
return
|
|
205
|
+
if (isPromiseLike(maybePromiseLike)) {
|
|
206
|
+
return maybePromiseLike.then(() => _cb(), err => _cb(err));
|
|
207
207
|
}
|
|
208
208
|
|
|
209
209
|
if (++currentPost >= numPosts) {
|
|
210
210
|
return callback.apply(null, [error].concat(args));
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
-
next(
|
|
213
|
+
next();
|
|
214
214
|
}
|
|
215
215
|
}
|
|
216
216
|
};
|
|
@@ -219,7 +219,7 @@ Kareem.prototype.execPost = function(name, context, args, options, callback) {
|
|
|
219
219
|
};
|
|
220
220
|
|
|
221
221
|
Kareem.prototype.execPostSync = function(name, context, args) {
|
|
222
|
-
const posts =
|
|
222
|
+
const posts = this._posts.get(name) || [];
|
|
223
223
|
const numPosts = posts.length;
|
|
224
224
|
|
|
225
225
|
for (let i = 0; i < numPosts; ++i) {
|
|
@@ -242,22 +242,18 @@ Kareem.prototype.createWrapperSync = function(name, fn) {
|
|
|
242
242
|
|
|
243
243
|
function _handleWrapError(instance, error, name, context, args, options, callback) {
|
|
244
244
|
if (options.useErrorHandlers) {
|
|
245
|
-
|
|
246
|
-
return instance.execPost(name, context, args, _options, function(error) {
|
|
245
|
+
return instance.execPost(name, context, args, { error: error }, function(error) {
|
|
247
246
|
return typeof callback === 'function' && callback(error);
|
|
248
247
|
});
|
|
249
248
|
} else {
|
|
250
|
-
return typeof callback === 'function'
|
|
251
|
-
callback(error) :
|
|
252
|
-
undefined;
|
|
249
|
+
return typeof callback === 'function' && callback(error);
|
|
253
250
|
}
|
|
254
251
|
}
|
|
255
252
|
|
|
256
253
|
Kareem.prototype.wrap = function(name, fn, context, args, options) {
|
|
257
254
|
const lastArg = (args.length > 0 ? args[args.length - 1] : null);
|
|
258
|
-
const argsWithoutCb =
|
|
259
|
-
|
|
260
|
-
args;
|
|
255
|
+
const argsWithoutCb = Array.from(args);
|
|
256
|
+
typeof lastArg === 'function' && argsWithoutCb.pop();
|
|
261
257
|
const _this = this;
|
|
262
258
|
|
|
263
259
|
options = options || {};
|
|
@@ -274,12 +270,16 @@ Kareem.prototype.wrap = function(name, fn, context, args, options) {
|
|
|
274
270
|
options, lastArg);
|
|
275
271
|
}
|
|
276
272
|
|
|
277
|
-
const end = (typeof lastArg === 'function' ? args.length - 1 : args.length);
|
|
278
273
|
const numParameters = fn.length;
|
|
279
|
-
|
|
274
|
+
let ret;
|
|
275
|
+
try {
|
|
276
|
+
ret = fn.apply(context, argsWithoutCb.concat(_cb));
|
|
277
|
+
} catch (err) {
|
|
278
|
+
return _cb(err);
|
|
279
|
+
}
|
|
280
280
|
|
|
281
281
|
if (checkForPromise) {
|
|
282
|
-
if (ret
|
|
282
|
+
if (isPromiseLike(ret)) {
|
|
283
283
|
// Thenable, use it
|
|
284
284
|
return ret.then(
|
|
285
285
|
res => _cb(null, res),
|
|
@@ -289,14 +289,14 @@ Kareem.prototype.wrap = function(name, fn, context, args, options) {
|
|
|
289
289
|
|
|
290
290
|
// If `fn()` doesn't have a callback argument and doesn't return a
|
|
291
291
|
// promise, assume it is sync
|
|
292
|
-
if (numParameters <
|
|
292
|
+
if (numParameters < argsWithoutCb.length + 1) {
|
|
293
293
|
return _cb(null, ret);
|
|
294
294
|
}
|
|
295
295
|
}
|
|
296
296
|
|
|
297
297
|
function _cb() {
|
|
298
|
-
const
|
|
299
|
-
|
|
298
|
+
const argsWithoutError = Array.from(arguments);
|
|
299
|
+
argsWithoutError.shift();
|
|
300
300
|
if (options.nullResultByDefault && argsWithoutError.length === 0) {
|
|
301
301
|
argsWithoutError.push(null);
|
|
302
302
|
}
|
|
@@ -306,15 +306,12 @@ Kareem.prototype.wrap = function(name, fn, context, args, options) {
|
|
|
306
306
|
argsWithoutError, options, lastArg);
|
|
307
307
|
} else {
|
|
308
308
|
_this.execPost(name, context, argsWithoutError, function() {
|
|
309
|
-
if (
|
|
310
|
-
return
|
|
311
|
-
lastArg(arguments[0]) :
|
|
312
|
-
undefined;
|
|
309
|
+
if (lastArg === null) {
|
|
310
|
+
return;
|
|
313
311
|
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
lastArg.apply(context, arguments)
|
|
317
|
-
undefined;
|
|
312
|
+
arguments[0]
|
|
313
|
+
? lastArg(arguments[0])
|
|
314
|
+
: lastArg.apply(context, arguments)
|
|
318
315
|
});
|
|
319
316
|
}
|
|
320
317
|
}
|
|
@@ -367,28 +364,26 @@ Kareem.prototype.createWrapper = function(name, fn, context, options) {
|
|
|
367
364
|
// Fast path: if there's no hooks for this function, just return the
|
|
368
365
|
// function wrapped in a nextTick()
|
|
369
366
|
return function() {
|
|
370
|
-
|
|
367
|
+
nextTick(() => fn.apply(this, arguments));
|
|
371
368
|
};
|
|
372
369
|
}
|
|
373
370
|
return function() {
|
|
374
371
|
var _context = context || this;
|
|
375
|
-
|
|
376
|
-
_this.wrap(name, fn, _context, args, options);
|
|
372
|
+
_this.wrap(name, fn, _context, Array.from(arguments), options);
|
|
377
373
|
};
|
|
378
374
|
};
|
|
379
375
|
|
|
380
376
|
Kareem.prototype.pre = function(name, isAsync, fn, error, unshift) {
|
|
381
377
|
let options = {};
|
|
382
|
-
if (typeof isAsync === 'object' && isAsync
|
|
378
|
+
if (typeof isAsync === 'object' && isAsync !== null) {
|
|
383
379
|
options = isAsync;
|
|
384
380
|
isAsync = options.isAsync;
|
|
385
381
|
} else if (typeof arguments[1] !== 'boolean') {
|
|
386
|
-
error = fn;
|
|
387
382
|
fn = isAsync;
|
|
388
383
|
isAsync = false;
|
|
389
384
|
}
|
|
390
385
|
|
|
391
|
-
const pres =
|
|
386
|
+
const pres = this._pres.get(name) || [];
|
|
392
387
|
this._pres.set(name, pres);
|
|
393
388
|
|
|
394
389
|
if (isAsync) {
|
|
@@ -410,7 +405,7 @@ Kareem.prototype.pre = function(name, isAsync, fn, error, unshift) {
|
|
|
410
405
|
};
|
|
411
406
|
|
|
412
407
|
Kareem.prototype.post = function(name, options, fn, unshift) {
|
|
413
|
-
const hooks =
|
|
408
|
+
const hooks = this._posts.get(name) || [];
|
|
414
409
|
|
|
415
410
|
if (typeof options === 'function') {
|
|
416
411
|
unshift = !!fn;
|
|
@@ -451,7 +446,7 @@ Kareem.prototype.merge = function(other, clone) {
|
|
|
451
446
|
var ret = clone ? this.clone() : this;
|
|
452
447
|
|
|
453
448
|
for (let key of other._pres.keys()) {
|
|
454
|
-
const sourcePres =
|
|
449
|
+
const sourcePres = ret._pres.get(key) || [];
|
|
455
450
|
const deduplicated = other._pres.get(key).
|
|
456
451
|
// Deduplicate based on `fn`
|
|
457
452
|
filter(p => sourcePres.map(_p => _p.fn).indexOf(p.fn) === -1);
|
|
@@ -461,7 +456,7 @@ Kareem.prototype.merge = function(other, clone) {
|
|
|
461
456
|
ret._pres.set(key, combined);
|
|
462
457
|
}
|
|
463
458
|
for (let key of other._posts.keys()) {
|
|
464
|
-
const sourcePosts =
|
|
459
|
+
const sourcePosts = ret._posts.get(key) || [];
|
|
465
460
|
const deduplicated = other._posts.get(key).
|
|
466
461
|
filter(p => sourcePosts.indexOf(p) === -1);
|
|
467
462
|
ret._posts.set(key, sourcePosts.concat(deduplicated));
|
|
@@ -470,28 +465,21 @@ Kareem.prototype.merge = function(other, clone) {
|
|
|
470
465
|
return ret;
|
|
471
466
|
};
|
|
472
467
|
|
|
473
|
-
function get(map, key, def) {
|
|
474
|
-
if (map.has(key)) {
|
|
475
|
-
return map.get(key);
|
|
476
|
-
}
|
|
477
|
-
return def;
|
|
478
|
-
}
|
|
479
|
-
|
|
480
468
|
function callMiddlewareFunction(fn, context, args, next) {
|
|
481
|
-
let
|
|
469
|
+
let maybePromiseLike;
|
|
482
470
|
try {
|
|
483
|
-
|
|
471
|
+
maybePromiseLike = fn.apply(context, args);
|
|
484
472
|
} catch (error) {
|
|
485
473
|
return next(error);
|
|
486
474
|
}
|
|
487
475
|
|
|
488
|
-
if (
|
|
489
|
-
|
|
476
|
+
if (isPromiseLike(maybePromiseLike)) {
|
|
477
|
+
maybePromiseLike.then(() => next(), err => next(err));
|
|
490
478
|
}
|
|
491
479
|
}
|
|
492
480
|
|
|
493
|
-
function
|
|
494
|
-
return v
|
|
481
|
+
function isPromiseLike(v) {
|
|
482
|
+
return (typeof v === 'object' && v !== null && typeof v.then === 'function');
|
|
495
483
|
}
|
|
496
484
|
|
|
497
485
|
function decorateNextFn(fn) {
|
|
@@ -505,8 +493,12 @@ function decorateNextFn(fn) {
|
|
|
505
493
|
called = true;
|
|
506
494
|
// Make sure to clear the stack so try/catch doesn't catch errors
|
|
507
495
|
// in subsequent middleware
|
|
508
|
-
return
|
|
496
|
+
return nextTick(() => fn.apply(_this, arguments));
|
|
509
497
|
};
|
|
510
498
|
}
|
|
511
499
|
|
|
500
|
+
const nextTick = typeof process === 'object' && process !== null && process.nextTick || function nextTick(cb) {
|
|
501
|
+
setTimeout(cb, 0);
|
|
502
|
+
}
|
|
503
|
+
|
|
512
504
|
module.exports = Kareem;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kareem",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.5",
|
|
4
4
|
"description": "Next-generation take on pre/post function hooks",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"acquit": "1.x",
|
|
16
16
|
"acquit-ignore": "0.1.x",
|
|
17
|
-
"
|
|
18
|
-
"
|
|
17
|
+
"mocha": "9.2.0",
|
|
18
|
+
"nyc": "15.1.0"
|
|
19
19
|
},
|
|
20
20
|
"author": "Valeri Karpov <val@karpov.io>",
|
|
21
21
|
"license": "Apache-2.0"
|
package/test/wrap.test.js
CHANGED
|
@@ -319,6 +319,30 @@ describe('wrap()', function() {
|
|
|
319
319
|
25);
|
|
320
320
|
});
|
|
321
321
|
|
|
322
|
+
it('catches sync errors', function(done) {
|
|
323
|
+
hooks.pre('cook', function(done) {
|
|
324
|
+
done();
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
hooks.post('cook', function(callback) {
|
|
328
|
+
callback();
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
var args = [];
|
|
332
|
+
args.push(function(error) {
|
|
333
|
+
assert.equal(error.message, 'oops!');
|
|
334
|
+
done();
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
hooks.wrap(
|
|
338
|
+
'cook',
|
|
339
|
+
function() {
|
|
340
|
+
throw new Error('oops!');
|
|
341
|
+
},
|
|
342
|
+
null,
|
|
343
|
+
args);
|
|
344
|
+
});
|
|
345
|
+
|
|
322
346
|
it('sync wrappers', function() {
|
|
323
347
|
var calledPre = 0;
|
|
324
348
|
var calledFn = 0;
|