kareem 2.4.0 → 2.5.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.
package/LICENSE CHANGED
@@ -186,7 +186,7 @@ Apache License
186
186
  same "printed page" as the copyright notice for easier
187
187
  identification within third-party archives.
188
188
 
189
- Copyright {yyyy} {name of copyright owner}
189
+ Copyright 2014-2022 mongoosejs
190
190
 
191
191
  Licensed under the Apache License, Version 2.0 (the "License");
192
192
  you may not use this file except in compliance with the License.
package/index.js CHANGED
@@ -1,5 +1,8 @@
1
1
  'use strict';
2
2
 
3
+ /**
4
+ * Create a new instance
5
+ */
3
6
  function Kareem() {
4
7
  this._pres = new Map();
5
8
  this._posts = new Map();
@@ -21,19 +24,27 @@ Kareem.overwriteResult = function overwriteResult() {
21
24
  this.args = [...arguments];
22
25
  };
23
26
 
27
+ /**
28
+ * Execute all "pre" hooks for "name"
29
+ * @param {String} name The hook name to execute
30
+ * @param {*} context Overwrite the "this" for the hook
31
+ * @param {Array|Function} args Optional arguments or directly the callback
32
+ * @param {Function} [callback] The callback to call when executing all hooks are finished
33
+ * @returns {void}
34
+ */
24
35
  Kareem.prototype.execPre = function(name, context, args, callback) {
25
36
  if (arguments.length === 3) {
26
37
  callback = args;
27
38
  args = [];
28
39
  }
29
- var pres = this._pres.get(name) || [];
30
- var numPres = pres.length;
31
- var numAsyncPres = pres.numAsync || 0;
32
- var currentPre = 0;
33
- var asyncPresLeft = numAsyncPres;
34
- var done = false;
35
- var $args = args;
36
- var shouldSkipWrappedFunction = null;
40
+ const pres = this._pres.get(name) || [];
41
+ const numPres = pres.length;
42
+ const numAsyncPres = pres.numAsync || 0;
43
+ let currentPre = 0;
44
+ let asyncPresLeft = numAsyncPres;
45
+ let done = false;
46
+ const $args = args;
47
+ let shouldSkipWrappedFunction = null;
37
48
 
38
49
  if (!numPres) {
39
50
  return nextTick(function() {
@@ -41,14 +52,14 @@ Kareem.prototype.execPre = function(name, context, args, callback) {
41
52
  });
42
53
  }
43
54
 
44
- var next = function() {
55
+ function next() {
45
56
  if (currentPre >= numPres) {
46
57
  return;
47
58
  }
48
- var pre = pres[currentPre];
59
+ const pre = pres[currentPre];
49
60
 
50
61
  if (pre.isAsync) {
51
- var args = [
62
+ const args = [
52
63
  decorateNextFn(_next),
53
64
  decorateNextFn(function(error) {
54
65
  if (error) {
@@ -70,9 +81,9 @@ Kareem.prototype.execPre = function(name, context, args, callback) {
70
81
 
71
82
  callMiddlewareFunction(pre.fn, context, args, args[0]);
72
83
  } else if (pre.fn.length > 0) {
73
- var args = [decorateNextFn(_next)];
74
- var _args = arguments.length >= 2 ? arguments : [null].concat($args);
75
- for (var i = 1; i < _args.length; ++i) {
84
+ const args = [decorateNextFn(_next)];
85
+ const _args = arguments.length >= 2 ? arguments : [null].concat($args);
86
+ for (let i = 1; i < _args.length; ++i) {
76
87
  args.push(_args[i]);
77
88
  }
78
89
 
@@ -103,7 +114,7 @@ Kareem.prototype.execPre = function(name, context, args, callback) {
103
114
  next();
104
115
  }
105
116
  }
106
- };
117
+ }
107
118
 
108
119
  next.apply(null, [null].concat(args));
109
120
 
@@ -133,25 +144,41 @@ Kareem.prototype.execPre = function(name, context, args, callback) {
133
144
  }
134
145
  };
135
146
 
147
+ /**
148
+ * Execute all "pre" hooks for "name" synchronously
149
+ * @param {String} name The hook name to execute
150
+ * @param {*} context Overwrite the "this" for the hook
151
+ * @param {Array} [args] Apply custom arguments to the hook
152
+ * @returns {void}
153
+ */
136
154
  Kareem.prototype.execPreSync = function(name, context, args) {
137
- var pres = this._pres.get(name) || [];
138
- var numPres = pres.length;
155
+ const pres = this._pres.get(name) || [];
156
+ const numPres = pres.length;
139
157
 
140
- for (var i = 0; i < numPres; ++i) {
158
+ for (let i = 0; i < numPres; ++i) {
141
159
  pres[i].fn.apply(context, args || []);
142
160
  }
143
161
  };
144
162
 
163
+ /**
164
+ * Execute all "post" hooks for "name"
165
+ * @param {String} name The hook name to execute
166
+ * @param {*} context Overwrite the "this" for the hook
167
+ * @param {Array|Function} args Apply custom arguments to the hook
168
+ * @param {*} options Optional options or directly the callback
169
+ * @param {Function} [callback] The callback to call when executing all hooks are finished
170
+ * @returns {void}
171
+ */
145
172
  Kareem.prototype.execPost = function(name, context, args, options, callback) {
146
173
  if (arguments.length < 5) {
147
174
  callback = options;
148
175
  options = null;
149
176
  }
150
- var posts = this._posts.get(name) || [];
151
- var numPosts = posts.length;
152
- var currentPost = 0;
177
+ const posts = this._posts.get(name) || [];
178
+ const numPosts = posts.length;
179
+ let currentPost = 0;
153
180
 
154
- var firstError = null;
181
+ let firstError = null;
155
182
  if (options && options.error) {
156
183
  firstError = options.error;
157
184
  }
@@ -162,12 +189,12 @@ Kareem.prototype.execPost = function(name, context, args, options, callback) {
162
189
  });
163
190
  }
164
191
 
165
- var next = function() {
166
- var post = posts[currentPost].fn;
167
- var numArgs = 0;
168
- var argLength = args.length;
169
- var newArgs = [];
170
- for (var i = 0; i < argLength; ++i) {
192
+ function next() {
193
+ const post = posts[currentPost].fn;
194
+ let numArgs = 0;
195
+ const argLength = args.length;
196
+ const newArgs = [];
197
+ for (let i = 0; i < argLength; ++i) {
171
198
  numArgs += args[i] && args[i]._kareemIgnore ? 0 : 1;
172
199
  if (!args[i] || !args[i]._kareemIgnore) {
173
200
  newArgs.push(args[i]);
@@ -175,7 +202,7 @@ Kareem.prototype.execPost = function(name, context, args, options, callback) {
175
202
  }
176
203
 
177
204
  if (firstError) {
178
- if (post.length === numArgs + 2) {
205
+ if (isErrorHandlingMiddleware(posts[currentPost], numArgs)) {
179
206
  const _cb = decorateNextFn(function(error) {
180
207
  if (error) {
181
208
  if (error instanceof Kareem.overwriteResult) {
@@ -222,7 +249,7 @@ Kareem.prototype.execPost = function(name, context, args, options, callback) {
222
249
  next();
223
250
  });
224
251
 
225
- if (post.length === numArgs + 2) {
252
+ if (isErrorHandlingMiddleware(posts[currentPost], numArgs)) {
226
253
  // Skip error handlers if no error
227
254
  if (++currentPost >= numPosts) {
228
255
  return callback.apply(null, [null].concat(args));
@@ -242,7 +269,12 @@ Kareem.prototype.execPost = function(name, context, args, options, callback) {
242
269
  }
243
270
 
244
271
  if (isPromiseLike(maybePromiseLike)) {
245
- return maybePromiseLike.then((res) => _cb(res), err => _cb(err));
272
+ return maybePromiseLike.then(
273
+ (res) => {
274
+ _cb(res instanceof Kareem.overwriteResult ? res : null);
275
+ },
276
+ err => _cb(err)
277
+ );
246
278
  }
247
279
 
248
280
  if (maybePromiseLike instanceof Kareem.overwriteResult) {
@@ -256,11 +288,18 @@ Kareem.prototype.execPost = function(name, context, args, options, callback) {
256
288
  next();
257
289
  }
258
290
  }
259
- };
291
+ }
260
292
 
261
293
  next();
262
294
  };
263
295
 
296
+ /**
297
+ * Execute all "post" hooks for "name" synchronously
298
+ * @param {String} name The hook name to execute
299
+ * @param {*} context Overwrite the "this" for the hook
300
+ * @param {Array|Function} args Apply custom arguments to the hook
301
+ * @returns {Array} The used arguments
302
+ */
264
303
  Kareem.prototype.execPostSync = function(name, context, args) {
265
304
  const posts = this._posts.get(name) || [];
266
305
  const numPosts = posts.length;
@@ -275,18 +314,24 @@ Kareem.prototype.execPostSync = function(name, context, args) {
275
314
  return args;
276
315
  };
277
316
 
317
+ /**
318
+ * Create a synchronous wrapper for "fn"
319
+ * @param {String} name The name of the hook
320
+ * @param {Function} fn The function to wrap
321
+ * @returns {Function} The wrapped function
322
+ */
278
323
  Kareem.prototype.createWrapperSync = function(name, fn) {
279
- var kareem = this;
324
+ const _this = this;
280
325
  return function syncWrapper() {
281
- kareem.execPreSync(name, this, arguments);
326
+ _this.execPreSync(name, this, arguments);
282
327
 
283
- var toReturn = fn.apply(this, arguments);
328
+ const toReturn = fn.apply(this, arguments);
284
329
 
285
- const result = kareem.execPostSync(name, this, [toReturn]);
330
+ const result = _this.execPostSync(name, this, [toReturn]);
286
331
 
287
332
  return result[0];
288
333
  };
289
- }
334
+ };
290
335
 
291
336
  function _handleWrapError(instance, error, name, context, args, options, callback) {
292
337
  if (options.useErrorHandlers) {
@@ -298,9 +343,19 @@ function _handleWrapError(instance, error, name, context, args, options, callbac
298
343
  }
299
344
  }
300
345
 
346
+ /**
347
+ * Executes pre hooks, followed by the wrapped function, followed by post hooks.
348
+ * @param {String} name The name of the hook
349
+ * @param {Function} fn The function for the hook
350
+ * @param {*} context Overwrite the "this" for the hook
351
+ * @param {Array} args Apply custom arguments to the hook
352
+ * @param {Object} [options]
353
+ * @param {Boolean} [options.checkForPromise]
354
+ * @returns {void}
355
+ */
301
356
  Kareem.prototype.wrap = function(name, fn, context, args, options) {
302
357
  const lastArg = (args.length > 0 ? args[args.length - 1] : null);
303
- let argsWithoutCb = Array.from(args);
358
+ const argsWithoutCb = Array.from(args);
304
359
  typeof lastArg === 'function' && argsWithoutCb.pop();
305
360
  const _this = this;
306
361
 
@@ -311,7 +366,7 @@ Kareem.prototype.wrap = function(name, fn, context, args, options) {
311
366
  if (error && !(error instanceof Kareem.skipWrappedFunction)) {
312
367
  const numCallbackParams = options.numCallbackParams || 0;
313
368
  const errorArgs = options.contextParameter ? [context] : [];
314
- for (var i = errorArgs.length; i < numCallbackParams; ++i) {
369
+ for (let i = errorArgs.length; i < numCallbackParams; ++i) {
315
370
  errorArgs.push(null);
316
371
  }
317
372
  return _handleWrapError(_this, error, name, context, errorArgs,
@@ -365,13 +420,18 @@ Kareem.prototype.wrap = function(name, fn, context, args, options) {
365
420
  }
366
421
  arguments[0]
367
422
  ? lastArg(arguments[0])
368
- : lastArg.apply(context, arguments)
423
+ : lastArg.apply(context, arguments);
369
424
  });
370
425
  }
371
426
  }
372
427
  });
373
428
  };
374
429
 
430
+ /**
431
+ * Filter current instance for something specific and return the filtered clone
432
+ * @param {Function} fn The filter function
433
+ * @returns {Kareem} The cloned and filtered instance
434
+ */
375
435
  Kareem.prototype.filter = function(fn) {
376
436
  const clone = this.clone();
377
437
 
@@ -408,12 +468,25 @@ Kareem.prototype.filter = function(fn) {
408
468
  return clone;
409
469
  };
410
470
 
471
+ /**
472
+ * Check for a "name" to exist either in pre or post hooks
473
+ * @param {String} name The name of the hook
474
+ * @returns {Boolean} "true" if found, "false" otherwise
475
+ */
411
476
  Kareem.prototype.hasHooks = function(name) {
412
477
  return this._pres.has(name) || this._posts.has(name);
413
478
  };
414
479
 
480
+ /**
481
+ * Create a Wrapper for "fn" on "name" and return the wrapped function
482
+ * @param {String} name The name of the hook
483
+ * @param {Function} fn The function to wrap
484
+ * @param {*} context Overwrite the "this" for the hook
485
+ * @param {Object} [options]
486
+ * @returns {Function} The wrapped function
487
+ */
415
488
  Kareem.prototype.createWrapper = function(name, fn, context, options) {
416
- var _this = this;
489
+ const _this = this;
417
490
  if (!this.hasHooks(name)) {
418
491
  // Fast path: if there's no hooks for this function, just return the
419
492
  // function wrapped in a nextTick()
@@ -422,11 +495,20 @@ Kareem.prototype.createWrapper = function(name, fn, context, options) {
422
495
  };
423
496
  }
424
497
  return function() {
425
- var _context = context || this;
498
+ const _context = context || this;
426
499
  _this.wrap(name, fn, _context, Array.from(arguments), options);
427
500
  };
428
501
  };
429
502
 
503
+ /**
504
+ * Register a new hook for "pre"
505
+ * @param {String} name The name of the hook
506
+ * @param {Boolean} [isAsync]
507
+ * @param {Function} fn The function to register for "name"
508
+ * @param {never} error Unused
509
+ * @param {Boolean} [unshift] Wheter to "push" or to "unshift" the new hook
510
+ * @returns {Kareem}
511
+ */
430
512
  Kareem.prototype.pre = function(name, isAsync, fn, error, unshift) {
431
513
  let options = {};
432
514
  if (typeof isAsync === 'object' && isAsync !== null) {
@@ -458,8 +540,16 @@ Kareem.prototype.pre = function(name, isAsync, fn, error, unshift) {
458
540
  return this;
459
541
  };
460
542
 
543
+ /**
544
+ * Register a new hook for "post"
545
+ * @param {String} name The name of the hook
546
+ * @param {Object} [options]
547
+ * @param {Function} fn The function to register for "name"
548
+ * @param {Boolean} [unshift] Wheter to "push" or to "unshift" the new hook
549
+ * @returns {Kareem}
550
+ */
461
551
  Kareem.prototype.post = function(name, options, fn, unshift) {
462
- const hooks = this._posts.get(name) || [];
552
+ const posts = this._posts.get(name) || [];
463
553
 
464
554
  if (typeof options === 'function') {
465
555
  unshift = !!fn;
@@ -472,34 +562,44 @@ Kareem.prototype.post = function(name, options, fn, unshift) {
472
562
  }
473
563
 
474
564
  if (unshift) {
475
- hooks.unshift(Object.assign({}, options, { fn: fn }));
565
+ posts.unshift(Object.assign({}, options, { fn: fn }));
476
566
  } else {
477
- hooks.push(Object.assign({}, options, { fn: fn }));
567
+ posts.push(Object.assign({}, options, { fn: fn }));
478
568
  }
479
- this._posts.set(name, hooks);
569
+ this._posts.set(name, posts);
480
570
  return this;
481
571
  };
482
572
 
573
+ /**
574
+ * Clone the current instance
575
+ * @returns {Kareem} The cloned instance
576
+ */
483
577
  Kareem.prototype.clone = function() {
484
578
  const n = new Kareem();
485
579
 
486
- for (let key of this._pres.keys()) {
580
+ for (const key of this._pres.keys()) {
487
581
  const clone = this._pres.get(key).slice();
488
582
  clone.numAsync = this._pres.get(key).numAsync;
489
583
  n._pres.set(key, clone);
490
584
  }
491
- for (let key of this._posts.keys()) {
585
+ for (const key of this._posts.keys()) {
492
586
  n._posts.set(key, this._posts.get(key).slice());
493
587
  }
494
588
 
495
589
  return n;
496
590
  };
497
591
 
592
+ /**
593
+ * Merge "other" into self or "clone"
594
+ * @param {Kareem} other The instance to merge with
595
+ * @param {Kareem} [clone] The instance to merge onto (if not defined, using "this")
596
+ * @returns {Kareem} The merged instance
597
+ */
498
598
  Kareem.prototype.merge = function(other, clone) {
499
599
  clone = arguments.length === 1 ? true : clone;
500
- var ret = clone ? this.clone() : this;
600
+ const ret = clone ? this.clone() : this;
501
601
 
502
- for (let key of other._pres.keys()) {
602
+ for (const key of other._pres.keys()) {
503
603
  const sourcePres = ret._pres.get(key) || [];
504
604
  const deduplicated = other._pres.get(key).
505
605
  // Deduplicate based on `fn`
@@ -509,7 +609,7 @@ Kareem.prototype.merge = function(other, clone) {
509
609
  combined.numAsync += deduplicated.filter(p => p.isAsync).length;
510
610
  ret._pres.set(key, combined);
511
611
  }
512
- for (let key of other._posts.keys()) {
612
+ for (const key of other._posts.keys()) {
513
613
  const sourcePosts = ret._posts.get(key) || [];
514
614
  const deduplicated = other._posts.get(key).
515
615
  filter(p => sourcePosts.indexOf(p) === -1);
@@ -537,8 +637,8 @@ function isPromiseLike(v) {
537
637
  }
538
638
 
539
639
  function decorateNextFn(fn) {
540
- var called = false;
541
- var _this = this;
640
+ let called = false;
641
+ const _this = this;
542
642
  return function() {
543
643
  // Ensure this function can only be called once
544
644
  if (called) {
@@ -551,8 +651,15 @@ function decorateNextFn(fn) {
551
651
  };
552
652
  }
553
653
 
554
- const nextTick = typeof process === 'object' && process !== null && process.nextTick || function nextTick(cb) {
555
- setTimeout(cb, 0);
654
+ const nextTick = typeof process === 'object' && process !== null && process.nextTick || function nextTick(cb) {
655
+ setTimeout(cb, 0);
656
+ };
657
+
658
+ function isErrorHandlingMiddleware(post, numArgs) {
659
+ if (post.errorHandler) {
660
+ return true;
661
+ }
662
+ return post.fn.length === numArgs + 2;
556
663
  }
557
664
 
558
665
  module.exports = Kareem;
package/package.json CHANGED
@@ -1,11 +1,13 @@
1
1
  {
2
2
  "name": "kareem",
3
- "version": "2.4.0",
3
+ "version": "2.5.0",
4
4
  "description": "Next-generation take on pre/post function hooks",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
+ "lint": "eslint .",
7
8
  "test": "mocha ./test/*",
8
- "test-travis": "nyc mocha ./test/*"
9
+ "test-coverage": "nyc --reporter lcov mocha ./test/*",
10
+ "docs": "node ./docs.js"
9
11
  },
10
12
  "repository": {
11
13
  "type": "git",
@@ -13,10 +15,17 @@
13
15
  },
14
16
  "devDependencies": {
15
17
  "acquit": "1.x",
16
- "acquit-ignore": "0.1.x",
18
+ "acquit-ignore": "0.2.x",
19
+ "eslint": "8.20.0",
17
20
  "mocha": "9.2.0",
18
21
  "nyc": "15.1.0"
19
22
  },
20
23
  "author": "Valeri Karpov <val@karpov.io>",
21
- "license": "Apache-2.0"
24
+ "license": "Apache-2.0",
25
+ "files": [
26
+ "index.js"
27
+ ],
28
+ "engines": {
29
+ "node": ">=12.0.0"
30
+ }
22
31
  }
@@ -1,30 +0,0 @@
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/.travis.yml DELETED
@@ -1,12 +0,0 @@
1
- language: node_js
2
- node_js:
3
- - "12"
4
- - "10"
5
- - "9"
6
- - "8"
7
- - "7"
8
- - "6"
9
- - "5"
10
- - "4"
11
- script: "npm run-script test-travis"
12
- after_script: "npm install coveralls@2.10.0 && cat ./coverage/lcov.info | coveralls"