kareem 2.3.0 → 2.3.4

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/.travis.yml CHANGED
@@ -1,5 +1,7 @@
1
1
  language: node_js
2
2
  node_js:
3
+ - "12"
4
+ - "10"
3
5
  - "9"
4
6
  - "8"
5
7
  - "7"
package/CHANGELOG.md CHANGED
@@ -1,6 +1,19 @@
1
- # Change Log
1
+ # Changelog
2
2
 
3
- All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
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
+
13
+ <a name="2.3.2"></a>
14
+ ## 2.3.2 (2020-12-08)
15
+
16
+ * fix: handle sync errors in pre hooks if there are multiple hooks
4
17
 
5
18
  <a name="2.3.0"></a>
6
19
  ## 2.3.0 (2018-09-24)
package/README.md CHANGED
@@ -24,11 +24,9 @@ appropriate, giving you more fine-grained control over your function hooks.
24
24
  #### It runs without any hooks specified
25
25
 
26
26
  ```javascript
27
-
28
- hooks.execPre('cook', null, function() {
29
- done();
30
- });
31
-
27
+ hooks.execPre('cook', null, function() {
28
+ // ...
29
+ });
32
30
  ```
33
31
 
34
32
  #### It runs basic serial pre hooks
@@ -38,44 +36,38 @@ when your pre hook is finished.
38
36
 
39
37
 
40
38
  ```javascript
41
-
42
- var count = 0;
43
-
44
- hooks.pre('cook', function(done) {
45
- ++count;
46
- done();
47
- });
48
-
49
- hooks.execPre('cook', null, function() {
50
- assert.equal(1, count);
51
- done();
52
- });
53
-
39
+ var count = 0;
40
+
41
+ hooks.pre('cook', function(done) {
42
+ ++count;
43
+ done();
44
+ });
45
+
46
+ hooks.execPre('cook', null, function() {
47
+ assert.equal(1, count);
48
+ });
54
49
  ```
55
50
 
56
51
  #### It can run multipe pre hooks
57
52
 
58
53
  ```javascript
59
-
60
- var count1 = 0;
61
- var count2 = 0;
62
-
63
- hooks.pre('cook', function(done) {
64
- ++count1;
65
- done();
66
- });
67
-
68
- hooks.pre('cook', function(done) {
69
- ++count2;
70
- done();
71
- });
72
-
73
- hooks.execPre('cook', null, function() {
74
- assert.equal(1, count1);
75
- assert.equal(1, count2);
76
- done();
77
- });
78
-
54
+ var count1 = 0;
55
+ var count2 = 0;
56
+
57
+ hooks.pre('cook', function(done) {
58
+ ++count1;
59
+ done();
60
+ });
61
+
62
+ hooks.pre('cook', function(done) {
63
+ ++count2;
64
+ done();
65
+ });
66
+
67
+ hooks.execPre('cook', null, function() {
68
+ assert.equal(1, count1);
69
+ assert.equal(1, count2);
70
+ });
79
71
  ```
80
72
 
81
73
  #### It can run fully synchronous pre hooks
@@ -85,25 +77,22 @@ fully synchronous.
85
77
 
86
78
 
87
79
  ```javascript
88
-
89
- var count1 = 0;
90
- var count2 = 0;
91
-
92
- hooks.pre('cook', function() {
93
- ++count1;
94
- });
95
-
96
- hooks.pre('cook', function() {
97
- ++count2;
98
- });
99
-
100
- hooks.execPre('cook', null, function(error) {
101
- assert.equal(null, error);
102
- assert.equal(1, count1);
103
- assert.equal(1, count2);
104
- done();
105
- });
106
-
80
+ var count1 = 0;
81
+ var count2 = 0;
82
+
83
+ hooks.pre('cook', function() {
84
+ ++count1;
85
+ });
86
+
87
+ hooks.pre('cook', function() {
88
+ ++count2;
89
+ });
90
+
91
+ hooks.execPre('cook', null, function(error) {
92
+ assert.equal(null, error);
93
+ assert.equal(1, count1);
94
+ assert.equal(1, count2);
95
+ });
107
96
  ```
108
97
 
109
98
  #### It properly attaches context to pre hooks
@@ -112,27 +101,24 @@ Pre save hook functions are bound to the second parameter to `execPre()`
112
101
 
113
102
 
