@oscarpalmer/atoms 0.152.1 → 0.154.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
@@ -54,6 +54,14 @@
54
54
  "types": "./types/function/index.d.ts",
55
55
  "default": "./dist/function/index.js"
56
56
  },
57
+ "./function/assert": {
58
+ "types": "./types/function/assert.d.ts",
59
+ "default": "./dist/function/assert.js"
60
+ },
61
+ "./function/retry": {
62
+ "types": "./types/function/retry.d.ts",
63
+ "default": "./dist/function/retry.js"
64
+ },
57
65
  "./function/work": {
58
66
  "types": "./types/function/work.d.ts",
59
67
  "default": "./dist/function/work.js"
@@ -176,5 +184,5 @@
176
184
  },
177
185
  "type": "module",
178
186
  "types": "./types/index.d.ts",
179
- "version": "0.152.1"
180
- }
187
+ "version": "0.154.0"
188
+ }
@@ -1,7 +1,19 @@
1
1
  import type {Constructor} from '../models';
2
2
 
3
+ // #region Types
4
+
3
5
  export type Asserter<Value> = (value: unknown) => asserts value is Value;
4
6
 
7
+ // #endregion
8
+
9
+ // #region Functions
10
+
11
+ /**
12
+ * Asserts that a condition is true, throwing an error if it is not
13
+ * @param condition Condition to assert
14
+ * @param message Error message
15
+ * @param error Error constructor
16
+ */
5
17
  export function assert<Condition extends () => boolean>(
6
18
  condition: Condition,
7
19
  message: string,
@@ -12,32 +24,78 @@ export function assert<Condition extends () => boolean>(
12
24
  }
13
25
  }
14
26
 
15
- assert.condition = <Value>(
27
+ assert.condition = assertCondition;
28
+ assert.defined = assertDefined;
29
+ assert.instanceOf = assertInstanceOf;
30
+ assert.is = assertIs;
31
+
32
+ /**
33
+ * Creates an asserter that asserts a condition is true, throwing an error if it is not
34
+ * @param condition Condition to assert
35
+ * @param message Error message
36
+ * @param error Error constructor
37
+ * @returns Asserter
38
+ */
39
+ function assertCondition<Value>(
16
40
  condition: (value: unknown) => boolean,
17
41
  message: string,
18
42
  error?: ErrorConstructor,
19
- ): Asserter<Value> => {
43
+ ): Asserter<Value> {
20
44
  return value => {
21
45
  assert(() => condition(value), message, error);
22
46
  };
23
- };
47
+ }
48
+
49
+ /**
50
+ * Asserts that a value is defined _(not `null` or `undefined`)_, throwing an error if it is not
51
+ * @param value Value to assert
52
+ * @param message Error message
53
+ */
54
+ function assertDefined<Value>(
55
+ value: unknown,
56
+ message?: string,
57
+ ): asserts value is Exclude<Value, null | undefined> {
58
+ assert(() => value != null, message ?? MESSAGE_DEFINED);
59
+ }
24
60
 
25
- assert.instanceOf = <Value>(
61
+ /**
62
+ * Creates an asserter that asserts a value is an instance of a constructor, throwing an error if it is not
63
+ * @param constructor Constructor to check against
64
+ * @param message Error message
65
+ * @param error Error constructor
66
+ * @returns Asserter
67
+ */
68
+ function assertInstanceOf<Value>(
26
69
  constructor: Constructor<Value>,
27
70
  message: string,
28
71
  error?: ErrorConstructor,
29
- ): Asserter<Value> => {
72
+ ): Asserter<Value> {
30
73
  return value => {
31
74
  assert(() => value instanceof constructor, message, error);
32
75
  };
33
- };
76
+ }
34
77
 
35
- assert.is = <Value>(
78
+ /**
79
+ * Creates an asserter that asserts a value is of a specific type, throwing an error if it is not
80
+ * @param condition Type guard function to check the value
81
+ * @param message Error message
82
+ * @param error Error constructor
83
+ * @returns Asserter
84
+ */
85
+ function assertIs<Value>(
36
86
  condition: (value: unknown) => value is Value,
37
87
  message: string,
38
88
  error?: ErrorConstructor,
39
- ): Asserter<Value> => {
89
+ ): Asserter<Value> {
40
90
  return value => {
41
91
  assert(() => condition(value), message, error);
42
92
  };
43
- };
93
+ }
94
+
95
+ // #endregion
96
+
97
+ // #region Variables
98
+
99
+ const MESSAGE_DEFINED = 'Expected value to be defined';
100
+
101
+ // #endregion
@@ -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';
package/src/math.ts CHANGED
@@ -154,10 +154,6 @@ export function median(array: unknown[], key?: unknown): number {
154
154
  return Number.NaN;
155
155
  }
156
156
 
157
- if (length === 1) {
158
- return isNumber(array[0]) ? array[0] : Number.NaN;
159
- }
160
-
161
157
  let values: unknown[] = array;
162
158
 
163
159
  const callback = getAggregateCallback(key);
@@ -170,6 +166,10 @@ export function median(array: unknown[], key?: unknown): number {
170
166
 
171
167
  length = numbers.length;
172
168
 
169
+ if (length === 1) {
170
+ return numbers[0];
171
+ }
172
+
173
173
  if (length % 2 === 0) {
174
174
  const first = length / 2 - 1;
175
175
  const second = length / 2;
@@ -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';