@oscarpalmer/atoms 0.152.0 → 0.153.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.
@@ -937,6 +937,82 @@ function debounce(callback, time) {
937
937
  function throttle(callback, time) {
938
938
  return getTimer(TIMER_THROTTLE, callback, time);
939
939
  }
940
+ var RetryError = class extends Error {
941
+ constructor(message, original) {
942
+ super(message);
943
+ this.original = original;
944
+ this.name = ERROR_NAME$1;
945
+ }
946
+ };
947
+ /**
948
+ * Retry a callback a specified number of times, with a delay between attempts
949
+ * @param callback Callback to retry
950
+ * @param options Retry options
951
+ * @returns Callback result
952
+ */
953
+ async function asyncRetry(callback, options) {
954
+ if (typeof callback !== "function") throw new TypeError(MESSAGE_EXPECTATION);
955
+ async function handle() {
956
+ try {
957
+ const result = await callback();
958
+ resolver(result);
959
+ } catch (error) {
960
+ if (attempts >= times || !when(error)) rejector(new RetryError(MESSAGE_FAILED, error));
961
+ else {
962
+ attempts += 1;
963
+ timer();
964
+ }
965
+ }
966
+ }
967
+ const { delay, times, when } = getRetryOptions(options);
968
+ const timer = getTimer(TIMER_WAIT, handle, delay);
969
+ let attempts = 0;
970
+ let rejector;
971
+ let resolver;
972
+ return new Promise((resolve, reject) => {
973
+ rejector = reject;
974
+ resolver = resolve;
975
+ handle();
976
+ });
977
+ }
978
+ function getRetryNumber(value) {
979
+ return typeof value === "number" && value > 0 ? value : 0;
980
+ }
981
+ function getRetryOptions(input) {
982
+ const options = isPlainObject(input) ? input : {};
983
+ return {
984
+ delay: getRetryNumber(options.delay),
985
+ times: getRetryNumber(options.times),
986
+ when: typeof options.when === "function" ? options.when : shouldRetry
987
+ };
988
+ }
989
+ /**
990
+ * Retry a callback a specified number of times
991
+ * @param callback Callback to retry
992
+ * @param options Retry options
993
+ * @returns Callback result
994
+ */
995
+ function retry(callback, options) {
996
+ if (typeof callback !== "function") throw new TypeError(MESSAGE_EXPECTATION);
997
+ const { times, when } = getRetryOptions(options);
998
+ let last;
999
+ for (let index = 0; index <= times; index += 1) try {
1000
+ return callback();
1001
+ } catch (error) {
1002
+ if (index >= times || !when(error)) {
1003
+ last = error;
1004
+ break;
1005
+ }
1006
+ }
1007
+ throw new RetryError(MESSAGE_FAILED, last);
1008
+ }
1009
+ retry.async = asyncRetry;
1010
+ function shouldRetry() {
1011
+ return true;
1012
+ }
1013
+ const ERROR_NAME$1 = "RetryError";
1014
+ const MESSAGE_EXPECTATION = "Retry expected a function";
1015
+ const MESSAGE_FAILED = "Retry failed";
940
1016
  function _isResult(value, okValue) {
941
1017
  if (!isPlainObject(value)) return false;
942
1018
  return value.ok === okValue && (okValue ? "value" : "error") in value;
@@ -3696,4 +3772,4 @@ var SizedSet = class extends Set {
3696
3772
  }
3697
3773
  }
3698
3774
  };