114
103
  ```javascript
115
-
116
- hooks.pre('cook', function(done) {
117
- this.bacon = 3;
118
- done();
119
- });
120
-
121
- hooks.pre('cook', function(done) {
122
- this.eggs = 4;
123
- done();
124
- });
125
-
126
- var obj = { bacon: 0, eggs: 0 };
127
-
128
- // In the pre hooks, `this` will refer to `obj`
129
- hooks.execPre('cook', obj, function(error) {
130
- assert.equal(null, error);
131
- assert.equal(3, obj.bacon);
132
- assert.equal(4, obj.eggs);
133
- done();
134
- });
135
-
104
+ hooks.pre('cook', function(done) {
105
+ this.bacon = 3;
106
+ done();
107
+ });
108
+
109
+ hooks.pre('cook', function(done) {
110
+ this.eggs = 4;
111
+ done();
112
+ });
113
+
114
+ var obj = { bacon: 0, eggs: 0 };
115
+
116
+ // In the pre hooks, `this` will refer to `obj`
117
+ hooks.execPre('cook', obj, function(error) {
118
+ assert.equal(null, error);
119
+ assert.equal(3, obj.bacon);
120
+ assert.equal(4, obj.eggs);
121
+ });
136
122
  ```
137
123
 
138
124
  #### It can execute parallel (async) pre hooks
@@ -144,38 +130,35 @@ async pre hooks have called `done()`.
144
130
 
145
131
 
146
132
  ```javascript
147
-
148
- hooks.pre('cook', true, function(next, done) {
149
- this.bacon = 3;
150
- next();
151
- setTimeout(function() {
152
- done();
153
- }, 5);
154
- });
155
-
156
- hooks.pre('cook', true, function(next, done) {
157
- next();
158
- var _this = this;
159
- setTimeout(function() {
160
- _this.eggs = 4;
161
- done();
162
- }, 10);
163
- });
164
-
165
- hooks.pre('cook', function(next) {
166
- this.waffles = false;
167
- next();
168
- });
169
-
170
- var obj = { bacon: 0, eggs: 0 };
171
-
172
- hooks.execPre('cook', obj, function() {
173
- assert.equal(3, obj.bacon);
174
- assert.equal(4, obj.eggs);
175
- assert.equal(false, obj.waffles);
176
- done();
177
- });
178
-
133
+ hooks.pre('cook', true, function(next, done) {
134
+ this.bacon = 3;
135
+ next();
136
+ setTimeout(function() {
137
+ done();
138
+ }, 5);
139
+ });
140
+
141
+ hooks.pre('cook', true, function(next, done) {
142
+ next();
143
+ var _this = this;
144
+ setTimeout(function() {
145
+ _this.eggs = 4;
146
+ done();
147
+ }, 10);
148
+ });
149
+
150
+ hooks.pre('cook', function(next) {
151
+ this.waffles = false;
152
+ next();
153
+ });
154
+
155
+ var obj = { bacon: 0, eggs: 0 };
156
+
157
+ hooks.execPre('cook', obj, function() {
158
+ assert.equal(3, obj.bacon);
159
+ assert.equal(4, obj.eggs);
160
+ assert.equal(false, obj.waffles);
161
+ });
179
162
  ```
180
163
 
181
164
  #### It supports returning a promise
@@ -186,148 +169,162 @@ next middleware.
186
169
 
187
170
 
188
171
  ```javascript
189
-
190
- hooks.pre('cook', function() {
191
- return new Promise(resolve => {
192
- setTimeout(() => {
193
- this.bacon = 3;
194
- resolve();
195
- }, 100);
196
- });
197
- });
198
-
199
- var obj = { bacon: 0 };
200
-
201
- hooks.execPre('cook', obj, function() {
202
- assert.equal(3, obj.bacon);
203
- done();
204
- });
205
-
172
+ hooks.pre('cook', function() {
173
+ return new Promise(resolve => {
174
+ setTimeout(() => {
175
+ this.bacon = 3;
176
+ resolve();
177
+ }, 100);
178
+ });
179
+ });
180
+
181
+ var obj = { bacon: 0 };
182
+
183
+ hooks.execPre('cook', obj, function() {
184
+ assert.equal(3, obj.bacon);
185
+ });
206
186
  ```
207
187
 
208
188
  ## post hooks
209
189
 
190
+ acquit:ignore:end
191
+
210
192
  #### It runs without any hooks specified
211
193
 
212
194
  ```javascript
213
-
214
- hooks.execPost('cook', null, [1], function(error, eggs) {
215
- assert.ifError(error);
216
- assert.equal(1, eggs);
217
- done();
218
- });
219
-
195
+ hooks.execPost('cook', null, [1], function(error, eggs) {
196
+ assert.ifError(error);
197
+ assert.equal(1, eggs);
198
+ done();
199
+ });
220
200
  ```
221
201
 
222
202
  #### It executes with parameters passed in
223
203
 
224
204
  ```javascript
225
-
226
- hooks.post('cook', function(eggs, bacon, callback) {
227
- assert.equal(1, eggs);
228
- assert.equal(2, bacon);
229
- callback();
230
- });
231
-
232
- hooks.execPost('cook', null, [1, 2], function(error, eggs, bacon) {
233
- assert.ifError(error);
234
- assert.equal(1, eggs);
235
- assert.equal(2, bacon);
236
- done();
237
- });
238
-
205
+ hooks.post('cook', function(eggs, bacon, callback) {
206
+ assert.equal(1, eggs);
207
+ assert.equal(2, bacon);
208
+ callback();
209
+ });
210
+
211
+ hooks.execPost('cook', null, [1, 2], function(error, eggs, bacon) {
212
+ assert.ifError(error);
213
+ assert.equal(1, eggs);
214
+ assert.equal(2, bacon);
215
+ });
239
216
  ```
