@webex/common 2.59.1 → 2.59.3-next.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.
Files changed (80) hide show
  1. package/.eslintrc.js +6 -6
  2. package/README.md +42 -42
  3. package/babel.config.js +3 -3
  4. package/dist/base64.js +22 -22
  5. package/dist/base64.js.map +1 -1
  6. package/dist/browser-detection.js.map +1 -1
  7. package/dist/capped-debounce.js +12 -12
  8. package/dist/capped-debounce.js.map +1 -1
  9. package/dist/check-required.js +8 -8
  10. package/dist/check-required.js.map +1 -1
  11. package/dist/constants.js.map +1 -1
  12. package/dist/defer.js +13 -13
  13. package/dist/defer.js.map +1 -1
  14. package/dist/deprecated.js +5 -5
  15. package/dist/deprecated.js.map +1 -1
  16. package/dist/event-envelope.js +11 -11
  17. package/dist/event-envelope.js.map +1 -1
  18. package/dist/events.js +15 -15
  19. package/dist/events.js.map +1 -1
  20. package/dist/exception.js +13 -13
  21. package/dist/exception.js.map +1 -1
  22. package/dist/in-browser/browser.js +2 -2
  23. package/dist/in-browser/browser.js.map +1 -1
  24. package/dist/in-browser/index.js.map +1 -1
  25. package/dist/in-browser/node.js +2 -2
  26. package/dist/in-browser/node.js.map +1 -1
  27. package/dist/index.js.map +1 -1
  28. package/dist/isBuffer.js +6 -6
  29. package/dist/isBuffer.js.map +1 -1
  30. package/dist/make-state-datatype.js +14 -14
  31. package/dist/make-state-datatype.js.map +1 -1
  32. package/dist/one-flight.js +13 -13
  33. package/dist/one-flight.js.map +1 -1
  34. package/dist/patterns.js +30 -30
  35. package/dist/patterns.js.map +1 -1
  36. package/dist/resolve-with.js +19 -19
  37. package/dist/resolve-with.js.map +1 -1
  38. package/dist/retry.js +17 -17
  39. package/dist/retry.js.map +1 -1
  40. package/dist/tap.js +14 -14
  41. package/dist/tap.js.map +1 -1
  42. package/dist/template-container.js +51 -51
  43. package/dist/template-container.js.map +1 -1
  44. package/dist/uuid-utils.js +76 -76
  45. package/dist/uuid-utils.js.map +1 -1
  46. package/dist/while-in-flight.js +5 -5
  47. package/dist/while-in-flight.js.map +1 -1
  48. package/jest.config.js +3 -3
  49. package/package.json +12 -11
  50. package/process +1 -1
  51. package/src/base64.js +67 -67
  52. package/src/browser-detection.js +37 -37
  53. package/src/capped-debounce.js +65 -65
  54. package/src/check-required.js +18 -18
  55. package/src/constants.js +79 -79
  56. package/src/defer.js +24 -24
  57. package/src/deprecated.js +19 -19
  58. package/src/event-envelope.js +54 -54
  59. package/src/events.js +55 -55
  60. package/src/exception.js +45 -45
  61. package/src/in-browser/browser.js +5 -5
  62. package/src/in-browser/index.js +11 -11
  63. package/src/in-browser/node.js +5 -5
  64. package/src/index.js +44 -44
  65. package/src/isBuffer.js +12 -12
  66. package/src/make-state-datatype.js +91 -91
  67. package/src/one-flight.js +89 -89
  68. package/src/patterns.js +51 -51
  69. package/src/resolve-with.js +27 -27
  70. package/src/retry.js +124 -124
  71. package/src/tap.js +25 -25
  72. package/src/template-container.js +222 -222
  73. package/src/uuid-utils.js +189 -189
  74. package/src/while-in-flight.js +38 -38
  75. package/test/unit/spec/capped-debounce.js +103 -103
  76. package/test/unit/spec/common.js +42 -42
  77. package/test/unit/spec/exception.js +102 -102
  78. package/test/unit/spec/one-flight.js +211 -211
  79. package/test/unit/spec/template-container.js +81 -81
  80. package/test/unit/spec/while-in-flight.js +70 -70