3699
- export { CancelablePromise, PromiseTimeoutError, QueueError, SizedMap, SizedSet, attempt, attemptPromise, average, beacon, between, camelCase, cancelable, capitalize, ceil, chunk, clamp, clone, compact, compare, count, debounce, delay, diff, endsWith, equal, error, exists, filter, find, flatten, floor, flow, toResult as fromPromise, toResult, fromQuery, toPromise as fromResult, toPromise, getArray, getColor, getForegroundColor, getHexColor, getHexaColor, getHslColor, getHslaColor, getNormalizedHex, getNumber, getRandomBoolean, getRandomCharacters, getRandomColor, getRandomFloat, getRandomHex, getRandomInteger, getRandomItem, getRandomItems, getRgbColor, getRgbaColor, getString, getUuid, getValue, groupBy, hexToHsl, hexToHsla, hexToRgb, hexToRgba, hslToHex, hslToRgb, hslToRgba, ignoreKey, includes, indexOf, insert, isArrayOrPlainObject, isColor, isConstructor, isEmpty, isError, isFulfilled, isHexColor, isHslColor, isHslLike, isHslaColor, isInstanceOf, isKey, isNonNullable, isNullable, isNullableOrEmpty, isNullableOrWhitespace, isNumber, isNumerical, isObject, isOk, isPlainObject, isPrimitive, isRejected, isResult, isRgbColor, isRgbLike, isRgbaColor, isTypedArray, join, kebabCase, logger, lowerCase, max, median, memoize, merge, min, noop, ok, omit, parse, partition, pascalCase, pick, pipe, promises, push, queue, range, rgbToHex, rgbToHsl, rgbToHsla, round, select, setValue, shuffle, smush, snakeCase, sort, splice, startsWith, sum, template, throttle, timed, times, titleCase, toMap, toQuery, toRecord, toSet, toggle, trim, truncate, tryDecode, tryEncode, unique, unsmush, unwrap, update, upperCase, words };
3775
+ export { CancelablePromise, PromiseTimeoutError, QueueError, RetryError, SizedMap, SizedSet, attempt, attemptPromise, average, beacon, between, camelCase, cancelable, capitalize, ceil, chunk, clamp, clone, compact, compare, count, debounce, delay, diff, endsWith, equal, error, exists, filter, find, flatten, floor, flow, toResult as fromPromise, toResult, fromQuery, toPromise as fromResult, toPromise, getArray, getColor, getForegroundColor, getHexColor, getHexaColor, getHslColor, getHslaColor, getNormalizedHex, getNumber, getRandomBoolean, getRandomCharacters, getRandomColor, getRandomFloat, getRandomHex, getRandomInteger, getRandomItem, getRandomItems, getRgbColor, getRgbaColor, getString, getUuid, getValue, groupBy, hexToHsl, hexToHsla, hexToRgb, hexToRgba, hslToHex, hslToRgb, hslToRgba, ignoreKey, includes, indexOf, insert, isArrayOrPlainObject, isColor, isConstructor, isEmpty, isError, isFulfilled, isHexColor, isHslColor, isHslLike, isHslaColor, isInstanceOf, isKey, isNonNullable, isNullable, isNullableOrEmpty, isNullableOrWhitespace, isNumber, isNumerical, isObject, isOk, isPlainObject, isPrimitive, isRejected, isResult, isRgbColor, isRgbLike, isRgbaColor, isTypedArray, join, kebabCase, logger, lowerCase, max, median, memoize, merge, min, noop, ok, omit, parse, partition, pascalCase, pick, pipe, promises, push, queue, range, retry, rgbToHex, rgbToHsl, rgbToHsla, round, select, setValue, shuffle, smush, snakeCase, sort, splice, startsWith, sum, template, throttle, timed, times, titleCase, toMap, toQuery, toRecord, toSet, toggle, trim, truncate, tryDecode, tryEncode, unique, unsmush, unwrap, update, upperCase, words };
@@ -0,0 +1,79 @@
1
+ import { isPlainObject } from "../internal/is.js";
2
+ import { TIMER_WAIT, getTimer } from "../internal/function/timer.js";
3
+ var RetryError = class extends Error {
4
+ constructor(message, original) {
5
+ super(message);
6
+ this.original = original;
7
+ this.name = ERROR_NAME;
8
+ }
9
+ };
10
+ /**
11
+ * Retry a callback a specified number of times, with a delay between attempts
12
+ * @param callback Callback to retry
13
+ * @param options Retry options
14
+ * @returns Callback result
15
+ */
16
+ async function asyncRetry(callback, options) {
17
+ if (typeof callback !== "function") throw new TypeError(MESSAGE_EXPECTATION);
18
+ async function handle() {
19
+ try {
20
+ const result = await callback();
21
+ resolver(result);
22
+ } catch (error) {
23
+ if (attempts >= times || !when(error)) rejector(new RetryError(MESSAGE_FAILED, error));
24
+ else {
25
+ attempts += 1;
26
+ timer();
27
+ }
28
+ }
29
+ }
30
+ const { delay, times, when } = getRetryOptions(options);
31
+ const timer = getTimer(TIMER_WAIT, handle, delay);
32
+ let attempts = 0;
33
+ let rejector;
34
+ let resolver;
35
+ return new Promise((resolve, reject) => {
36
+ rejector = reject;
37
+ resolver = resolve;
38
+ handle();
39
+ });
40
+ }
41
+ function getRetryNumber(value) {
42
+ return typeof value === "number" && value > 0 ? value : 0;
43
+ }
44
+ function getRetryOptions(input) {
45
+ const options = isPlainObject(input) ? input : {};
46
+ return {
47
+ delay: getRetryNumber(options.delay),
48
+ times: getRetryNumber(options.times),
49
+ when: typeof options.when === "function" ? options.when : shouldRetry
50
+ };
51
+ }
52
+ /**
53
+ * Retry a callback a specified number of times
54
+ * @param callback Callback to retry
55
+ * @param options Retry options
56
+ * @returns Callback result
57
+ */
58
+ function retry(callback, options) {
59
+ if (typeof callback !== "function") throw new TypeError(MESSAGE_EXPECTATION);
60
+ const { times, when } = getRetryOptions(options);
61
+ let last;
62
+ for (let index = 0; index <= times; index += 1) try {
63
+ return callback();
64
+ } catch (error) {
65
+ if (index >= times || !when(error)) {
66
+ last = error;
67
+ break;
68
+ }
69
+ }
70
+ throw new RetryError(MESSAGE_FAILED, last);
71
+ }
72
+ retry.async = asyncRetry;
73
+ function shouldRetry() {
74
+ return true;
75
+ }
76
+ var ERROR_NAME = "RetryError";
77
+ var MESSAGE_EXPECTATION = "Retry expected a function";
78
+ var MESSAGE_FAILED = "Retry failed";
79
+ export { RetryError, retry };
package/dist/index.js CHANGED
@@ -39,6 +39,7 @@ import { getColor } from "./color/index.js";
39
39
  import { SizedMap } from "./sized/map.js";