240
217
 
241
218
  #### It can use synchronous post hooks
242
219
 
243
220
  ```javascript
244
-
245
- var execed = {};
246
-
247
- hooks.post('cook', function(eggs, bacon) {
248
- execed.first = true;
249
- assert.equal(1, eggs);
250
- assert.equal(2, bacon);
251
- });
252
-
253
- hooks.post('cook', function(eggs, bacon, callback) {
254
- execed.second = true;
255
- assert.equal(1, eggs);
256
- assert.equal(2, bacon);
257
- callback();
258
- });
259
-
260
- hooks.execPost('cook', null, [1, 2], function(error, eggs, bacon) {
261
- assert.ifError(error);
262
- assert.equal(2, Object.keys(execed).length);
263
- assert.ok(execed.first);
264
- assert.ok(execed.second);
265
- assert.equal(1, eggs);
266
- assert.equal(2, bacon);
267
- done();
268
- });
269
-
221
+ var execed = {};
222
+
223
+ hooks.post('cook', function(eggs, bacon) {
224
+ execed.first = true;
225
+ assert.equal(1, eggs);
226
+ assert.equal(2, bacon);
227
+ });
228
+
229
+ hooks.post('cook', function(eggs, bacon, callback) {
230
+ execed.second = true;
231
+ assert.equal(1, eggs);
232
+ assert.equal(2, bacon);
233
+ callback();
234
+ });
235
+
236
+ hooks.execPost('cook', null, [1, 2], function(error, eggs, bacon) {
237
+ assert.ifError(error);
238
+ assert.equal(2, Object.keys(execed).length);
239
+ assert.ok(execed.first);
240
+ assert.ok(execed.second);
241
+ assert.equal(1, eggs);
242
+ assert.equal(2, bacon);
243
+ });
244
+ ```
245
+
246
+ #### It supports returning a promise
247
+
248
+ You can also return a promise from your post hooks instead of calling
249
+ `next()`. When the returned promise resolves, kareem will kick off the
250
+ next middleware.
251
+
252
+
253
+ ```javascript
254
+ hooks.post('cook', function(bacon) {
255
+ return new Promise(resolve => {
256
+ setTimeout(() => {
257
+ this.bacon = 3;
258
+ resolve();
259
+ }, 100);
260
+ });
261
+ });
262
+
263
+ var obj = { bacon: 0 };
264
+
265
+ hooks.execPost('cook', obj, obj, function() {
266
+ assert.equal(obj.bacon, 3);
267
+ });
270
268
  ```
271
269
 
272
270
  ## wrap()
273
271
 
272
+ acquit:ignore:end
273
+
274
274
  #### It wraps pre and post calls into one call
275
275
 
276
276
  ```javascript
277
-
278
- hooks.pre('cook', true, function(next, done) {
279
- this.bacon = 3;
280
- next();
281
- setTimeout(function() {
282
- done();
283
- }, 5);
284
- });
285
-
286
- hooks.pre('cook', true, function(next, done) {
287
- next();
288
- var _this = this;
289
- setTimeout(function() {
290
- _this.eggs = 4;
291
- done();
292
- }, 10);
293
- });
294
-
295
- hooks.pre('cook', function(next) {
296
- this.waffles = false;
297
- next();
298
- });
299
-
300
- hooks.post('cook', function(obj) {
301
- obj.tofu = 'no';
302
- });
303
-
304
- var obj = { bacon: 0, eggs: 0 };
305
-
306
- var args = [obj];
307
- args.push(function(error, result) {
308
- assert.ifError(error);
309
- assert.equal(null, error);
310
- assert.equal(3, obj.bacon);
311
- assert.equal(4, obj.eggs);
312
- assert.equal(false, obj.waffles);
313
- assert.equal('no', obj.tofu);
314
-
315
- assert.equal(obj, result);
316
- done();
317
- });
318
-
319
- hooks.wrap(
320
- 'cook',
321
- function(o, callback) {
322
- assert.equal(3, obj.bacon);
323
- assert.equal(4, obj.eggs);
324
- assert.equal(false, obj.waffles);
325
- assert.equal(undefined, obj.tofu);
326
- callback(null, o);
327
- },
328
- obj,
329
- args);
330
-
277
+ hooks.pre('cook', true, function(next, done) {
278
+ this.bacon = 3;
279
+ next();
280
+ setTimeout(function() {
281
+ done();
282
+ }, 5);
283
+ });
284
+
285
+ hooks.pre('cook', true, function(next, done) {
286
+ next();
287
+ var _this = this;
288
+ setTimeout(function() {
289
+ _this.eggs = 4;
290
+ done();
291
+ }, 10);
292
+ });
293
+
294
+ hooks.pre('cook', function(next) {
295
+ this.waffles = false;
296
+ next();
297
+ });
298
+
299
+ hooks.post('cook', function(obj) {
300
+ obj.tofu = 'no';
301
+ });
302
+
303
+ var obj = { bacon: 0, eggs: 0 };
304
+
305
+ var args = [obj];
306
+ args.push(function(error, result) {
307
+ assert.ifError(error);
308
+ assert.equal(null, error);
309
+ assert.equal(3, obj.bacon);
310
+ assert.equal(4, obj.eggs);
311
+ assert.equal(false, obj.waffles);
312
+ assert.equal('no', obj.tofu);
313
+
314
+ assert.equal(obj, result);
315
+ });
316
+
317
+ hooks.wrap(
318
+ 'cook',
319
+ function(o, callback) {
320
+ assert.equal(3, obj.bacon);
321
+ assert.equal(4, obj.eggs);
322
+ assert.equal(false, obj.waffles);
323
+ assert.equal(undefined, obj.tofu);
324
+ callback(null, o);
325
+ },
326
+ obj,
327
+ args);
331
328
  ```