package/src/one-flight.js CHANGED
@@ -1,89 +1,89 @@
1
- /*!
2
- * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
- */
4
-
5
- import {wrap} from 'lodash';
6
-
7
- import make from './template-container';
8
-
9
- // Alias Map and WeakMap to get around a babel compiler bug
10
- const W = WeakMap;
11
- const M = Map;
12
- const WeakMappedMappedMap = make(W, M, M);
13
-
14
- const flights = new WeakMappedMappedMap();
15
-
16
- /**
17
- * @memberof Util
18
- * @param {Object} options
19
- * @param {Function} options.keyFactory
20
- * @param {boolean} options.cacheFailures
21
- * @param {boolean} options.cacheSuccesses
22
- * @returns {Function}
23
- */
24
- export default function oneFlight(...params) {
25
- if (params.length === 3) {
26
- return Reflect.apply(oneFlightDecorator, null, params);
27
- }
28
-
29
- const options = params[0] || {};
30
-
31
- const {cacheFailures, cacheSuccesses, keyFactory} = options;
32
-
33
- return oneFlightDecorator;
34
-
35
- /**
36
- * @param {Object} target
37
- * @param {string} prop
38
- * @param {Object} descriptor
39
- * @private
40
- * @returns {Object}
41
- */
42
- function oneFlightDecorator(target, prop, descriptor) {
43
- const key = prop;
44
-
45
- descriptor.value = wrap(descriptor.value, function oneFlightExecutor(fn, ...args) {
46
- let innerKey = key;
47
-
48
- if (keyFactory) {
49
- innerKey = `${innerKey}_${keyFactory(...args)}`;
50
- }
51
-
52
- /* eslint no-invalid-this: [0] */
53
- let flight = flights.get(this, target, innerKey);
54
-
55
- if (flight) {
56
- return flight;
57
- }
58
-
59
- flight = Reflect.apply(fn, this, args);
60
- if (!cacheFailures && flight && flight.catch) {
61
- flight = flight.catch((reason) => {
62
- flights.delete(this, target, innerKey);
63
-
64
- return Promise.reject(reason);
65
- });
66
- }
67
-
68
- if (!cacheSuccesses && flight && flight.then) {
69
- flight = flight.then((result) => {
70
- flights.delete(this, target, innerKey);
71
-
72
- return result;
73
- });
74
- }
75
-
76
- flights.set(this, target, innerKey, flight);
77
-
78
- return flight;
79
- });
80
-
81
- // This *should* make decorators compatible with AmpersandState class
82
- // definitions
83
- if (typeof target === 'object' && !target.prototype) {
84
- target[prop] = descriptor.value;
85
- }
86
-
87
- return descriptor;
88
- }
89
- }
1
+ /*!
2
+ * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
+ */
4
+
5
+ import {wrap} from 'lodash';
6
+
7
+ import make from './template-container';
8
+
9
+ // Alias Map and WeakMap to get around a babel compiler bug
10
+ const W = WeakMap;
11
+ const M = Map;
12
+ const WeakMappedMappedMap = make(W, M, M);
13
+
14
+ const flights = new WeakMappedMappedMap();
15
+
16
+ /**
17
+ * @memberof Util
18
+ * @param {Object} options
19
+ * @param {Function} options.keyFactory
20
+ * @param {boolean} options.cacheFailures
21
+ * @param {boolean} options.cacheSuccesses
22
+ * @returns {Function}
23
+ */
24
+ export default function oneFlight(...params) {
25
+ if (params.length === 3) {
26
+ return Reflect.apply(oneFlightDecorator, null, params);
27
+ }
28
+
29
+ const options = params[0] || {};
30
+
31
+ const {cacheFailures, cacheSuccesses, keyFactory} = options;
32
+
33
+ return oneFlightDecorator;
34
+
35
+ /**
36
+ * @param {Object} target
37
+ * @param {string} prop
38
+ * @param {Object} descriptor
39
+ * @private
40
+ * @returns {Object}
41
+ */
42
+ function oneFlightDecorator(target, prop, descriptor) {
43
+ const key = prop;
44
+
45
+ descriptor.value = wrap(descriptor.value, function oneFlightExecutor(fn, ...args) {
46
+ let innerKey = key;
47
+
48
+ if (keyFactory) {
49
+ innerKey = `${innerKey}_${keyFactory(...args)}`;
50
+ }
51
+
52
+ /* eslint no-invalid-this: [0] */
53
+ let flight = flights.get(this, target, innerKey);
54
+
55
+ if (flight) {
56
+ return flight;
57
+ }
58
+
59
+ flight = Reflect.apply(fn, this, args);
60
+ if (!cacheFailures && flight && flight.catch) {
61
+ flight = flight.catch((reason) => {
62
+ flights.delete(this, target, innerKey);
63
+
64
+ return Promise.reject(reason);
65
+ });
66
+ }
67
+
68
+ if (!cacheSuccesses && flight && flight.then) {
69
+ flight = flight.then((result) => {
70
+ flights.delete(this, target, innerKey);
71
+
72
+ return result;
73
+ });
74
+ }
75
+
76
+ flights.set(this, target, innerKey, flight);
77
+
78
+ return flight;
79
+ });
80
+
81
+ // This *should* make decorators compatible with AmpersandState class
82
+ // definitions
83
+ if (typeof target === 'object' && !target.prototype) {
84
+ target[prop] = descriptor.value;
85
+ }
86
+
87
+ return descriptor;
88
+ }
89
+ }
package/src/patterns.js CHANGED
@@ -1,51 +1,51 @@
1
- /*!
2
- * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
- */
4
-
5
- /**
6
- * @description Set of regex patterns to compile once and use throughout the
7
- * app. All non-prefixed patterns have start/end characters to ensure exact
8
- * matches. Patterns prefixed with "exec" are the same as their non-prefixed
9
- * counterparts but without the start/end characters so they can be used with
10
- * methods like `RegExp#exec`.
11
- */
12
- export default {
13
- /**
14
- * Regular express that validates a string is strictly an email.
15
- * Allows for validation of emails within services such as conversation
16
- * activities or user details.
17
- * See [RegEx information here]{@link https://ihateregex.io/expr/email-2}.
18
- *
19
- * @type {RegExp}
20
- */
21
- email:
22
- /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
23
-
24
- /**
25
- * Regular expression that validates an ambiguous string contains emails
26
- * (one or more) within.
27
- * See [RegEx information here]{@link https://ihateregex.io/expr/email-2}.
28
- *
29
- * @type {RegExp}
30
- */
31
- containsEmails:
32
- /(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/g,
33
-
34
- /**
35
- * Matches a UUID
36
- * @type {RegExp}
37
- */
38
- uuid: /^[a-f\d]{8}(?:-[a-f\d]{4}){3}-[a-f\d]{12}$/,
39
-
40
- /**
41
- * Same as this.email, but allows for surrounding characters
42
- * @type {RegExp}
43
- */
44
- execEmail: /[^\s]+?@[^\s]+?/,
45
-
46
- /**
47
- * Same as this.uuid but allows for surrounding characters
48
- * @type {RegExp}
49
- */
50
- execUuid: /[a-f\d]{8}(?:-[a-f\d]{4}){3}-[a-f\d]{12}/,
51
- };
1
+ /*!
2
+ * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
+ */
4
+
5
+ /**
6
+ * @description Set of regex patterns to compile once and use throughout the
7
+ * app. All non-prefixed patterns have start/end characters to ensure exact
8
+ * matches. Patterns prefixed with "exec" are the same as their non-prefixed
9
+ * counterparts but without the start/end characters so they can be used with
10
+ * methods like `RegExp#exec`.
11
+ */
12
+ export default {
13
+ /**
14
+ * Regular express that validates a string is strictly an email.
15
+ * Allows for validation of emails within services such as conversation
16
+ * activities or user details.
17
+ * See [RegEx information here]{@link https://ihateregex.io/expr/email-2}.
18
+ *
19
+ * @type {RegExp}
20
+ */
21
+ email:
22
+ /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
23
+
24
+ /**
25
+ * Regular expression that validates an ambiguous string contains emails
26
+ * (one or more) within.
27
+ * See [RegEx information here]{@link https://ihateregex.io/expr/email-2}.
28
+ *
29
+ * @type {RegExp}
30
+ */
31
+ containsEmails:
32
+ /(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/g,
33
+
34
+ /**
35
+ * Matches a UUID
36
+ * @type {RegExp}
37
+ */
38
+ uuid: /^[a-f\d]{8}(?:-[a-f\d]{4}){3}-[a-f\d]{12}$/,
39
+
40
+ /**
41
+ * Same as this.email, but allows for surrounding characters
42
+ * @type {RegExp}
43
+ */
44
+ execEmail: /[^\s]+?@[^\s]+?/,
45
+
46
+ /**
47
+ * Same as this.uuid but allows for surrounding characters
48
+ * @type {RegExp}
49
+ */
50
+ execUuid: /[a-f\d]{8}(?:-[a-f\d]{4}){3}-[a-f\d]{12}/,
51
+ };
@@ -1,27 +1,27 @@
1
- /*!
2
- * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
- */
4
-
5
- /**
6
- * Sugar method for returning the desired object at the end of a promise chain
7
- * @param {any} object the item with which to resolve the promise chain
8
- * @returns {function}
9
- * @example
10
- * var item = {
11
- * prop: 2
12
- * };
13
- * Promise
14
- * .resolve(item.prop)
15
- * .then(resolveWith(item))
16
- * .then(function(res) {
17
- * require('assert').deepEqual(res, {prop:2});
18
- * return 'success'
19
- * })
20
- * // => success
21
- *
22
- */
23
- export default function resolveWith(object) {
24
- return function resolver() {
25
- return Promise.resolve(object);
26
- };
27
- }
1
+ /*!
2
+ * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
+ */
4
+
5
+ /**
6
+ * Sugar method for returning the desired object at the end of a promise chain
7
+ * @param {any} object the item with which to resolve the promise chain
8
+ * @returns {function}
9
+ * @example
10
+ * var item = {
11
+ * prop: 2
12
+ * };
13
+ * Promise
14
+ * .resolve(item.prop)
15
+ * .then(resolveWith(item))
16
+ * .then(function(res) {
17
+ * require('assert').deepEqual(res, {prop:2});
18
+ * return 'success'
19
+ * })
20
+ * // => success
21
+ *
22
+ */
23
+ export default function resolveWith(object) {
24
+ return function resolver() {
25
+ return Promise.resolve(object);
26
+ };
27
+ }
package/src/retry.js CHANGED
@@ -1,124 +1,124 @@
1
- /*!
2
- * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
- */
4
-
5
- import {EventEmitter} from 'events';
6
-
7
- import {defaults, isFunction, wrap} from 'lodash';
8
- import backoff from 'backoff';
9
-
10
- /* eslint max-nested-callbacks: [0] */
11
-
12
- /**
13
- * Makes a promise-returning method retryable according to the specified backoff
14
- * pattern
15
- * @param {Object} options
16
- * @param {boolean} options.backoff
17
- * @param {number} options.delay
18
- * @param {number} options.initialDelay
19
- * @param {number} options.maxAttempts
20
- * @param {number} options.maxDelay
21
- *
22
- * @returns {Function}
23
- */
24
- export default function retry(...params) {
25
- let options = params[0] || {};
26
-
27
- options = {...options};
28
- defaults(options, {
29
- backoff: true,
30
- delay: 1,
31
- maxAttempts: 3,
32
- });
33
-
34
- let strategyOptions;
35
-
36
- if (options.backoff) {
37
- strategyOptions = {
38
- initialDelay: options.delay,
39
- maxDelay: options.maxDelay,
40
- };
41
- } else {
42
- strategyOptions = {
43
- initialDelay: 1,
44
- maxDelay: 1,
45
- };
46
- }
47
-
48
- if (params.length === 3) {
49
- return Reflect.apply(retryDecorator, null, params);
50
- }
51
-
52
- return retryDecorator;
53
-
54
- /**
55
- * @param {Object} target
56
- * @param {string} prop
57
- * @param {Object} descriptor
58
- * @private
59
- * @returns {Object}
60
- */
61
- function retryDecorator(target, prop, descriptor) {
62
- descriptor.value = wrap(descriptor.value, function retryExecutor(fn, ...args) {
63
- const emitter = new EventEmitter();
64
- const promise = new Promise((resolve, reject) => {
65
- // backoff.call is not Function.prototype.call; it's an unfortunate naming
66
- // collision.
67
- /* eslint prefer-reflect: [0] */
68
- const call = backoff.call(
69
- (cb) => {
70
- /* eslint no-invalid-this: [0] */
71
- const innerPromise = Reflect.apply(fn, this, args);
72
-
73
- if (isFunction(innerPromise.on)) {
74
- innerPromise.on('progress', emitter.emit.bind(emitter, 'progress'));
75
- innerPromise.on('upload-progress', emitter.emit.bind(emitter, 'upload-progress'));
76
- innerPromise.on('download-progress', emitter.emit.bind(emitter, 'download-progress'));
77
- }
78
-
79
- return innerPromise
80
- .then((res) => {
81
- cb(null, res);
82
- })
83
- .catch((reason) => {
84
- if (!reason) {
85
- reason = new Error('retryable method failed without providing an error object');
86
- }
87
- cb(reason);
88
- });
89
- },
90
- (err, res) => {
91
- if (err) {
92
- return reject(err);
93
- }
94
-
95
- return resolve(res);
96
- }
97
- );
98
-
99
- call.setStrategy(new backoff.ExponentialStrategy(strategyOptions));
100
- if (options.maxAttempts) {
101
- call.failAfter(options.maxAttempts - 1);
102
- }
103
-
104
- call.start();
105
- });
106
-
107
- promise.on = function on(key, callback) {
108
- emitter.on(key, callback);
109
-
110
- return promise;
111
- };
112
-
113
- return promise;
114
- });
115
-
116
- // This *should* make decorators compatible with AmpersandState class
117
- // definitions
118
- if (typeof target === 'object' && !target.prototype) {
119
- target[prop] = descriptor.value;
120
- }
121
-
122
- return descriptor;
123
- }
124
- }
1
+ /*!
2
+ * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
+ */
4
+
5
+ import {EventEmitter} from 'events';
6
+
7
+ import {defaults, isFunction, wrap} from 'lodash';
8
+ import backoff from 'backoff';
9
+
10
+ /* eslint max-nested-callbacks: [0] */
11
+
12
+ /**
13
+ * Makes a promise-returning method retryable according to the specified backoff
14
+ * pattern
15
+ * @param {Object} options
16
+ * @param {boolean} options.backoff
17
+ * @param {number} options.delay
18
+ * @param {number} options.initialDelay
19
+ * @param {number} options.maxAttempts
20
+ * @param {number} options.maxDelay
21
+ *
22
+ * @returns {Function}
23
+ */
24
+ export default function retry(...params) {
25
+ let options = params[0] || {};
26
+
27
+ options = {...options};
28
+ defaults(options, {
29
+ backoff: true,
30
+ delay: 1,
31
+ maxAttempts: 3,
32
+ });
33
+
34
+ let strategyOptions;
35
+
36
+ if (options.backoff) {
37
+ strategyOptions = {
38
+ initialDelay: options.delay,
39
+ maxDelay: options.maxDelay,
40
+ };
41
+ } else {
42
+ strategyOptions = {
43
+ initialDelay: 1,
44
+ maxDelay: 1,
45
+ };
46
+ }
47
+
48
+ if (params.length === 3) {
49
+ return Reflect.apply(retryDecorator, null, params);
50
+ }
51
+
52
+ return retryDecorator;
53
+
54
+ /**
55
+ * @param {Object} target
56
+ * @param {string} prop
57
+ * @param {Object} descriptor
58
+ * @private
59
+ * @returns {Object}
60
+ */
61
+ function retryDecorator(target, prop, descriptor) {
62
+ descriptor.value = wrap(descriptor.value, function retryExecutor(fn, ...args) {
63
+ const emitter = new EventEmitter();
64
+ const promise = new Promise((resolve, reject) => {
65
+ // backoff.call is not Function.prototype.call; it's an unfortunate naming
66
+ // collision.
67
+ /* eslint prefer-reflect: [0] */
68
+ const call = backoff.call(
69
+ (cb) => {
70
+ /* eslint no-invalid-this: [0] */
71
+ const innerPromise = Reflect.apply(fn, this, args);
72
+
73
+ if (isFunction(innerPromise.on)) {
74
+ innerPromise.on('progress', emitter.emit.bind(emitter, 'progress'));
75
+ innerPromise.on('upload-progress', emitter.emit.bind(emitter, 'upload-progress'));
76
+ innerPromise.on('download-progress', emitter.emit.bind(emitter, 'download-progress'));
77
+ }
78
+
79
+ return innerPromise
80
+ .then((res) => {
81
+ cb(null, res);
82
+ })
83
+ .catch((reason) => {
84
+ if (!reason) {
85
+ reason = new Error('retryable method failed without providing an error object');
86
+ }
87
+ cb(reason);
88
+ });
89
+ },
90
+ (err, res) => {
91
+ if (err) {
92
+ return reject(err);
93
+ }
94
+
95
+ return resolve(res);
96
+ }
97
+ );
98
+
99
+ call.setStrategy(new backoff.ExponentialStrategy(strategyOptions));
100
+ if (options.maxAttempts) {
101
+ call.failAfter(options.maxAttempts - 1);
102
+ }
103
+
104
+ call.start();
105
+ });
106
+
107
+ promise.on = function on(key, callback) {
108
+ emitter.on(key, callback);
109
+
110
+ return promise;
111
+ };
112
+
113
+ return promise;
114
+ });
115
+
116
+ // This *should* make decorators compatible with AmpersandState class
117
+ // definitions
118
+ if (typeof target === 'object' && !target.prototype) {
119
+ target[prop] = descriptor.value;
120
+ }
121
+
122
+ return descriptor;
123
+ }
124
+ }
package/src/tap.js CHANGED
@@ -1,25 +1,25 @@
1
- /*!
2
- * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
- */
4
-
5
- /**
6
- * Injects code into a promise chain without modifying the promise chain's result
7
- * @param {Function} fn
8
- * @returns {Promise}
9
- * @example
10
- * function f() {
11
- * return Promise.resolve(5);
12
- * }
13
- *
14
- * f()
15
- * .then(tap(() => 12))
16
- * // => 5
17
- */
18
- export default function tap(fn) {
19
- return (r) =>
20
- new Promise((resolve) => {
21
- resolve(fn(r));
22
- })
23
- .then(() => r)
24
- .catch(() => r);
25
- }
1
+ /*!
2
+ * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
+ */
4
+
5
+ /**
6
+ * Injects code into a promise chain without modifying the promise chain's result
7
+ * @param {Function} fn
8
+ * @returns {Promise}
9
+ * @example
10
+ * function f() {
11
+ * return Promise.resolve(5);
12
+ * }
13
+ *
14
+ * f()
15
+ * .then(tap(() => 12))
16
+ * // => 5
17
+ */
18
+ export default function tap(fn) {
19
+ return (r) =>
20
+ new Promise((resolve) => {
21
+ resolve(fn(r));
22
+ })
23
+ .then(() => r)
24
+ .catch(() => r);
25
+ }