40
40
  import { memoize } from "./function/memoize.js";
41
41
  import { debounce, throttle } from "./function/index.js";
42
+ import { RetryError, retry } from "./function/retry.js";
42
43
  import { isError, isOk, isResult } from "./internal/result.js";
43
44
  import { flow, pipe } from "./function/work.js";
44
45
  import { equal } from "./internal/value/equal.js";
@@ -70,4 +71,4 @@ import { QueueError, queue } from "./queue.js";
70
71
  import { getRandomBoolean, getRandomCharacters, getRandomColor, getRandomHex, getRandomItem, getRandomItems } from "./random.js";
71
72
  import { attempt } from "./result/index.js";
72
73
  import { SizedSet } from "./sized/set.js";
73
- export { CancelablePromise, PromiseTimeoutError, QueueError, SizedMap, SizedSet, attempt, attemptPromise, average, beacon, between, camelCase, cancelable, capitalize, ceil, chunk, clamp, clone, compact, compare, count, debounce, delay, diff, endsWith, equal, error, exists, filter, find, flatten, floor, flow, toResult as fromPromise, fromQuery, toPromise as fromResult, getArray, getColor, getForegroundColor, getHexColor, getHexaColor, getHslColor, getHslaColor, getNormalizedHex, getNumber, getRandomBoolean, getRandomCharacters, getRandomColor, getRandomFloat, getRandomHex, getRandomInteger, getRandomItem, getRandomItems, getRgbColor, getRgbaColor, getString, getUuid, getValue, groupBy, hexToHsl, hexToHsla, hexToRgb, hexToRgba, hslToHex, hslToRgb, hslToRgba, ignoreKey, includes, indexOf, insert, isArrayOrPlainObject, isColor, isConstructor, isEmpty, isError, isFulfilled, isHexColor, isHslColor, isHslLike, isHslaColor, isInstanceOf, isKey, isNonNullable, isNullable, isNullableOrEmpty, isNullableOrWhitespace, isNumber, isNumerical, isObject, isOk, isPlainObject, isPrimitive, isRejected, isResult, isRgbColor, isRgbLike, isRgbaColor, isTypedArray, join, kebabCase, logger, lowerCase, max, median, memoize, merge, min, noop, ok, omit, parse, partition, pascalCase, pick, pipe, promises, push, queue, range, rgbToHex, rgbToHsl, rgbToHsla, round, select, setValue, shuffle, smush, snakeCase, sort, splice, startsWith, sum, template, throttle, timed, times, titleCase, toMap, toPromise, toQuery, toRecord, toResult, toSet, toggle, trim, truncate, tryDecode, tryEncode, unique, unsmush, unwrap, update, upperCase, words };
74
+ export { CancelablePromise, PromiseTimeoutError, QueueError, RetryError, SizedMap, SizedSet, attempt, attemptPromise, average, beacon, between, camelCase, cancelable, capitalize, ceil, chunk, clamp, clone, compact, compare, count, debounce, delay, diff, endsWith, equal, error, exists, filter, find, flatten, floor, flow, toResult as fromPromise, fromQuery, toPromise as fromResult, getArray, getColor, getForegroundColor, getHexColor, getHexaColor, getHslColor, getHslaColor, getNormalizedHex, getNumber, getRandomBoolean, getRandomCharacters, getRandomColor, getRandomFloat, getRandomHex, getRandomInteger, getRandomItem, getRandomItems, getRgbColor, getRgbaColor, getString, getUuid, getValue, groupBy, hexToHsl, hexToHsla, hexToRgb, hexToRgba, hslToHex, hslToRgb, hslToRgba, ignoreKey, includes, indexOf, insert, isArrayOrPlainObject, isColor, isConstructor, isEmpty, isError, isFulfilled, isHexColor, isHslColor, isHslLike, isHslaColor, isInstanceOf, isKey, isNonNullable, isNullable, isNullableOrEmpty, isNullableOrWhitespace, isNumber, isNumerical, isObject, isOk, isPlainObject, isPrimitive, isRejected, isResult, isRgbColor, isRgbLike, isRgbaColor, isTypedArray, join, kebabCase, logger, lowerCase, max, median, memoize, merge, min, noop, ok, omit, parse, partition, pascalCase, pick, pipe, promises, push, queue, range, retry, rgbToHex, rgbToHsl, rgbToHsla, round, select, setValue, shuffle, smush, snakeCase, sort, splice, startsWith, sum, template, throttle, timed, times, titleCase, toMap, toPromise, toQuery, toRecord, toResult, toSet, toggle, trim, truncate, tryDecode, tryEncode, unique, unsmush, unwrap, update, upperCase, words };
package/package.json CHANGED
@@ -51,8 +51,12 @@
51
51
  "default": "./dist/color/index.js"