332
329
 
333
330
  ## createWrapper()
@@ -335,73 +332,70 @@ next middleware.
335
332
  #### It wraps wrap() into a callable function
336
333
 
337
334
  ```javascript
338
-
339
- hooks.pre('cook', true, function(next, done) {
340
- this.bacon = 3;
341
- next();
342
- setTimeout(function() {
343
- done();
344
- }, 5);
345
- });
346
-
347
- hooks.pre('cook', true, function(next, done) {
348
- next();
349
- var _this = this;
350
- setTimeout(function() {
351
- _this.eggs = 4;
352
- done();
353
- }, 10);
354
- });
355
-
356
- hooks.pre('cook', function(next) {
357
- this.waffles = false;
358
- next();
359
- });
360
-
361
- hooks.post('cook', function(obj) {
362
- obj.tofu = 'no';
363
- });
364
-
365
- var obj = { bacon: 0, eggs: 0 };
366
-
367
- var cook = hooks.createWrapper(
368
- 'cook',
369
- function(o, callback) {
370
- assert.equal(3, obj.bacon);
371
- assert.equal(4, obj.eggs);
372
- assert.equal(false, obj.waffles);
373
- assert.equal(undefined, obj.tofu);
374
- callback(null, o);
375
- },
376
- obj);
377
-
378
- cook(obj, function(error, result) {
379
- assert.ifError(error);
380
- assert.equal(3, obj.bacon);
381
- assert.equal(4, obj.eggs);
382
- assert.equal(false, obj.waffles);
383
- assert.equal('no', obj.tofu);
384
-
385
- assert.equal(obj, result);
386
- done();
387
- });
388
-
335
+ hooks.pre('cook', true, function(next, done) {
336
+ this.bacon = 3;
337
+ next();
338
+ setTimeout(function() {
339
+ done();
340
+ }, 5);
341
+ });
342
+
343
+ hooks.pre('cook', true, function(next, done) {
344
+ next();
345
+ var _this = this;
346
+ setTimeout(function() {
347
+ _this.eggs = 4;
348
+ done();
349
+ }, 10);
350
+ });
351
+
352
+ hooks.pre('cook', function(next) {
353
+ this.waffles = false;
354
+ next();
355
+ });
356
+
357
+ hooks.post('cook', function(obj) {
358
+ obj.tofu = 'no';
359
+ });
360
+
361
+ var obj = { bacon: 0, eggs: 0 };
362
+
363
+ var cook = hooks.createWrapper(
364
+ 'cook',
365
+ function(o, callback) {
366
+ assert.equal(3, obj.bacon);
367
+ assert.equal(4, obj.eggs);
368
+ assert.equal(false, obj.waffles);
369
+ assert.equal(undefined, obj.tofu);
370
+ callback(null, o);
371
+ },
372
+ obj);
373
+
374
+ cook(obj, function(error, result) {
375
+ assert.ifError(error);
376
+ assert.equal(3, obj.bacon);
377
+ assert.equal(4, obj.eggs);
378
+ assert.equal(false, obj.waffles);
379
+ assert.equal('no', obj.tofu);
380
+
381
+ assert.equal(obj, result);
382
+ });
389
383
  ```
390
384
 
391
385
  ## clone()
392
386
 
387
+ acquit:ignore:end
388
+
393
389
  #### It clones a Kareem object
394
390
 
