kareem 2.3.3 → 2.4.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,30 @@
1
+ name: Test
2
+ on:
3
+ pull_request:
4
+ push:
5
+ permissions:
6
+ contents: read
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ${{ matrix.os }}
11
+ strategy:
12
+ fail-fast: false
13
+ matrix:
14
+ node: [12, 14, 16, 18]
15
+ os: [ubuntu-20.04]
16
+ include:
17
+ - os: ubuntu-20.04
18
+ mongo-os: ubuntu2004
19
+ name: Node ${{ matrix.node }}
20
+ steps:
21
+ - uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846 # v3
22
+
23
+ - name: Setup node
24
+ uses: actions/setup-node@5b52f097d36d4b0b2f94ed6de710023fbb8b2236 # v3.1.0
25
+ with:
26
+ node-version: ${{ matrix.node }}
27
+
28
+ - run: npm install
29
+
30
+ - run: npm test
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ <a name="2.4.0"></a>
4
+ ## 2.4.0 (2022-06-13)
5
+
6
+ * feat: add `overwriteResult()` and `skipWrappedFunction()` for more advanced control flow
7
+
8
+ <a name="2.3.4"></a>
9
+ ## 2.3.4 (2022-02-10)
10
+
11
+ * perf: various performance improvements #27 #24 #23 #22 #21 #20
12
+
3
13
  <a name="2.3.3"></a>
4
14
  ## 2.3.3 (2021-12-26)
5
15
 
package/index.js CHANGED
@@ -5,21 +5,38 @@ function Kareem() {
5
5
  this._posts = new Map();
6
6
  }
7
7
 
8
+ Kareem.skipWrappedFunction = function skipWrappedFunction() {
9
+ if (!(this instanceof Kareem.skipWrappedFunction)) {
10
+ return new Kareem.skipWrappedFunction(...arguments);
11
+ }
12
+
13
+ this.args = [...arguments];
14
+ };
15
+
16
+ Kareem.overwriteResult = function overwriteResult() {
17
+ if (!(this instanceof Kareem.overwriteResult)) {
18
+ return new Kareem.overwriteResult(...arguments);
19
+ }
20
+
21
+ this.args = [...arguments];
22
+ };
23
+
8
24
  Kareem.prototype.execPre = function(name, context, args, callback) {
9
25
  if (arguments.length === 3) {
10
26
  callback = args;
11
27
  args = [];
12
28
  }
13
- var pres = get(this._pres, name, []);
29
+ var pres = this._pres.get(name) || [];
14
30
  var numPres = pres.length;
15
31
  var numAsyncPres = pres.numAsync || 0;
16
32
  var currentPre = 0;
17
33
  var asyncPresLeft = numAsyncPres;
18
34
  var done = false;
19
35
  var $args = args;
36
+ var shouldSkipWrappedFunction = null;
20
37
 
21
38
  if (!numPres) {
22
- return process.nextTick(function() {
39
+ return nextTick(function() {
23
40
  callback(null);
24
41
  });
25
42
  }
@@ -38,11 +55,15 @@ Kareem.prototype.execPre = function(name, context, args, callback) {
38
55
  if (done) {
39
56
  return;
40
57
  }
41
- done = true;
42
- return callback(error);
58
+ if (error instanceof Kareem.skipWrappedFunction) {
59
+ shouldSkipWrappedFunction = error;
60
+ } else {
61
+ done = true;
62
+ return callback(error);
63
+ }
43
64
  }
44
65
  if (--asyncPresLeft === 0 && currentPre >= numPres) {
45
- return callback(null);
66
+ return callback(shouldSkipWrappedFunction);
46
67
  }
47
68
  })
48
69
  ];
