kareem 2.4.1 → 2.5.1

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,12 @@ 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) {
87
+ if (i === _args.length - 1 && typeof _args[i] === 'function') {
88
+ continue; // skip callbacks to avoid accidentally calling the callback from a hook
89
+ }
76
90
  args.push(_args[i]);
77
91
  }
78
92
 
@@ -103,7 +117,7 @@ Kareem.prototype.execPre = function(name, context, args, callback) {
103
117
  next();
104
118
  }
105
119
  }
106
- };
120
+ }
107
121
 
108
122
  next.apply(null, [null].concat(args));
109
123
 
@@ -133,25 +147,41 @@ Kareem.prototype.execPre = function(name, context, args, callback) {
133
147
  }
134
148
  };
135
149
 
150
+ /**
151
+ * Execute all "pre" hooks for "name" synchronously
152
+ * @param {String} name The hook name to execute
153
+ * @param {*} context Overwrite the "this" for the hook
154
+ * @param {Array} [args] Apply custom arguments to the hook
155
+ * @returns {void}
156
+ */
136
157
  Kareem.prototype.execPreSync = function(name, context, args) {
137
- var pres = this._pres.get(name) || [];
138
- var numPres = pres.length;
158
+ const pres = this._pres.get(name) || [];
159
+ const numPres = pres.length;
139
160
 
140
- for (var i = 0; i < numPres; ++i) {
161
+ for (let i = 0; i < numPres; ++i) {
141
162
  pres[i].fn.apply(context, args || []);
142
163
  }
143
164
  };
144
165
 
166
+ /**
167
+ * Execute all "post" hooks for "name"
168
+ * @param {String} name The hook name to execute
169
+ * @param {*} context Overwrite the "this" for the hook
170
+ * @param {Array|Function} args Apply custom arguments to the hook
171
+ * @param {*} options Optional options or directly the callback
172
+ * @param {Function} [callback] The callback to call when executing all hooks are finished
173
+ * @returns {void}
174
+ */
145
175
  Kareem.prototype.execPost = function(name, context, args, options, callback) {
146
176
  if (arguments.length < 5) {
147
177
  callback = options;
148
178
  options = null;
149
179
  }
150
- var posts = this._posts.get(name) || [];
151
- var numPosts = posts.length;
152
- var currentPost = 0;
180
+ const posts = this._posts.get(name) || [];
181
+ const numPosts = posts.length;
182
+ let currentPost = 0;
153
183
 
154
- var firstError = null;
184
+ let firstError = null;
155
185
  if (options && options.error) {
156
186
  firstError = options.error;
157
187
  }
@@ -162,12 +192,12 @@ Kareem.prototype.execPost = function(name, context, args, options, callback) {
162
192
  });
163
193
  }