52
52
  },
53
53
  "./function": {
54
- "types": "./types/function/memoize.d.ts",
55
- "default": "./dist/function/memoize.js"
54
+ "types": "./types/function/index.d.ts",
55
+ "default": "./dist/function/index.js"
56
+ },
57
+ "./function/retry": {
58
+ "types": "./types/function/retry.d.ts",
59
+ "default": "./dist/function/retry.js"
56
60
  },
57
61
  "./function/work": {
58
62
  "types": "./types/function/work.d.ts",
@@ -176,5 +180,5 @@
176
180
  },
177
181
  "type": "module",
178
182
  "types": "./types/index.d.ts",
179
- "version": "0.152.0"
183
+ "version": "0.153.0"
180
184
  }
@@ -0,0 +1,162 @@
1
+ import {getTimer, TIMER_WAIT} from '../internal/function/timer';
2
+ import {isPlainObject} from '../internal/is';
3
+ import type {GenericAsyncCallback, GenericCallback} from '../models';
4
+
5
+ // #region Types
6
+
7
+ export class RetryError extends Error {
8
+ constructor(
9
+ message: string,
10
+ readonly original: unknown,
11
+ ) {
12
+ super(message);
13
+
14
+ this.name = ERROR_NAME;
15
+ }
16
+ }
17
+
18
+ export type RetryOptions = {
19
+ delay?: number;
20
+ times?: number;
21
+ when?: (error: unknown) => boolean;
22
+ };
23
+
24
+ // #endregion
25
+
26
+ // #region Functions
27
+
28
+ /**
29
+ * Retry a callback a specified number of times, with a delay between attempts
30
+ * @param callback Callback to retry
31
+ * @param options Retry options
32
+ * @returns Callback result
33
+ */
34
+ async function asyncRetry<Callback extends GenericAsyncCallback>(
35
+ callback: Callback,
36
+ options?: RetryOptions,
37
+ ): Promise<Awaited<ReturnType<Callback>>>;
38
+
39
+ /**
40
+ * Retry a callback a specified number of times, with a delay between attempts
41
+ * @param callback Callback to retry
42
+ * @param options Retry options
43
+ * @returns Callback result
44
+ */
45
+ async function asyncRetry<Callback extends GenericCallback>(
46
+ callback: Callback,
47
+ options?: RetryOptions,
48
+ ): Promise<ReturnType<Callback>>;
49
+
50
+ /**
51
+ * Retry a callback a specified number of times, with a delay between attempts
52
+ * @param callback Callback to retry
53
+ * @param options Retry options
54
+ * @returns Callback result
55
+ */
56
+ async function asyncRetry<Callback extends GenericCallback>(
57
+ callback: Callback,
58
+ options?: RetryOptions,
59
+ ): Promise<ReturnType<Callback>> {
60
+ if (typeof callback !== 'function') {
61
+ throw new TypeError(MESSAGE_EXPECTATION);
62
+ }
63
+
64
+ async function handle(): Promise<void> {
65
+ try {
66
+ const result = await callback();
67
+
68
+ resolver(result);
69
+ } catch (error) {
70
+ if (attempts >= times || !when(error)) {
71
+ rejector(new RetryError(MESSAGE_FAILED, error));
72
+ } else {
73
+ attempts += 1;
74
+
75
+ timer();
76
+ }
77
+ }
78
+ }
79
+
80
+ const {delay, times, when} = getRetryOptions(options);
81
+
82
+ const timer = getTimer(TIMER_WAIT, handle, delay);
83
+
84
+ let attempts = 0;
85
+
86
+ let rejector: (reason?: unknown) => void;
87
+ let resolver: (value: Awaited<ReturnType<Callback>>) => void;
88
+
89
+ return new Promise<Awaited<ReturnType<Callback>>>((resolve, reject) => {
90
+ rejector = reject;
91
+ resolver = resolve;
92
+
93
+ handle();
94
+ });
95
+ }
96
+
97
+ function getRetryNumber(value?: unknown): number {
98
+ return typeof value === 'number' && value > 0 ? value : 0;
99
+ }
100
+
101
+ function getRetryOptions(input?: RetryOptions): Required<RetryOptions> {
102
+ const options = isPlainObject(input) ? input : {};
103
+
104
+ return {
105
+ delay: getRetryNumber(options.delay),
106
+ times: getRetryNumber(options.times),
107
+ when: typeof options.when === 'function' ? options.when : shouldRetry,
108
+ };
109
+ }
110
+
111
+ /**
112
+ * Retry a callback a specified number of times
113
+ * @param callback Callback to retry
114
+ * @param options Retry options
115
+ * @returns Callback result
116
+ */
117
+ export function retry<Callback extends GenericCallback>(
118
+ callback: Callback,
119
+ options?: Omit<RetryOptions, 'delay'>,
120
+ ): ReturnType<Callback> {
121
+ if (typeof callback !== 'function') {
122
+ throw new TypeError(MESSAGE_EXPECTATION);
123
+ }
124
+
125
+ const {times, when} = getRetryOptions(options);
126
+
127
+ let last: unknown;
128
+
129
+ for (let index = 0; index <= times; index += 1) {
130
+ try {
131
+ const result = callback();
132
+
133
+ return result;
134
+ } catch (error) {
135
+ if (index >= times || !when(error)) {
136
+ last = error;
137
+
138
+ break;
139
+ }
140
+ }
141
+ }
142
+
143
+ throw new RetryError(MESSAGE_FAILED, last);
144
+ }
145
+
146
+ retry.async = asyncRetry;
147
+
148
+ function shouldRetry(): boolean {
149
+ return true;
150
+ }
151
+
152
+ // #endregion
153
+
154
+ // #region Variables
155
+
156
+ const ERROR_NAME = 'RetryError';
157
+
158
+ const MESSAGE_EXPECTATION = 'Retry expected a function';
159
+
160
+ const MESSAGE_FAILED = 'Retry failed';
161
+
162
+ // #endregion
package/src/index.ts CHANGED
@@ -5,6 +5,7 @@ export * from './array/to-record';
5
5
  export * from './array/unique';