@@ -57,25 +78,25 @@ Kareem.prototype.execPre = function(name, context, args, callback) {
57
78
 
58
79
  callMiddlewareFunction(pre.fn, context, args, args[0]);
59
80
  } else {
60
- let maybePromise = null;
81
+ let maybePromiseLike = null;
61
82
  try {
62
- maybePromise = pre.fn.call(context);
83
+ maybePromiseLike = pre.fn.call(context);
63
84
  } catch (err) {
64
85
  if (err != null) {
65
86
  return callback(err);
66
87
  }
67
88
  }
68
89
 
69
- if (isPromise(maybePromise)) {
70
- maybePromise.then(() => _next(), err => _next(err));
90
+ if (isPromiseLike(maybePromiseLike)) {
91
+ maybePromiseLike.then(() => _next(), err => _next(err));
71
92
  } else {
72
93
  if (++currentPre >= numPres) {
73
94
  if (asyncPresLeft > 0) {
74
95
  // Leave parallel hooks to run
75
96
  return;
76
97
  } else {
77
- return process.nextTick(function() {
78
- callback(null);
98
+ return nextTick(function() {
99
+ callback(shouldSkipWrappedFunction);
79
100
  });
80
101
  }
81
102
  }
@@ -91,8 +112,12 @@ Kareem.prototype.execPre = function(name, context, args, callback) {
91
112
  if (done) {
92
113
  return;
93
114
  }
94
- done = true;
95
- return callback(error);
115
+ if (error instanceof Kareem.skipWrappedFunction) {
116
+ shouldSkipWrappedFunction = error;
117
+ } else {
118
+ done = true;
119
+ return callback(error);
120
+ }
96
121
  }
97
122
 
98
123
  if (++currentPre >= numPres) {
@@ -100,7 +125,7 @@ Kareem.prototype.execPre = function(name, context, args, callback) {
100
125
  // Leave parallel hooks to run
101
126
  return;
102
127
  } else {
103
- return callback(null);
128
+ return callback(shouldSkipWrappedFunction);
104
129
  }
105
130
  }
106
131
 
@@ -109,7 +134,7 @@ Kareem.prototype.execPre = function(name, context, args, callback) {
109
134
  };
110
135
 
111
136
  Kareem.prototype.execPreSync = function(name, context, args) {
112
- var pres = get(this._pres, name, []);
137
+ var pres = this._pres.get(name) || [];
113
138
  var numPres = pres.length;
114
139
 
115
140
  for (var i = 0; i < numPres; ++i) {
@@ -122,7 +147,7 @@ Kareem.prototype.execPost = function(name, context, args, options, callback) {
122
147
  callback = options;
123
148
  options = null;
124
149
  }
125
- var posts = get(this._posts, name, []);
150
+ var posts = this._posts.get(name) || [];
126
151
  var numPosts = posts.length;
127
152
  var currentPost = 0;
128
153
 
@@ -132,7 +157,7 @@ Kareem.prototype.execPost = function(name, context, args, options, callback) {
132
157
  }
133
158
 
134
159
  if (!numPosts) {
135
- return process.nextTick(function() {
160
+ return nextTick(function() {
136
161
  callback.apply(null, [firstError].concat(args));
137
162
  });
138
163
  }
@@ -151,8 +176,15 @@ Kareem.prototype.execPost = function(name, context, args, options, callback) {
151
176
 
152
177
  if (firstError) {
153
178
  if (post.length === numArgs + 2) {
154
- var _cb = decorateNextFn(function(error) {
179
+ const _cb = decorateNextFn(function(error) {
155
180
  if (error) {
181
+ if (error instanceof Kareem.overwriteResult) {
182
+ args = error.args;
183
+ if (++currentPost >= numPosts) {
184
+ return callback.call(null, firstError);
185
+ }
186
+ return next();
187
+ }
156
188
  firstError = error;
157
189
  }
158
190
  if (++currentPost >= numPosts) {
@@ -172,6 +204,13 @@ Kareem.prototype.execPost = function(name, context, args, options, callback) {
172
204
  } else {
173
205
  const _cb = decorateNextFn(function(error) {
174
206
  if (error) {
207
+ if (error instanceof Kareem.overwriteResult) {
208
+ args = error.args;
209
+ if (++currentPost >= numPosts) {
210
+ return callback.apply(null, [null].concat(args));
211
+ }
212
+ return next();
213
+ }
175
214
  firstError = error;
176
215
  return next();
177
216
  }
@@ -194,23 +233,27 @@ Kareem.prototype.execPost = function(name, context, args, options, callback) {
194
233
  callMiddlewareFunction(post, context, newArgs.concat([_cb]), _cb);
195
234
  } else {
196
235
  let error;
197
- let maybePromise;
236
+ let maybePromiseLike;
198
237
  try {
199
- maybePromise = post.apply(context, newArgs);
238
+ maybePromiseLike = post.apply(context, newArgs);
200
239
  } catch (err) {
201
240
  error = err;
202
241
  firstError = err;
203
242
  }
204
243
 
205
- if (isPromise(maybePromise)) {
206
- return maybePromise.then(() => _cb(), err => _cb(err));
244
+ if (isPromiseLike(maybePromiseLike)) {
245
+ return maybePromiseLike.then((res) => _cb(res), err => _cb(err));
246
+ }
247
+
248
+ if (maybePromiseLike instanceof Kareem.overwriteResult) {
249
+ args = maybePromiseLike.args;
207
250
  }
208
251
 
209
252
  if (++currentPost >= numPosts) {
210
253
  return callback.apply(null, [error].concat(args));
211
254
  }
212
255
 
213
- next(error);
256
+ next();
214
257
  }
215
258
  }
216
259
  };
@@ -219,12 +262,17 @@ Kareem.prototype.execPost = function(name, context, args, options, callback) {
219
262
  };
220
263
 
221
264
  Kareem.prototype.execPostSync = function(name, context, args) {
222
- const posts = get(this._posts, name, []);
265
+ const posts = this._posts.get(name) || [];
223
266
  const numPosts = posts.length;
224
267
 
225
268
  for (let i = 0; i < numPosts; ++i) {
226
- posts[i].fn.apply(context, args || []);
269
+ const res = posts[i].fn.apply(context, args || []);
270
+ if (res instanceof Kareem.overwriteResult) {
271
+ args = res.args;
272
+ }
227
273
  }
274
+
275
+ return args;
228
276
  };
229
277
 
230
278
  Kareem.prototype.createWrapperSync = function(name, fn) {
@@ -234,37 +282,33 @@ Kareem.prototype.createWrapperSync = function(name, fn) {
234
282
 
235
283
  var toReturn = fn.apply(this, arguments);
236
284
 
237
- kareem.execPostSync(name, this, [toReturn]);
285
+ const result = kareem.execPostSync(name, this, [toReturn]);
238
286
 
239
- return toReturn;
287
+ return result[0];
240
288
  };
241
289
  }
242
290
 
243
291
  function _handleWrapError(instance, error, name, context, args, options, callback) {
244
292
  if (options.useErrorHandlers) {
245
- var _options = { error: error };
246
- return instance.execPost(name, context, args, _options, function(error) {
293
+ return instance.execPost(name, context, args, { error: error }, function(error) {
247
294
  return typeof callback === 'function' && callback(error);
248
295
  });
249
296
  } else {
250
- return typeof callback === 'function' ?
251
- callback(error) :
252
- undefined;
297
+ return typeof callback === 'function' && callback(error);
253
298
  }
254
299
  }
255
300
 
256
301
  Kareem.prototype.wrap = function(name, fn, context, args, options) {
257
302
  const lastArg = (args.length > 0 ? args[args.length - 1] : null);
258
- const argsWithoutCb = typeof lastArg === 'function' ?
259
- args.slice(0, args.length - 1) :
260
- args;
303
+ let argsWithoutCb = Array.from(args);
304
+ typeof lastArg === 'function' && argsWithoutCb.pop();
261
305
  const _this = this;
262
306
 
263
307
  options = options || {};
264
308
  const checkForPromise = options.checkForPromise;
265
309
 
266
310
  this.execPre(name, context, args, function(error) {
267
- if (error) {
311
+ if (error && !(error instanceof Kareem.skipWrappedFunction)) {
268
312
  const numCallbackParams = options.numCallbackParams || 0;
269
313
  const errorArgs = options.contextParameter ? [context] : [];
270
314
  for (var i = errorArgs.length; i < numCallbackParams; ++i) {
@@ -274,17 +318,22 @@ Kareem.prototype.wrap = function(name, fn, context, args, options) {
274
318
  options, lastArg);
275
319
  }
276
320
 
277
- const end = (typeof lastArg === 'function' ? args.length - 1 : args.length);
278
321
  const numParameters = fn.length;
279
322
  let ret;
280
- try {
281
- ret = fn.apply(context, args.slice(0, end).concat(_cb));
282
- } catch (err) {
283
- return _cb(err);
323
+
324
+ if (error instanceof Kareem.skipWrappedFunction) {
325
+ ret = error.args[0];
326
+ return _cb(null, ...error.args);
327
+ } else {
328
+ try {
329
+ ret = fn.apply(context, argsWithoutCb.concat(_cb));
330
+ } catch (err) {
331
+ return _cb(err);
332
+ }
284
333
  }
285
334
 
286
335
  if (checkForPromise) {
287
- if (ret != null && typeof ret.then === 'function') {
336
+ if (isPromiseLike(ret)) {
288
337
  // Thenable, use it
289
338
  return ret.then(
290
339
  res => _cb(null, res),
@@ -294,14 +343,14 @@ Kareem.prototype.wrap = function(name, fn, context, args, options) {
294
343
 
295
344
  // If `fn()` doesn't have a callback argument and doesn't return a
296
345
  // promise, assume it is sync
297
- if (numParameters < end + 1) {
346
+ if (numParameters < argsWithoutCb.length + 1) {
298
347
  return _cb(null, ret);
299
348
  }
300
349
  }
301
350
 
302
351
  function _cb() {
303
- const args = arguments;
304
- const argsWithoutError = Array.prototype.slice.call(arguments, 1);
352
+ const argsWithoutError = Array.from(arguments);
353
+ argsWithoutError.shift();
305
354
  if (options.nullResultByDefault && argsWithoutError.length === 0) {
306
355
  argsWithoutError.push(null);
307
356
  }
@@ -311,15 +360,12 @@ Kareem.prototype.wrap = function(name, fn, context, args, options) {
311
360
  argsWithoutError, options, lastArg);
312
361
  } else {
313
362
  _this.execPost(name, context, argsWithoutError, function() {
314
- if (arguments[0]) {
315
- return typeof lastArg === 'function' ?
316
- lastArg(arguments[0]) :
317
- undefined;
363
+ if (lastArg === null) {
364
+ return;
318
365
  }
319
-
320
- return typeof lastArg === 'function' ?
321
- lastArg.apply(context, arguments) :
322
- undefined;
366
+ arguments[0]
367
+ ? lastArg(arguments[0])
368
+ : lastArg.apply(context, arguments)
323
369
  });
324
370
  }
325
371
  }
@@ -372,28 +418,26 @@ Kareem.prototype.createWrapper = function(name, fn, context, options) {
372
418
  // Fast path: if there's no hooks for this function, just return the
373
419
  // function wrapped in a nextTick()
374
420
  return function() {
375
- process.nextTick(() => fn.apply(this, arguments));
421
+ nextTick(() => fn.apply(this, arguments));
376
422
  };
377
423
  }
378
424
  return function() {
379
425
  var _context = context || this;
380
- var args = Array.prototype.slice.call(arguments);
381
- _this.wrap(name, fn, _context, args, options);
426
+ _this.wrap(name, fn, _context, Array.from(arguments), options);
382
427
  };
383
428
  };
384
429
 
385
430
  Kareem.prototype.pre = function(name, isAsync, fn, error, unshift) {
386
431
  let options = {};
387
- if (typeof isAsync === 'object' && isAsync != null) {
432
+ if (typeof isAsync === 'object' && isAsync !== null) {
388
433
  options = isAsync;
389
434
  isAsync = options.isAsync;
390
435
  } else if (typeof arguments[1] !== 'boolean') {
391
- error = fn;
392
436
  fn = isAsync;
393
437
  isAsync = false;
394
438
  }
395
439
 
396
- const pres = get(this._pres, name, []);
440
+ const pres = this._pres.get(name) || [];
397
441
  this._pres.set(name, pres);
398
442
 
399
443
  if (isAsync) {
@@ -415,7 +459,7 @@ Kareem.prototype.pre = function(name, isAsync, fn, error, unshift) {
415
459
  };
416
460
 
417
461
  Kareem.prototype.post = function(name, options, fn, unshift) {
418
- const hooks = get(this._posts, name, []);
462
+ const hooks = this._posts.get(name) || [];
419
463
 
420
464
  if (typeof options === 'function') {
421
465
  unshift = !!fn;
@@ -456,7 +500,7 @@ Kareem.prototype.merge = function(other, clone) {
456
500
  var ret = clone ? this.clone() : this;
457
501
 
458
502
  for (let key of other._pres.keys()) {
459
- const sourcePres = get(ret._pres, key, []);
503
+ const sourcePres = ret._pres.get(key) || [];
460
504
  const deduplicated = other._pres.get(key).
461
505
  // Deduplicate based on `fn`
462
506
  filter(p => sourcePres.map(_p => _p.fn).indexOf(p.fn) === -1);
@@ -466,7 +510,7 @@ Kareem.prototype.merge = function(other, clone) {
466
510
  ret._pres.set(key, combined);
467
511
  }
468
512
  for (let key of other._posts.keys()) {
469
- const sourcePosts = get(ret._posts, key, []);
513
+ const sourcePosts = ret._posts.get(key) || [];
470
514
  const deduplicated = other._posts.get(key).
471
515
  filter(p => sourcePosts.indexOf(p) === -1);
472
516
  ret._posts.set(key, sourcePosts.concat(deduplicated));
@@ -475,28 +519,21 @@ Kareem.prototype.merge = function(other, clone) {
475
519
  return ret;
476
520
  };
477
521
 
478
- function get(map, key, def) {
479
- if (map.has(key)) {
480
- return map.get(key);
481
- }
482
- return def;
483
- }
484
-
485
522
  function callMiddlewareFunction(fn, context, args, next) {
486
- let maybePromise;
523
+ let maybePromiseLike;
487
524
  try {
488
- maybePromise = fn.apply(context, args);
525
+ maybePromiseLike = fn.apply(context, args);
489
526
  } catch (error) {
490
527
  return next(error);
491
528
  }
492
529
 
493
- if (isPromise(maybePromise)) {
494
- maybePromise.then(() => next(), err => next(err));
530
+ if (isPromiseLike(maybePromiseLike)) {
531
+ maybePromiseLike.then(() => next(), err => next(err));
495
532
  }
496
533
  }
497
534
 
498
- function isPromise(v) {
499
- return v != null && typeof v.then === 'function';
535
+ function isPromiseLike(v) {
536
+ return (typeof v === 'object' && v !== null && typeof v.then === 'function');
500
537
  }
501
538
 
502
539
  function decorateNextFn(fn) {
@@ -510,8 +547,12 @@ function decorateNextFn(fn) {
510
547
  called = true;
511
548
  // Make sure to clear the stack so try/catch doesn't catch errors
512
549
  // in subsequent middleware
513
- return process.nextTick(() => fn.apply(_this, arguments));
550
+ return nextTick(() => fn.apply(_this, arguments));
514
551
  };
515
552
  }
516
553
 
554
+ const nextTick = typeof process === 'object' && process !== null && process.nextTick || function nextTick(cb) {
555
+ setTimeout(cb, 0);
556
+ }
557
+
517
558
  module.exports = Kareem;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kareem",
3
- "version": "2.3.3",
3
+ "version": "2.4.0",
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
- "nyc": "11.x",
18
- "mocha": "5.x"
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/post.test.js CHANGED
@@ -165,6 +165,71 @@ describe('execPost', function() {
165
165
  done();
166
166
  });
167
167
  });
168
+
169
+ it('supports overwriteResult', function(done) {
170
+ hooks.post('cook', function(eggs, callback) {
171
+ callback(Kareem.overwriteResult(5));
172
+ });
173
+
174
+ hooks.post('cook', function(eggs, callback) {
175
+ assert.equal(eggs, 5);
176
+ callback();
177
+ });
178
+
179
+ var options = {};
180
+ hooks.execPost('cook', null, [4], options, function(error, eggs) {
181
+ assert.equal(eggs, 5);
182
+ done();
183
+ });
184
+ });
185
+
186
+ it('supports sync returning overwriteResult', function(done) {
187
+ hooks.post('cook', function() {
188
+ return Kareem.overwriteResult(5);
189
+ });
190
+
191
+ hooks.post('cook', function(eggs, callback) {
192
+ assert.equal(eggs, 5);
193
+ callback();
194
+ });
195
+
196
+ var options = {};
197
+ hooks.execPost('cook', null, [4], options, function(error, eggs) {
198
+ assert.ifError(error);
199
+ assert.equal(eggs, 5);
200
+ done();
201
+ });
202
+ });
203
+
204
+ it('supports sync overwriteResult', function() {
205
+ hooks.post('cook', function(eggs) {
206
+ return Kareem.overwriteResult(5);
207
+ });
208
+
209
+ hooks.post('cook', function(eggs) {
210
+ assert.equal(eggs, 5);
211
+ });
212
+
213
+ var options = {};
214
+ const res = hooks.execPostSync('cook', null, [4], options);
215
+ assert.deepEqual(res, [5]);
216
+ });
217
+
218
+ it('supports overwriteResult with promises', function(done) {
219
+ hooks.post('cook', function(eggs) {
220
+ return Promise.resolve(Kareem.overwriteResult(5));
221
+ });
222
+
223
+ hooks.post('cook', function(eggs) {
224
+ assert.equal(eggs, 5);
225
+ });
226
+
227
+ var options = {};
228
+ hooks.execPost('cook', null, [4], options, function(error, eggs) {
229
+ assert.equal(eggs, 5);
230
+ done();
231
+ });
232
+ });
168
233
  });
169
234
 
170
235
  describe('execPostSync', function() {
package/test/pre.test.js CHANGED
@@ -307,6 +307,24 @@ describe('execPre', function() {
307
307
  done();
308
308
  });
309
309
  });
310
+
311
+ it('supports skipWrappedFunction', function(done) {
312
+ var execed = {};
313
+
314
+ hooks.pre('cook', function(callback) {
315
+ callback(Kareem.skipWrappedFunction(42));
316
+ });
317
+
318
+ hooks.pre('cook', function() {
319
+ execed.second = true;
320
+ });
321
+
322
+ hooks.execPre('cook', null, function(err) {
323
+ assert.ok(execed.second);
324
+ assert.ok(err instanceof Kareem.skipWrappedFunction);
325
+ done();
326
+ });
327
+ });
310
328
  });
311
329
 
312
330
  describe('execPreSync', function() {
package/test/wrap.test.js CHANGED
@@ -287,6 +287,91 @@ describe('wrap()', function() {
287
287
  25);
288
288
  });
289
289
 
290
+ it('supports overwriteResult', function(done) {
291
+ hooks.post('cook', function(eggs, callback) {
292
+ callback(Kareem.overwriteResult(5));
293
+ });
294
+
295
+ const args = [(err, res) => {
296
+ assert.ifError(err);
297
+ assert.equal(res, 5);
298
+ done();
299
+ }];
300
+
301
+ hooks.wrap(
302
+ 'cook',
303
+ function(callback) {
304
+ callback(null, 4);
305
+ },
306
+ null,
307
+ args);
308
+ });
309
+
310
+ it('supports skipWrappedFunction', function(done) {
311
+ const execed = {};
312
+ hooks.pre('cook', function pre(callback) {
313
+ execed.pre = true;
314
+ callback(Kareem.skipWrappedFunction(3));
315
+ });
316
+
317
+ hooks.post('cook', function(res, callback) {
318
+ assert.equal(res, 3);
319
+ execed.post = true;
320
+ callback();
321
+ });
322
+
323
+ const args = [(err, res) => {
324
+ assert.ifError(err);
325
+ assert.equal(res, 3);
326
+ assert.ok(execed.pre);
327
+ assert.ok(execed.post);
328
+ assert.ok(!execed.wrapped);
329
+ done();
330
+ }];
331
+
332
+ hooks.wrap(
333
+ 'cook',
334
+ function wrapped(callback) {
335
+ execed.wrapped = true;
336
+ callback();
337
+ },
338
+ null,
339
+ args);
340
+ });
341
+
342
+ it('supports skipWrappedFunction with arguments', function(done) {
343
+ const execed = {};
344
+ hooks.pre('cook', function pre(callback, arg) {
345
+ execed.pre = true;
346
+ assert.strictEqual(arg, 4);
347
+ callback(Kareem.skipWrappedFunction(3));
348
+ });
349
+
350
+ hooks.post('cook', function(res, callback) {
351
+ assert.equal(res, 3);
352
+ execed.post = true;
353
+ callback();
354
+ });
355
+
356
+ const args = [4, (err, res) => {
357
+ assert.ifError(err);
358
+ assert.equal(res, 3);
359
+ assert.ok(execed.pre);
360
+ assert.ok(execed.post);
361
+ assert.ok(!execed.wrapped);
362
+ done();
363
+ }];
364
+
365
+ hooks.wrap(
366
+ 'cook',
367
+ function wrapped(arg, callback) {
368
+ execed.wrapped = true;
369
+ callback();
370
+ },
371
+ null,
372
+ args);
373
+ });
374
+
290
375
  it('handles post errors with no args', function(done) {
291
376
  hooks.pre('cook', function(done) {
292
377
  obj.waffles = false;
@@ -363,4 +448,17 @@ describe('wrap()', function() {
363
448
  assert.equal(calledFn, 1);
364
449
  assert.equal(calledPost, 1);
365
450
  });
451
+
452
+ it('sync wrappers with overwriteResult', function() {
453
+ hooks.pre('cook', function() {
454
+ });
455
+
456
+ hooks.post('cook', function() {
457
+ return Kareem.overwriteResult(5);
458
+ });
459
+
460
+ const wrapper = hooks.createWrapperSync('cook', function() { return 4; });
461
+
462
+ assert.strictEqual(wrapper(), 5);
463
+ });
366
464
  });