395
391
  ```javascript
396
-
397
- var k1 = new Kareem();
398
- k1.pre('cook', function() {});
399
- k1.post('cook', function() {});
400
-
401
- var k2 = k1.clone();
402
- assert.deepEqual(['cook'], Object.keys(k2._pres));
403
- assert.deepEqual(['cook'], Object.keys(k2._posts));
404
-
392
+ var k1 = new Kareem();
393
+ k1.pre('cook', function() {});
394
+ k1.post('cook', function() {});
395
+
396
+ var k2 = k1.clone();
397
+ assert.deepEqual(Array.from(k2._pres.keys()), ['cook']);
398
+ assert.deepEqual(Array.from(k2._posts.keys()), ['cook']);
405
399
  ```
406
400
 
407
401
  ## merge()
@@ -409,20 +403,18 @@ next middleware.
409
403
  #### It pulls hooks from another Kareem object
410
404
 
411
405
  ```javascript
412
-
413
- var k1 = new Kareem();
414
- var test1 = function() {};
415
- k1.pre('cook', test1);
416
- k1.post('cook', function() {});
417
-
418
- var k2 = new Kareem();
419
- var test2 = function() {};
420
- k2.pre('cook', test2);
421
- var k3 = k2.merge(k1);
422
- assert.equal(k3._pres['cook'].length, 2);
423
- assert.equal(k3._pres['cook'][0].fn, test2);
424
- assert.equal(k3._pres['cook'][1].fn, test1);
425
- assert.equal(k3._posts['cook'].length, 1);
426
-
406
+ var k1 = new Kareem();
407
+ var test1 = function() {};
408
+ k1.pre('cook', test1);
409
+ k1.post('cook', function() {});
410
+
411
+ var k2 = new Kareem();
412
+ var test2 = function() {};
413
+ k2.pre('cook', test2);
414
+ var k3 = k2.merge(k1);
415
+ assert.equal(k3._pres.get('cook').length, 2);
416
+ assert.equal(k3._pres.get('cook')[0].fn, test2);
417
+ assert.equal(k3._pres.get('cook')[1].fn, test1);
418
+ assert.equal(k3._posts.get('cook').length, 1);
427
419
  ```
428
420
 
package/docs.js CHANGED
@@ -1,5 +1,7 @@
1
1
  var acquit = require('acquit');
2
2
 
3
+ require('acquit-ignore')();
4
+
3
5
  var content = require('fs').readFileSync('./test/examples.test.js').toString();
4
6
  var blocks = acquit.parse(content);
5
7
 
@@ -29,7 +31,7 @@ for (var i = 0; i < blocks.length; ++i) {
29
31
  acquit.trimEachLine(it.comments[0]) + '\n\n' :
30
32
  '';
31
33
  mdOutput += '```javascript\n';
32
- mdOutput += ' ' + it.code + '\n';
34
+ mdOutput += it.code + '\n';
33
35
  mdOutput += '```\n\n';
34
36
  }
35
37
  }
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 = get(this._pres, name, []);
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;
@@ -57,12 +57,13 @@ Kareem.prototype.execPre = function(name, context, args, callback) {
57
57
 
58
58
  callMiddlewareFunction(pre.fn, context, args, args[0]);
59
59
  } else {
60
- let error = null;
61
60
  let maybePromise = null;
62
61
  try {
63
62
  maybePromise = pre.fn.call(context);
64
63
  } catch (err) {
65
- error = err;
64
+ if (err != null) {
65
+ return callback(err);
66
+ }
66
67
  }
67
68
 
68
69
  if (isPromise(maybePromise)) {
@@ -74,11 +75,11 @@ Kareem.prototype.execPre = function(name, context, args, callback) {
74
75
  return;
75
76
  } else {
76
77
  return process.nextTick(function() {
77
- callback(error);
78
+ callback(null);
78
79
  });
79
80
  }
80
81
  }
81
- next(error);
82
+ next();
82
83
  }
83
84
  }
84
85
  };
@@ -108,7 +109,7 @@ Kareem.prototype.execPre = function(name, context, args, callback) {
108
109
  };
109
110
 