164
194
 
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) {
195
+ function next() {
196
+ const post = posts[currentPost].fn;
197
+ let numArgs = 0;
198
+ const argLength = args.length;
199
+ const newArgs = [];
200
+ for (let i = 0; i < argLength; ++i) {
171
201
  numArgs += args[i] && args[i]._kareemIgnore ? 0 : 1;
172
202
  if (!args[i] || !args[i]._kareemIgnore) {
173
203
  newArgs.push(args[i]);
@@ -175,7 +205,7 @@ Kareem.prototype.execPost = function(name, context, args, options, callback) {
175
205
  }
176
206
 
177
207
  if (firstError) {
178
- if (post.length === numArgs + 2) {
208
+ if (isErrorHandlingMiddleware(posts[currentPost], numArgs)) {
179
209
  const _cb = decorateNextFn(function(error) {
180
210
  if (error) {
181
211
  if (error instanceof Kareem.overwriteResult) {
@@ -222,7 +252,7 @@ Kareem.prototype.execPost = function(name, context, args, options, callback) {
222
252
  next();
223
253
  });
224
254
 
225
- if (post.length === numArgs + 2) {
255
+ if (isErrorHandlingMiddleware(posts[currentPost], numArgs)) {
226
256
  // Skip error handlers if no error
227
257
  if (++currentPost >= numPosts) {
228
258
  return callback.apply(null, [null].concat(args));
@@ -261,11 +291,18 @@ Kareem.prototype.execPost = function(name, context, args, options, callback) {
261
291
  next();
262
292
  }
263
293
  }
264
- };
294
+ }
265
295
 
266
296
  next();
267
297
  };
268
298
 
299
+ /**
300
+ * Execute all "post" hooks for "name" synchronously
301
+ * @param {String} name The hook name to execute
302
+ * @param {*} context Overwrite the "this" for the hook
303
+ * @param {Array|Function} args Apply custom arguments to the hook
304
+ * @returns {Array} The used arguments
305
+ */
269
306
  Kareem.prototype.execPostSync = function(name, context, args) {
270
307
  const posts = this._posts.get(name) || [];
271
308
  const numPosts = posts.length;
@@ -280,14 +317,20 @@ Kareem.prototype.execPostSync = function(name, context, args) {
280
317
  return args;
281
318
  };
282
319
 
320
+ /**
321
+ * Create a synchronous wrapper for "fn"
322
+ * @param {String} name The name of the hook
323
+ * @param {Function} fn The function to wrap
324
+ * @returns {Function} The wrapped function
325
+ */
283
326
  Kareem.prototype.createWrapperSync = function(name, fn) {
284
- var kareem = this;
327
+ const _this = this;
285
328
  return function syncWrapper() {
286
- kareem.execPreSync(name, this, arguments);
329
+ _this.execPreSync(name, this, arguments);
287
330
 
288
- var toReturn = fn.apply(this, arguments);
331
+ const toReturn = fn.apply(this, arguments);
289
332
 
290
- const result = kareem.execPostSync(name, this, [toReturn]);
333
+ const result = _this.execPostSync(name, this, [toReturn]);
291
334
 
292
335
  return result[0];
293
336
  };
@@ -303,9 +346,19 @@ function _handleWrapError(instance, error, name, context, args, options, callbac
303
346
  }
304
347
  }
305
348
 
349
+ /**
350
+ * Executes pre hooks, followed by the wrapped function, followed by post hooks.
351
+ * @param {String} name The name of the hook
352
+ * @param {Function} fn The function for the hook
353
+ * @param {*} context Overwrite the "this" for the hook
354
+ * @param {Array} args Apply custom arguments to the hook
355
+ * @param {Object} [options]
356
+ * @param {Boolean} [options.checkForPromise]
357
+ * @returns {void}
358
+ */
306
359
  Kareem.prototype.wrap = function(name, fn, context, args, options) {
307
360
  const lastArg = (args.length > 0 ? args[args.length - 1] : null);
308
- let argsWithoutCb = Array.from(args);
361
+ const argsWithoutCb = Array.from(args);
309
362
  typeof lastArg === 'function' && argsWithoutCb.pop();
310
363
  const _this = this;
311
364
 
@@ -316,7 +369,7 @@ Kareem.prototype.wrap = function(name, fn, context, args, options) {
316
369
  if (error && !(error instanceof Kareem.skipWrappedFunction)) {
317
370
  const numCallbackParams = options.numCallbackParams || 0;
318
371
  const errorArgs = options.contextParameter ? [context] : [];
319
- for (var i = errorArgs.length; i < numCallbackParams; ++i) {
372
+ for (let i = errorArgs.length; i < numCallbackParams; ++i) {
320
373
  errorArgs.push(null);
321
374
  }
322
375
  return _handleWrapError(_this, error, name, context, errorArgs,
@@ -377,6 +430,11 @@ Kareem.prototype.wrap = function(name, fn, context, args, options) {
377
430
  });
378
431
  };
379
432
 
433
+ /**
434
+ * Filter current instance for something specific and return the filtered clone
435
+ * @param {Function} fn The filter function
436
+ * @returns {Kareem} The cloned and filtered instance
437
+ */
380
438
  Kareem.prototype.filter = function(fn) {
381
439
  const clone = this.clone();
382
440
 
@@ -413,12 +471,25 @@ Kareem.prototype.filter = function(fn) {
413
471
  return clone;
414
472
  };
415
473
 
474
+ /**
475
+ * Check for a "name" to exist either in pre or post hooks
476
+ * @param {String} name The name of the hook
477
+ * @returns {Boolean} "true" if found, "false" otherwise
478
+ */
416
479
  Kareem.prototype.hasHooks = function(name) {
417
480
  return this._pres.has(name) || this._posts.has(name);
418
481
  };
419
482
 
483
+ /**
484
+ * Create a Wrapper for "fn" on "name" and return the wrapped function
485
+ * @param {String} name The name of the hook
486
+ * @param {Function} fn The function to wrap
487
+ * @param {*} context Overwrite the "this" for the hook
488
+ * @param {Object} [options]
489
+ * @returns {Function} The wrapped function
490
+ */
420
491
  Kareem.prototype.createWrapper = function(name, fn, context, options) {
421
- var _this = this;
492
+ const _this = this;
422
493
  if (!this.hasHooks(name)) {
423
494
  // Fast path: if there's no hooks for this function, just return the
424
495
  // function wrapped in a nextTick()
@@ -427,11 +498,20 @@ Kareem.prototype.createWrapper = function(name, fn, context, options) {
427
498
  };
428
499
  }
429
500
  return function() {
430
- var _context = context || this;
501
+ const _context = context || this;
431
502
  _this.wrap(name, fn, _context, Array.from(arguments), options);
432
503
  };
433
504
  };
434
505
 
506
+ /**
507
+ * Register a new hook for "pre"
508
+ * @param {String} name The name of the hook
509
+ * @param {Boolean} [isAsync]
510
+ * @param {Function} fn The function to register for "name"
511
+ * @param {never} error Unused
512
+ * @param {Boolean} [unshift] Wheter to "push" or to "unshift" the new hook
513
+ * @returns {Kareem}
514
+ */
435
515
  Kareem.prototype.pre = function(name, isAsync, fn, error, unshift) {
436
516
  let options = {};
437
517
  if (typeof isAsync === 'object' && isAsync !== null) {
@@ -463,8 +543,16 @@ Kareem.prototype.pre = function(name, isAsync, fn, error, unshift) {
463
543
  return this;
464
544
  };
465
545
 
546
+ /**
547
+ * Register a new hook for "post"
548
+ * @param {String} name The name of the hook
549
+ * @param {Object} [options]
550
+ * @param {Function} fn The function to register for "name"
551
+ * @param {Boolean} [unshift] Wheter to "push" or to "unshift" the new hook
552
+ * @returns {Kareem}
553
+ */
466
554
  Kareem.prototype.post = function(name, options, fn, unshift) {
467
- const hooks = this._posts.get(name) || [];
555
+ const posts = this._posts.get(name) || [];
468
556
 
469
557
  if (typeof options === 'function') {
470
558
  unshift = !!fn;
@@ -477,34 +565,44 @@ Kareem.prototype.post = function(name, options, fn, unshift) {
477
565
  }
478
566
 
479
567
  if (unshift) {
480
- hooks.unshift(Object.assign({}, options, { fn: fn }));
568
+ posts.unshift(Object.assign({}, options, { fn: fn }));
481
569
  } else {
482
- hooks.push(Object.assign({}, options, { fn: fn }));
570
+ posts.push(Object.assign({}, options, { fn: fn }));
483
571
  }
484
- this._posts.set(name, hooks);
572
+ this._posts.set(name, posts);
485
573
  return this;
486
574
  };
487
575
 
576
+ /**
577
+ * Clone the current instance
578
+ * @returns {Kareem} The cloned instance
579
+ */
488
580
  Kareem.prototype.clone = function() {
489
581
  const n = new Kareem();
490
582
 
491
- for (let key of this._pres.keys()) {
583
+ for (const key of this._pres.keys()) {
492
584
  const clone = this._pres.get(key).slice();
493
585
  clone.numAsync = this._pres.get(key).numAsync;
494
586
  n._pres.set(key, clone);
495
587
  }
496
- for (let key of this._posts.keys()) {
588
+ for (const key of this._posts.keys()) {
497
589
  n._posts.set(key, this._posts.get(key).slice());
498
590
  }
499
591
 
500
592
  return n;
501
593
  };
502
594
 
595
+ /**
596
+ * Merge "other" into self or "clone"
597
+ * @param {Kareem} other The instance to merge with
598
+ * @param {Kareem} [clone] The instance to merge onto (if not defined, using "this")
599
+ * @returns {Kareem} The merged instance
600
+ */
503
601
  Kareem.prototype.merge = function(other, clone) {
504
602
  clone = arguments.length === 1 ? true : clone;
505
- var ret = clone ? this.clone() : this;
603
+ const ret = clone ? this.clone() : this;
506
604
 
507
- for (let key of other._pres.keys()) {
605
+ for (const key of other._pres.keys()) {
508
606
  const sourcePres = ret._pres.get(key) || [];
509
607
  const deduplicated = other._pres.get(key).
510
608
  // Deduplicate based on `fn`
@@ -514,7 +612,7 @@ Kareem.prototype.merge = function(other, clone) {
514
612
  combined.numAsync += deduplicated.filter(p => p.isAsync).length;
515
613
  ret._pres.set(key, combined);
516
614
  }
517
- for (let key of other._posts.keys()) {
615
+ for (const key of other._posts.keys()) {
518
616
  const sourcePosts = ret._posts.get(key) || [];
519
617
  const deduplicated = other._posts.get(key).
520
618
  filter(p => sourcePosts.indexOf(p) === -1);
@@ -542,8 +640,8 @@ function isPromiseLike(v) {
542
640
  }
543
641
 
544
642
  function decorateNextFn(fn) {
545
- var called = false;
546
- var _this = this;
643
+ let called = false;
644
+ const _this = this;
547
645
  return function() {
548
646
  // Ensure this function can only be called once
549
647
  if (called) {
@@ -556,8 +654,15 @@ function decorateNextFn(fn) {
556
654
  };
557
655
  }
558
656
 
559
- const nextTick = typeof process === 'object' && process !== null && process.nextTick || function nextTick(cb) {
560
- setTimeout(cb, 0);
657
+ const nextTick = typeof process === 'object' && process !== null && process.nextTick || function nextTick(cb) {
658
+ setTimeout(cb, 0);
561
659
  };
562
660
 
661
+ function isErrorHandlingMiddleware(post, numArgs) {
662
+ if (post.errorHandler) {
663
+ return true;
664
+ }
665
+ return post.fn.length === numArgs + 2;
666
+ }
667
+
563
668
  module.exports = Kareem;
package/package.json CHANGED
@@ -1,25 +1,31 @@
1
1
  {
2
2
  "name": "kareem",
3
- "version": "2.4.1",
3
+ "version": "2.5.1",
4
4
  "description": "Next-generation take on pre/post function hooks",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
7
  "lint": "eslint .",
8
8
  "test": "mocha ./test/*",
9
- "test-travis": "nyc mocha ./test/*"
9
+ "test-coverage": "nyc --reporter lcov mocha ./test/*",
10
+ "docs": "node ./docs.js"
10
11
  },
11
12
  "repository": {
12
13
  "type": "git",
13
14
  "url": "git://github.com/vkarpov15/kareem.git"
14
15
  },
15
16
  "devDependencies": {
16
- "@masteringjs/eslint-config": "0.0.1",
17
17
  "acquit": "1.x",
18
- "acquit-ignore": "0.1.x",
19
- "eslint": "8.15.0",
18
+ "acquit-ignore": "0.2.x",
19
+ "eslint": "8.20.0",
20
20
  "mocha": "9.2.0",
21
21
  "nyc": "15.1.0"
22
22
  },
23
23
  "author": "Valeri Karpov <val@karpov.io>",
24
- "license": "Apache-2.0"
24
+ "license": "Apache-2.0",
25
+ "files": [
26
+ "index.js"
27
+ ],
28
+ "engines": {
29
+ "node": ">=12.0.0"
30
+ }
25
31
  }
package/.eslintrc.json DELETED
@@ -1,16 +0,0 @@
1
- {
2
- "extends": [
3
- "@masteringjs"
4
- ],
5
- "parserOptions": {
6
- "ecmaVersion": 2020
7
- },
8
- "env": {
9
- "node": true,
10
- "es6": true
11
- },
12
- "rules": {
13
- "no-var": "off",
14
- "prefer-const": "off"
15
- }
16
- }
@@ -1,47 +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
- name: Node ${{ matrix.node }}
17
- steps:
18
- - uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846 # v3
19
-
20
- - name: Setup node
21
- uses: actions/setup-node@5b52f097d36d4b0b2f94ed6de710023fbb8b2236 # v3.1.0
22
- with:
23
- node-version: ${{ matrix.node }}
24
-
25
- - run: npm install
26
-
27
- - run: npm test
28
-
29
- lint:
30
- runs-on: ${{ matrix.os }}
31
- strategy:
32
- fail-fast: false
33
- matrix:
34
- node: [18]
35
- os: [ubuntu-20.04]
36
- name: Lint
37
- steps:
38
- - uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846 # v3
39
-
40
- - name: Setup node
41
- uses: actions/setup-node@5b52f097d36d4b0b2f94ed6de710023fbb8b2236 # v3.1.0
42
- with:
43
- node-version: ${{ matrix.node }}
44
-
45
- - run: npm install
46
-
47
- - run: npm run lint
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"