6
6
 
7
7
  export * from './function/index';
8
+ export * from './function/retry';
8
9
  export * from './function/work';
9
10
 
10
11
  export * from './internal/function/misc';
@@ -0,0 +1,35 @@
1
+ import type { GenericAsyncCallback, GenericCallback } from '../models';
2
+ export declare class RetryError extends Error {
3
+ readonly original: unknown;
4
+ constructor(message: string, original: unknown);
5
+ }
6
+ export type RetryOptions = {
7
+ delay?: number;
8
+ times?: number;
9
+ when?: (error: unknown) => boolean;
10
+ };
11
+ /**
12
+ * Retry a callback a specified number of times, with a delay between attempts
13
+ * @param callback Callback to retry
14
+ * @param options Retry options
15
+ * @returns Callback result
16
+ */
17
+ declare function asyncRetry<Callback extends GenericAsyncCallback>(callback: Callback, options?: RetryOptions): Promise<Awaited<ReturnType<Callback>>>;
18
+ /**
19
+ * Retry a callback a specified number of times, with a delay between attempts
20
+ * @param callback Callback to retry
21
+ * @param options Retry options
22
+ * @returns Callback result
23
+ */
24
+ declare function asyncRetry<Callback extends GenericCallback>(callback: Callback, options?: RetryOptions): Promise<ReturnType<Callback>>;
25
+ /**
26
+ * Retry a callback a specified number of times
27
+ * @param callback Callback to retry
28
+ * @param options Retry options
29
+ * @returns Callback result
30
+ */
31
+ export declare function retry<Callback extends GenericCallback>(callback: Callback, options?: Omit<RetryOptions, 'delay'>): ReturnType<Callback>;
32
+ export declare namespace retry {
33
+ var async: typeof asyncRetry;
34
+ }
35
+ export {};
package/types/index.d.ts CHANGED
@@ -4,6 +4,7 @@ export * from './array/to-map';
4
4
  export * from './array/to-record';
5
5
  export * from './array/unique';
6
6
  export * from './function/index';
7
+ export * from './function/retry';
7
8
  export * from './function/work';
8
9
  export * from './internal/function/misc';
9
10
  export * from './internal/string';