110
111
  Kareem.prototype.execPreSync = function(name, context, args) {
111
- var pres = get(this._pres, name, []);
112
+ var pres = this._pres.get(name) || [];
112
113
  var numPres = pres.length;
113
114
 
114
115
  for (var i = 0; i < numPres; ++i) {
@@ -121,7 +122,7 @@ Kareem.prototype.execPost = function(name, context, args, options, callback) {
121
122
  callback = options;
122
123
  options = null;
123
124
  }
124
- var posts = get(this._posts, name, []);
125
+ var posts = this._posts.get(name) || [];
125
126
  var numPosts = posts.length;
126
127
  var currentPost = 0;
127
128
 
@@ -150,7 +151,7 @@ Kareem.prototype.execPost = function(name, context, args, options, callback) {
150
151
 
151
152
  if (firstError) {
152
153
  if (post.length === numArgs + 2) {
153
- var _cb = decorateNextFn(function(error) {
154
+ const _cb = decorateNextFn(function(error) {
154
155
  if (error) {
155
156
  firstError = error;
156
157
  }
@@ -209,7 +210,7 @@ Kareem.prototype.execPost = function(name, context, args, options, callback) {
209
210
  return callback.apply(null, [error].concat(args));
210
211
  }
211
212
 
212
- next(error);
213
+ next();
213
214
  }
214
215
  }
215
216
  };
@@ -218,7 +219,7 @@ Kareem.prototype.execPost = function(name, context, args, options, callback) {
218
219
  };
219
220
 
220
221
  Kareem.prototype.execPostSync = function(name, context, args) {
221
- const posts = get(this._posts, name, []);
222
+ const posts = this._posts.get(name) || [];
222
223
  const numPosts = posts.length;
223
224
 
224
225
  for (let i = 0; i < numPosts; ++i) {
@@ -241,14 +242,11 @@ Kareem.prototype.createWrapperSync = function(name, fn) {
241
242
 
242
243
  function _handleWrapError(instance, error, name, context, args, options, callback) {
243
244
  if (options.useErrorHandlers) {
244
- var _options = { error: error };
245
- return instance.execPost(name, context, args, _options, function(error) {
245
+ return instance.execPost(name, context, args, { error: error }, function(error) {
246
246
  return typeof callback === 'function' && callback(error);
247
247
  });
248
248
  } else {
249
- return typeof callback === 'function' ?
250
- callback(error) :
251
- undefined;
249
+ return typeof callback === 'function' && callback(error);
252
250
  }
253
251
  }
254
252
 
@@ -275,7 +273,12 @@ Kareem.prototype.wrap = function(name, fn, context, args, options) {
275
273
 
276
274
  const end = (typeof lastArg === 'function' ? args.length - 1 : args.length);
277
275
  const numParameters = fn.length;
278
- const ret = fn.apply(context, args.slice(0, end).concat(_cb));
276
+ let ret;
277
+ try {
278
+ ret = fn.apply(context, args.slice(0, end).concat(_cb));
279
+ } catch (err) {
280
+ return _cb(err);
281
+ }
279
282
 
280
283
  if (checkForPromise) {
281
284
  if (ret != null && typeof ret.then === 'function') {
@@ -294,8 +297,8 @@ Kareem.prototype.wrap = function(name, fn, context, args, options) {
294
297
  }
295
298
 
296
299
  function _cb() {
297
- const args = arguments;
298
- const argsWithoutError = Array.prototype.slice.call(arguments, 1);
300
+ const argsWithoutError = Array.from(arguments);
301
+ argsWithoutError.shift();
299
302
  if (options.nullResultByDefault && argsWithoutError.length === 0) {
300
303
  argsWithoutError.push(null);
301
304
  }
@@ -371,23 +374,21 @@ Kareem.prototype.createWrapper = function(name, fn, context, options) {
371
374
  }
372
375
  return function() {
373
376
  var _context = context || this;
374
- var args = Array.prototype.slice.call(arguments);
375
- _this.wrap(name, fn, _context, args, options);
377
+ _this.wrap(name, fn, _context, Array.from(arguments), options);
376
378
  };
377
379
  };
378
380
 
379
381
  Kareem.prototype.pre = function(name, isAsync, fn, error, unshift) {
380
382
  let options = {};
381
- if (typeof isAsync === 'object' && isAsync != null) {
383
+ if (typeof isAsync === 'object' && isAsync !== null) {
382
384
  options = isAsync;
383
385
  isAsync = options.isAsync;
384
386
  } else if (typeof arguments[1] !== 'boolean') {
385
- error = fn;
386
387
  fn = isAsync;
387
388
  isAsync = false;
388
389
  }
389
390
 
390
- const pres = get(this._pres, name, []);
391
+ const pres = this._pres.get(name) || [];
391
392
  this._pres.set(name, pres);
392
393
 
393
394
  if (isAsync) {
@@ -395,6 +396,10 @@ Kareem.prototype.pre = function(name, isAsync, fn, error, unshift) {
395
396
  ++pres.numAsync;
396
397
  }
397
398
 
399
+ if (typeof fn !== 'function') {
400
+ throw new Error('pre() requires a function, got "' + typeof fn + '"');
401
+ }
402
+
398
403
  if (unshift) {
399
404
  pres.unshift(Object.assign({}, options, { fn: fn, isAsync: isAsync }));
400
405
  } else {
@@ -405,7 +410,7 @@ Kareem.prototype.pre = function(name, isAsync, fn, error, unshift) {
405
410
  };
406
411
 
407
412
  Kareem.prototype.post = function(name, options, fn, unshift) {
408
- const hooks = get(this._posts, name, []);
413
+ const hooks = this._posts.get(name) || [];
409
414
 
410
415
  if (typeof options === 'function') {
411
416
  unshift = !!fn;
@@ -413,6 +418,10 @@ Kareem.prototype.post = function(name, options, fn, unshift) {
413
418
  options = {};
414
419
  }
415
420
 
421
+ if (typeof fn !== 'function') {
422
+ throw new Error('post() requires a function, got "' + typeof fn + '"');
423
+ }
424
+
416
425
  if (unshift) {
417
426
  hooks.unshift(Object.assign({}, options, { fn: fn }));
418
427
  } else {
@@ -442,7 +451,7 @@ Kareem.prototype.merge = function(other, clone) {
442
451
  var ret = clone ? this.clone() : this;
443
452
 
444
453
  for (let key of other._pres.keys()) {
445
- const sourcePres = get(ret._pres, key, []);
454
+ const sourcePres = ret._pres.get(key) || [];
446
455
  const deduplicated = other._pres.get(key).
447
456
  // Deduplicate based on `fn`
448
457
  filter(p => sourcePres.map(_p => _p.fn).indexOf(p.fn) === -1);
@@ -452,7 +461,7 @@ Kareem.prototype.merge = function(other, clone) {
452
461
  ret._pres.set(key, combined);
453
462
  }
454
463
  for (let key of other._posts.keys()) {
455
- const sourcePosts = get(ret._posts, key, []);
464
+ const sourcePosts = ret._posts.get(key) || [];
456
465
  const deduplicated = other._posts.get(key).
457
466
  filter(p => sourcePosts.indexOf(p) === -1);
458
467
  ret._posts.set(key, sourcePosts.concat(deduplicated));
@@ -461,13 +470,6 @@ Kareem.prototype.merge = function(other, clone) {
461
470
  return ret;
462
471
  };
463
472
 
464
- function get(map, key, def) {
465
- if (map.has(key)) {
466
- return map.get(key);
467
- }
468
- return def;
469
- }
470
-
471
473
  function callMiddlewareFunction(fn, context, args, next) {
472
474
  let maybePromise;
473
475
  try {
package/package.json CHANGED
@@ -1,30 +1,21 @@
1
1
  {
2
2
  "name": "kareem",
3
- "version": "2.3.0",
3
+ "version": "2.3.4",
4
4
  "description": "Next-generation take on pre/post function hooks",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
- "test": "./node_modules/mocha/bin/mocha ./test/*",
8
- "test-travis": "./node_modules/istanbul/lib/cli.js cover ./node_modules/mocha/bin/_mocha -- -R spec ./test/*"
7
+ "test": "mocha ./test/*",
8
+ "test-travis": "nyc mocha ./test/*"
9
9
  },
10
10
  "repository": {
11
11
  "type": "git",
12
12
  "url": "git://github.com/vkarpov15/kareem.git"
13
13
  },
14
14
  "devDependencies": {
15
- "acquit": "0.5.1",
16
- "gulp": "3.8.10",
17
- "gulp-mocha": "2.0.0",
18
- "gulp-jscs": "1.4.0",
19
- "istanbul": "0.4.5",
20
- "jscs": "1.9.0",
21
- "mocha": "3.2.0",
22
- "standard-version": "4.4.0"
23
- },
24
- "jscsConfig": {
25
- "preset": "airbnb",
26
- "requireMultipleVarDecl": null,
27
- "disallowMultipleVarDecl": true
15
+ "acquit": "1.x",
16
+ "acquit-ignore": "0.1.x",
17
+ "mocha": "9.2.0",
18
+ "nyc": "15.1.0"
28
19
  },
29
20
  "author": "Valeri Karpov <val@karpov.io>",
30
21
  "license": "Apache-2.0"
@@ -17,7 +17,10 @@ describe('pre hooks', function() {
17
17
 
18
18
  it('runs without any hooks specified', function(done) {
19
19
  hooks.execPre('cook', null, function() {
20
+ // ...
21
+ // acquit:ignore:start
20
22
  done();
23
+ // acquit:ignore:end
21
24
  });
22
25
  });
23
26
 
@@ -34,7 +37,9 @@ describe('pre hooks', function() {
34
37
 
35
38
  hooks.execPre('cook', null, function() {
36
39
  assert.equal(1, count);
40
+ // acquit:ignore:start
37
41
  done();
42
+ // acquit:ignore:end
38
43
  });
39
44
  });
40
45
 
@@ -55,7 +60,9 @@ describe('pre hooks', function() {
55
60
  hooks.execPre('cook', null, function() {
56
61
  assert.equal(1, count1);
57
62
  assert.equal(1, count2);
63
+ // acquit:ignore:start
58
64
  done();
65
+ // acquit:ignore:end
59
66
  });
60
67
  });
61
68
 
@@ -78,7 +85,9 @@ describe('pre hooks', function() {
78
85
  assert.equal(null, error);
79
86
  assert.equal(1, count1);
80
87
  assert.equal(1, count2);
88
+ // acquit:ignore:start
81
89
  done();
90
+ // acquit:ignore:end
82
91
  });
83
92
  });
84
93
 
@@ -102,7 +111,9 @@ describe('pre hooks', function() {
102
111
  assert.equal(null, error);
103
112
  assert.equal(3, obj.bacon);
104
113
  assert.equal(4, obj.eggs);
114
+ // acquit:ignore:start
105
115
  done();
116
+ // acquit:ignore:end
106
117
  });
107
118
  });
108
119
 
@@ -140,7 +151,9 @@ describe('pre hooks', function() {
140
151
  assert.equal(3, obj.bacon);
141
152
  assert.equal(4, obj.eggs);
142
153
  assert.equal(false, obj.waffles);
154
+ // acquit:ignore:start
143
155
  done();
156
+ // acquit:ignore:end
144
157
  });
145
158
  });
146
159
 
@@ -162,7 +175,9 @@ describe('pre hooks', function() {
162
175
 
163
176
  hooks.execPre('cook', obj, function() {
164
177
  assert.equal(3, obj.bacon);
178
+ // acquit:ignore:start
165
179
  done();
180
+ // acquit:ignore:end
166
181
  });
167
182
  });
168
183
  });
@@ -193,7 +208,9 @@ describe('post hooks', function() {
193
208
  assert.ifError(error);
194
209
  assert.equal(1, eggs);
195
210
  assert.equal(2, bacon);
211
+ // acquit:ignore:start
196
212
  done();
213
+ // acquit:ignore:end
197
214
  });
198
215
  });
199
216
 
@@ -220,7 +237,33 @@ describe('post hooks', function() {
220
237
  assert.ok(execed.second);
221
238
  assert.equal(1, eggs);
222
239
  assert.equal(2, bacon);
240
+ // acquit:ignore:start
223
241
  done();
242
+ // acquit:ignore:end
243
+ });
244
+ });
245
+
246
+ /* You can also return a promise from your post hooks instead of calling
247
+ * `next()`. When the returned promise resolves, kareem will kick off the
248
+ * next middleware.
249
+ */
250
+ it('supports returning a promise', function(done) {
251
+ hooks.post('cook', function(bacon) {
252
+ return new Promise(resolve => {
253
+ setTimeout(() => {
254
+ this.bacon = 3;
255
+ resolve();
256
+ }, 100);
257
+ });
258
+ });
259
+
260
+ var obj = { bacon: 0 };
261
+
262
+ hooks.execPost('cook', obj, obj, function() {
263
+ assert.equal(obj.bacon, 3);
264
+ // acquit:ignore:start
265
+ done();
266
+ // acquit:ignore:end
224
267
  });
225
268
  });
226
269
  });
@@ -271,7 +314,9 @@ describe('wrap()', function() {
271
314
  assert.equal('no', obj.tofu);
272
315
 
273
316
  assert.equal(obj, result);
317
+ // acquit:ignore:start
274
318
  done();
319
+ // acquit:ignore:end
275
320
  });
276
321
 
277
322
  hooks.wrap(
@@ -343,7 +388,9 @@ describe('createWrapper()', function() {
343
388
  assert.equal('no', obj.tofu);
344
389
 
345
390
  assert.equal(obj, result);
391
+ // acquit:ignore:start
346
392
  done();
393
+ // acquit:ignore:end
347
394
  });
348
395
  });
349
396
  });
package/test/post.test.js CHANGED
@@ -40,6 +40,10 @@ describe('execPost', function() {
40
40
  assert.equal(hooks._posts.get('cook')[0].bar, 'baz');
41
41
  });
42
42
 
43
+ it('throws error if no function', function() {
44
+ assert.throws(() => hooks.post('test'), /got "undefined"/);
45
+ });
46
+
43
47
  it('multiple posts', function(done) {
44
48
  hooks.post('cook', function(eggs, callback) {
45
49
  setTimeout(
package/test/pre.test.js CHANGED
@@ -65,6 +65,10 @@ describe('execPre', function() {
65
65
  assert.strictEqual(hooks._pres.get('cook')[1].fn, f1);
66
66
  });
67
67
 
68
+ it('throws error if no function', function() {
69
+ assert.throws(() => hooks.pre('test'), /got "undefined"/);
70
+ });
71
+
68
72
  it('arbitrary options', function() {
69
73
  const f1 = function() {};
70
74
  const f2 = function() {};
@@ -283,6 +287,26 @@ describe('execPre', function() {
283
287
  done();
284
288
  });
285
289
  });
290
+
291
+ it('handles sync errors in pre if there are more hooks', function(done) {
292
+ var execed = {};
293
+
294
+ hooks.pre('cook', function() {
295
+ execed.first = true;
296
+ throw new Error('Oops!');
297
+ });
298
+
299
+ hooks.pre('cook', function() {
300
+ execed.second = true;
301
+ });
302
+
303
+ hooks.execPre('cook', null, function(err) {
304
+ assert.ok(err);
305
+ assert.ok(execed.first);
306
+ assert.equal(err.message, 'Oops!');
307
+ done();
308
+ });
309
+ });
286
310
  });
287
311
 
288
312
  describe('execPreSync', function() {
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;