dce-reactkit 3.7.3 → 3.7.5
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/dist/cjs/index.js +159 -3
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/components/Modal.d.ts +1 -0
- package/dist/cjs/types/components/Shimmer.d.ts +13 -0
- package/dist/cjs/types/helpers/asyncArrayFunctions/everyAsync.d.ts +13 -0
- package/dist/cjs/types/helpers/asyncArrayFunctions/everyAsync.test.d.ts +1 -0
- package/dist/cjs/types/helpers/asyncArrayFunctions/filterAsync.d.ts +13 -0
- package/dist/cjs/types/helpers/asyncArrayFunctions/filterAsync.test.d.ts +1 -0
- package/dist/cjs/types/helpers/asyncArrayFunctions/forEachAsync.d.ts +10 -0
- package/dist/cjs/types/helpers/asyncArrayFunctions/forEachAsync.test.d.ts +1 -0
- package/dist/cjs/types/helpers/asyncArrayFunctions/mapAsync.d.ts +11 -0
- package/dist/cjs/types/helpers/asyncArrayFunctions/mapAsync.test.d.ts +1 -0
- package/dist/cjs/types/helpers/asyncArrayFunctions/someAsync.d.ts +13 -0
- package/dist/cjs/types/helpers/asyncArrayFunctions/someAsync.test.d.ts +1 -0
- package/dist/cjs/types/index.d.ts +6 -1
- package/dist/esm/index.js +155 -4
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/components/Modal.d.ts +1 -0
- package/dist/esm/types/components/Shimmer.d.ts +13 -0
- package/dist/esm/types/helpers/asyncArrayFunctions/everyAsync.d.ts +13 -0
- package/dist/esm/types/helpers/asyncArrayFunctions/everyAsync.test.d.ts +1 -0
- package/dist/esm/types/helpers/asyncArrayFunctions/filterAsync.d.ts +13 -0
- package/dist/esm/types/helpers/asyncArrayFunctions/filterAsync.test.d.ts +1 -0
- package/dist/esm/types/helpers/asyncArrayFunctions/forEachAsync.d.ts +10 -0
- package/dist/esm/types/helpers/asyncArrayFunctions/forEachAsync.test.d.ts +1 -0
- package/dist/esm/types/helpers/asyncArrayFunctions/mapAsync.d.ts +11 -0
- package/dist/esm/types/helpers/asyncArrayFunctions/mapAsync.test.d.ts +1 -0
- package/dist/esm/types/helpers/asyncArrayFunctions/someAsync.d.ts +13 -0
- package/dist/esm/types/helpers/asyncArrayFunctions/someAsync.test.d.ts +1 -0
- package/dist/esm/types/index.d.ts +6 -1
- package/dist/index.d.ts +62 -1
- package/package.json +1 -1
- package/src/components/CopiableBox.tsx +1 -1
- package/src/components/Modal.tsx +4 -1
- package/src/components/Shimmer.tsx +153 -0
- package/src/helpers/asyncArrayFunctions/everyAsync.test.ts +114 -0
- package/src/helpers/asyncArrayFunctions/everyAsync.ts +51 -0
- package/src/helpers/asyncArrayFunctions/filterAsync.test.ts +126 -0
- package/src/helpers/asyncArrayFunctions/filterAsync.ts +50 -0
- package/src/helpers/asyncArrayFunctions/forEachAsync.test.ts +136 -0
- package/src/helpers/asyncArrayFunctions/forEachAsync.ts +40 -0
- package/src/helpers/asyncArrayFunctions/mapAsync.test.ts +125 -0
- package/src/helpers/asyncArrayFunctions/mapAsync.ts +46 -0
- package/src/helpers/asyncArrayFunctions/someAsync.test.ts +92 -0
- package/src/helpers/asyncArrayFunctions/someAsync.ts +49 -0
- package/src/index.ts +10 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import filterAsync from './filterAsync';
|
|
2
|
+
|
|
3
|
+
describe('filterAsync', () => {
|
|
4
|
+
it('should return an empty array when given an empty array', async () => {
|
|
5
|
+
const result = await filterAsync(
|
|
6
|
+
[],
|
|
7
|
+
async () => {
|
|
8
|
+
return true;
|
|
9
|
+
},
|
|
10
|
+
);
|
|
11
|
+
expect(result).toEqual([]);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('should return the original array when all items pass the filter', async () => {
|
|
15
|
+
const originalArray = [1, 2, 3];
|
|
16
|
+
const result = await filterAsync(
|
|
17
|
+
originalArray,
|
|
18
|
+
async () => {
|
|
19
|
+
return true;
|
|
20
|
+
},
|
|
21
|
+
);
|
|
22
|
+
expect(result).toEqual(originalArray);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should return an empty array when no items pass the filter', async () => {
|
|
26
|
+
const originalArray = [1, 2, 3];
|
|
27
|
+
const result = await filterAsync(
|
|
28
|
+
originalArray,
|
|
29
|
+
async () => {
|
|
30
|
+
return false;
|
|
31
|
+
},
|
|
32
|
+
);
|
|
33
|
+
expect(result).toEqual([]);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should return only the items that pass the filter', async () => {
|
|
37
|
+
const originalArray = [1, 2, 3];
|
|
38
|
+
const result = await filterAsync(
|
|
39
|
+
originalArray,
|
|
40
|
+
async (item) => {
|
|
41
|
+
return item > 1;
|
|
42
|
+
},
|
|
43
|
+
);
|
|
44
|
+
expect(result).toEqual([2, 3]);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should pass the correct index to the operator function', async () => {
|
|
48
|
+
const originalArray = [1, 2, 3];
|
|
49
|
+
const result = await filterAsync(
|
|
50
|
+
originalArray,
|
|
51
|
+
async (_, index) => {
|
|
52
|
+
return index === 1;
|
|
53
|
+
},
|
|
54
|
+
);
|
|
55
|
+
expect(result).toEqual([2]);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should allow breaking out of the loop early', async () => {
|
|
59
|
+
const originalArray = [1, 2, 3];
|
|
60
|
+
const result = await filterAsync(
|
|
61
|
+
originalArray,
|
|
62
|
+
async (_, index, { breakNow }) => {
|
|
63
|
+
if (index === 1) {
|
|
64
|
+
breakNow();
|
|
65
|
+
}
|
|
66
|
+
return true;
|
|
67
|
+
},
|
|
68
|
+
);
|
|
69
|
+
expect(result).toEqual([1]);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should pass the original array to the operator function', async () => {
|
|
73
|
+
const originalArray = [1, 2, 3];
|
|
74
|
+
const result = await filterAsync(
|
|
75
|
+
originalArray,
|
|
76
|
+
async (_, index, { array }) => {
|
|
77
|
+
return array.length === 3;
|
|
78
|
+
},
|
|
79
|
+
);
|
|
80
|
+
expect(result).toEqual(originalArray);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should handle an operator function that returns a non-boolean value', async () => {
|
|
84
|
+
const originalArray = [1, 2, 3];
|
|
85
|
+
const result = await filterAsync(
|
|
86
|
+
originalArray,
|
|
87
|
+
async () => {
|
|
88
|
+
return 'hello';
|
|
89
|
+
},
|
|
90
|
+
);
|
|
91
|
+
expect(result).toEqual(originalArray);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('should handle an operator function that throws an error', async () => {
|
|
95
|
+
const originalArray = [1, 2, 3];
|
|
96
|
+
let error: any = null;
|
|
97
|
+
let result: number[] | null = null;
|
|
98
|
+
try {
|
|
99
|
+
result = await filterAsync(
|
|
100
|
+
originalArray,
|
|
101
|
+
async () => {
|
|
102
|
+
throw new Error('Something went wrong');
|
|
103
|
+
},
|
|
104
|
+
);
|
|
105
|
+
} catch (err) {
|
|
106
|
+
error = err;
|
|
107
|
+
}
|
|
108
|
+
expect(result).toEqual(null);
|
|
109
|
+
expect(error).not.toBe(null);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should handle an array of objects', async () => {
|
|
113
|
+
const originalArray = [
|
|
114
|
+
{ name: 'Alice', age: 30 },
|
|
115
|
+
{ name: 'Bob', age: 25 },
|
|
116
|
+
{ name: 'Charlie', age: 35 },
|
|
117
|
+
];
|
|
118
|
+
const result = await filterAsync(
|
|
119
|
+
originalArray,
|
|
120
|
+
async (item) => {
|
|
121
|
+
return (item.age > 30);
|
|
122
|
+
},
|
|
123
|
+
);
|
|
124
|
+
expect(result).toEqual([{ name: 'Charlie', age: 35 }]);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run the operator function on each item in the array, returning a new array
|
|
3
|
+
* that only contains the items that pass the filter
|
|
4
|
+
* @author Gabe Abrams
|
|
5
|
+
* @param operatorFunction the operator function to apply. If it returns true
|
|
6
|
+
* for an item, the item will be included in the returned array
|
|
7
|
+
* @returns the filtered array
|
|
8
|
+
*/
|
|
9
|
+
const filterAsync = async <T>(
|
|
10
|
+
array: T[],
|
|
11
|
+
operatorFunction: (
|
|
12
|
+
item: T,
|
|
13
|
+
index: number,
|
|
14
|
+
opts: {
|
|
15
|
+
breakNow: () => void,
|
|
16
|
+
array: Array<T>,
|
|
17
|
+
},
|
|
18
|
+
) => Promise<any>,
|
|
19
|
+
): Promise<T[]> => {
|
|
20
|
+
// Create break logic
|
|
21
|
+
let done = false;
|
|
22
|
+
/**
|
|
23
|
+
* Break the loop (filtering stops here)
|
|
24
|
+
* @author Gabe Abrams
|
|
25
|
+
*/
|
|
26
|
+
const breakNow = () => {
|
|
27
|
+
done = true;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Loop through each item, filtering
|
|
31
|
+
const output: T[] = [];
|
|
32
|
+
for (let i = 0; i < array.length && !done; i++) {
|
|
33
|
+
const included = await operatorFunction(
|
|
34
|
+
array[i],
|
|
35
|
+
i,
|
|
36
|
+
{
|
|
37
|
+
breakNow,
|
|
38
|
+
array,
|
|
39
|
+
},
|
|
40
|
+
);
|
|
41
|
+
if (included && !done) {
|
|
42
|
+
output.push(array[i]);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Return results
|
|
47
|
+
return output;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export default filterAsync;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import forEachAsync from './forEachAsync';
|
|
2
|
+
|
|
3
|
+
describe('forEachAsync', () => {
|
|
4
|
+
it('should call the operator function for each item in the array', async () => {
|
|
5
|
+
const array = [1, 2, 3];
|
|
6
|
+
const operatorFunction = jest.fn();
|
|
7
|
+
|
|
8
|
+
await forEachAsync(array, operatorFunction);
|
|
9
|
+
|
|
10
|
+
expect(operatorFunction).toHaveBeenCalledTimes(3);
|
|
11
|
+
expect(operatorFunction).toHaveBeenCalledWith(1, 0, expect.any(Object));
|
|
12
|
+
expect(operatorFunction).toHaveBeenCalledWith(2, 1, expect.any(Object));
|
|
13
|
+
expect(operatorFunction).toHaveBeenCalledWith(3, 2, expect.any(Object));
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should pass the correct arguments to the operator function', async () => {
|
|
17
|
+
const array = ['a', 'b', 'c'];
|
|
18
|
+
const operatorFunction = jest.fn();
|
|
19
|
+
|
|
20
|
+
await forEachAsync(array, operatorFunction);
|
|
21
|
+
|
|
22
|
+
expect(operatorFunction).toHaveBeenCalledTimes(3);
|
|
23
|
+
expect(operatorFunction).toHaveBeenCalledWith('a', 0, expect.any(Object));
|
|
24
|
+
expect(operatorFunction).toHaveBeenCalledWith('b', 1, expect.any(Object));
|
|
25
|
+
expect(operatorFunction).toHaveBeenCalledWith('c', 2, expect.any(Object));
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should allow the operator function to break out of the loop', async () => {
|
|
29
|
+
const array = [1, 2, 3];
|
|
30
|
+
const operatorFunction = jest.fn((item, index, { breakNow }) => {
|
|
31
|
+
if (item === 2) {
|
|
32
|
+
breakNow();
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
await forEachAsync(array, operatorFunction);
|
|
37
|
+
|
|
38
|
+
expect(operatorFunction).toHaveBeenCalledTimes(2);
|
|
39
|
+
expect(operatorFunction).toHaveBeenCalledWith(1, 0, expect.any(Object));
|
|
40
|
+
expect(operatorFunction).toHaveBeenCalledWith(2, 1, expect.any(Object));
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should not call the operator function if the array is empty', async () => {
|
|
44
|
+
const array: string[] = [];
|
|
45
|
+
const operatorFunction = jest.fn();
|
|
46
|
+
|
|
47
|
+
await forEachAsync(array, operatorFunction);
|
|
48
|
+
|
|
49
|
+
expect(operatorFunction).not.toHaveBeenCalled();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should return undefined', async () => {
|
|
53
|
+
const array = [1, 2, 3];
|
|
54
|
+
const operatorFunction = jest.fn();
|
|
55
|
+
|
|
56
|
+
const result = await forEachAsync(array, operatorFunction);
|
|
57
|
+
|
|
58
|
+
expect(result).toBeUndefined();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should work with an array of objects', async () => {
|
|
62
|
+
const array = [
|
|
63
|
+
{ name: 'Alice', age: 30 },
|
|
64
|
+
{ name: 'Bob', age: 25 },
|
|
65
|
+
{ name: 'Charlie', age: 40 },
|
|
66
|
+
];
|
|
67
|
+
const operatorFunction = jest.fn();
|
|
68
|
+
|
|
69
|
+
await forEachAsync(array, operatorFunction);
|
|
70
|
+
|
|
71
|
+
expect(operatorFunction).toHaveBeenCalledTimes(3);
|
|
72
|
+
expect(operatorFunction).toHaveBeenCalledWith(
|
|
73
|
+
{ name: 'Alice', age: 30 },
|
|
74
|
+
0,
|
|
75
|
+
expect.any(Object),
|
|
76
|
+
);
|
|
77
|
+
expect(operatorFunction).toHaveBeenCalledWith(
|
|
78
|
+
{ name: 'Bob', age: 25 },
|
|
79
|
+
1,
|
|
80
|
+
expect.any(Object),
|
|
81
|
+
);
|
|
82
|
+
expect(operatorFunction).toHaveBeenCalledWith(
|
|
83
|
+
{ name: 'Charlie', age: 40 },
|
|
84
|
+
2,
|
|
85
|
+
expect.any(Object),
|
|
86
|
+
);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should work with an array of mixed types', async () => {
|
|
90
|
+
const array = [1, 'two', { three: 3 }];
|
|
91
|
+
const operatorFunction = jest.fn();
|
|
92
|
+
|
|
93
|
+
await forEachAsync(array, operatorFunction);
|
|
94
|
+
|
|
95
|
+
expect(operatorFunction).toHaveBeenCalledTimes(3);
|
|
96
|
+
expect(operatorFunction).toHaveBeenCalledWith(1, 0, expect.any(Object));
|
|
97
|
+
expect(operatorFunction).toHaveBeenCalledWith('two', 1, expect.any(Object));
|
|
98
|
+
expect(operatorFunction).toHaveBeenCalledWith(
|
|
99
|
+
{ three: 3 },
|
|
100
|
+
2,
|
|
101
|
+
expect.any(Object),
|
|
102
|
+
);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should work with an array of length 1', async () => {
|
|
106
|
+
const array = ['a'];
|
|
107
|
+
const operatorFunction = jest.fn();
|
|
108
|
+
|
|
109
|
+
await forEachAsync(array, operatorFunction);
|
|
110
|
+
|
|
111
|
+
expect(operatorFunction).toHaveBeenCalledTimes(1);
|
|
112
|
+
expect(operatorFunction).toHaveBeenCalledWith('a', 0, expect.any(Object));
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('should work with an array of length 100', async () => {
|
|
116
|
+
const array = Array.from({ length: 100 }, (_, i) => i);
|
|
117
|
+
const operatorFunction = jest.fn();
|
|
118
|
+
|
|
119
|
+
await forEachAsync(array, operatorFunction);
|
|
120
|
+
|
|
121
|
+
expect(operatorFunction).toHaveBeenCalledTimes(100);
|
|
122
|
+
expect(operatorFunction).toHaveBeenCalledWith(0, 0, expect.any(Object));
|
|
123
|
+
expect(operatorFunction).toHaveBeenCalledWith(99, 99, expect.any(Object));
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('should work with an array of length 1000', async () => {
|
|
127
|
+
const array = Array.from({ length: 1000 }, (_, i) => i);
|
|
128
|
+
const operatorFunction = jest.fn();
|
|
129
|
+
|
|
130
|
+
await forEachAsync(array, operatorFunction);
|
|
131
|
+
|
|
132
|
+
expect(operatorFunction).toHaveBeenCalledTimes(1000);
|
|
133
|
+
expect(operatorFunction).toHaveBeenCalledWith(0, 0, expect.any(Object));
|
|
134
|
+
expect(operatorFunction).toHaveBeenCalledWith(999, 999, expect.any(Object));
|
|
135
|
+
});
|
|
136
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run the operator function on each item in the array
|
|
3
|
+
* @author Gabe Abrams
|
|
4
|
+
* @param operatorFunction the operator function to apply
|
|
5
|
+
*/
|
|
6
|
+
const forEachAsync = async <T>(
|
|
7
|
+
array: T[],
|
|
8
|
+
operatorFunction: (
|
|
9
|
+
item: T,
|
|
10
|
+
index: number,
|
|
11
|
+
opts: {
|
|
12
|
+
breakNow: () => void,
|
|
13
|
+
array: Array<T>,
|
|
14
|
+
},
|
|
15
|
+
) => void,
|
|
16
|
+
) => {
|
|
17
|
+
// Create break logic
|
|
18
|
+
let done = false;
|
|
19
|
+
/**
|
|
20
|
+
* Break the loop
|
|
21
|
+
* @author Gabe Abrams
|
|
22
|
+
*/
|
|
23
|
+
const breakNow = () => {
|
|
24
|
+
done = true;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// Loop through each item
|
|
28
|
+
for (let i = 0; i < array.length && !done; i++) {
|
|
29
|
+
await operatorFunction(
|
|
30
|
+
array[i],
|
|
31
|
+
i,
|
|
32
|
+
{
|
|
33
|
+
breakNow,
|
|
34
|
+
array,
|
|
35
|
+
},
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export default forEachAsync;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import waitMs from '../waitMs';
|
|
2
|
+
import mapAsync from './mapAsync';
|
|
3
|
+
|
|
4
|
+
describe('mapAsync', () => {
|
|
5
|
+
it('should return an empty array when given an empty array', async () => {
|
|
6
|
+
const result = await mapAsync([], async () => {
|
|
7
|
+
// Operator function logic goes here
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
expect(result).toEqual([]);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('should apply the operator function to each item in the array', async () => {
|
|
14
|
+
const array = [1, 2, 3];
|
|
15
|
+
const operatorFunction = jest.fn();
|
|
16
|
+
|
|
17
|
+
await mapAsync(array, operatorFunction);
|
|
18
|
+
|
|
19
|
+
expect(operatorFunction).toHaveBeenCalledTimes(3);
|
|
20
|
+
expect(operatorFunction).toHaveBeenCalledWith(1, 0, expect.any(Object));
|
|
21
|
+
expect(operatorFunction).toHaveBeenCalledWith(2, 1, expect.any(Object));
|
|
22
|
+
expect(operatorFunction).toHaveBeenCalledWith(3, 2, expect.any(Object));
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should collect and return the results of the operator function', async () => {
|
|
26
|
+
const array = [1, 2, 3];
|
|
27
|
+
const operatorFunction = async (item: number) => {
|
|
28
|
+
return item * 2;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const result = await mapAsync(array, operatorFunction);
|
|
32
|
+
|
|
33
|
+
expect(result).toEqual([2, 4, 6]);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should pass the correct index to the operator function', async () => {
|
|
37
|
+
const array = [1, 2, 3];
|
|
38
|
+
const operatorFunction = jest.fn();
|
|
39
|
+
|
|
40
|
+
await mapAsync(array, operatorFunction);
|
|
41
|
+
|
|
42
|
+
expect(operatorFunction).toHaveBeenCalledWith(expect.anything(), 0, expect.any(Object));
|
|
43
|
+
expect(operatorFunction).toHaveBeenCalledWith(expect.anything(), 1, expect.any(Object));
|
|
44
|
+
expect(operatorFunction).toHaveBeenCalledWith(expect.anything(), 2, expect.any(Object));
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should pass the correct options object to the operator function', async () => {
|
|
48
|
+
const array = [1, 2, 3];
|
|
49
|
+
const operatorFunction = jest.fn();
|
|
50
|
+
|
|
51
|
+
await mapAsync(array, operatorFunction);
|
|
52
|
+
|
|
53
|
+
expect(operatorFunction).toHaveBeenCalledWith(expect.anything(), expect.anything(), {
|
|
54
|
+
breakNow: expect.any(Function),
|
|
55
|
+
array: expect.any(Array),
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should allow the operator function to break the loop', async () => {
|
|
60
|
+
const array = [1, 2, 3];
|
|
61
|
+
|
|
62
|
+
const result = await mapAsync(
|
|
63
|
+
array,
|
|
64
|
+
async (
|
|
65
|
+
item,
|
|
66
|
+
index,
|
|
67
|
+
{ breakNow },
|
|
68
|
+
) => {
|
|
69
|
+
if (item === 2) {
|
|
70
|
+
breakNow();
|
|
71
|
+
}
|
|
72
|
+
return item;
|
|
73
|
+
},
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
expect(result).toEqual([1]);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should handle asynchronous operator function', async () => {
|
|
80
|
+
const array = [1, 2, 3];
|
|
81
|
+
const result = await mapAsync(
|
|
82
|
+
array,
|
|
83
|
+
async (item) => {
|
|
84
|
+
await waitMs(1000);
|
|
85
|
+
return item * 2;
|
|
86
|
+
},
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
expect(result).toEqual([2, 4, 6]);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should handle errors thrown by the operator function', async () => {
|
|
93
|
+
const array = [1, 2, 3];
|
|
94
|
+
|
|
95
|
+
await expect(
|
|
96
|
+
mapAsync(
|
|
97
|
+
array,
|
|
98
|
+
async (item) => {
|
|
99
|
+
if (item === 2) {
|
|
100
|
+
throw new Error('Error processing item');
|
|
101
|
+
}
|
|
102
|
+
return item * 2;
|
|
103
|
+
},
|
|
104
|
+
),
|
|
105
|
+
).rejects.toThrow('Error processing item');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('should handle empty array with breakNow called', async () => {
|
|
109
|
+
const array: number[] = [];
|
|
110
|
+
|
|
111
|
+
const result = await mapAsync(
|
|
112
|
+
array,
|
|
113
|
+
async (
|
|
114
|
+
item,
|
|
115
|
+
index,
|
|
116
|
+
{ breakNow },
|
|
117
|
+
) => {
|
|
118
|
+
breakNow();
|
|
119
|
+
return item;
|
|
120
|
+
},
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
expect(result).toEqual([]);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run the operator function on each item in the array, collecting all results
|
|
3
|
+
* @author Gabe Abrams
|
|
4
|
+
* @param operatorFunction the operator function to apply
|
|
5
|
+
* @returns the array of results
|
|
6
|
+
*/
|
|
7
|
+
const mapAsync = async <T, U>(
|
|
8
|
+
array: T[],
|
|
9
|
+
operatorFunction: (
|
|
10
|
+
item: T,
|
|
11
|
+
index: number,
|
|
12
|
+
opts: {
|
|
13
|
+
breakNow: () => void,
|
|
14
|
+
array: Array<T>,
|
|
15
|
+
},
|
|
16
|
+
) => Promise<U>,
|
|
17
|
+
): Promise<U[]> => {
|
|
18
|
+
// Create break logic
|
|
19
|
+
let done = false;
|
|
20
|
+
/**
|
|
21
|
+
* Break the loop
|
|
22
|
+
* @author Gabe Abrams
|
|
23
|
+
*/
|
|
24
|
+
const breakNow = () => {
|
|
25
|
+
done = true;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Loop through each item, collecting results
|
|
29
|
+
const results: U[] = [];
|
|
30
|
+
for (let i = 0; i < array.length && !done; i++) {
|
|
31
|
+
const result = await operatorFunction(
|
|
32
|
+
array[i],
|
|
33
|
+
i,
|
|
34
|
+
{
|
|
35
|
+
breakNow,
|
|
36
|
+
array,
|
|
37
|
+
},
|
|
38
|
+
);
|
|
39
|
+
results.push(result);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Return results
|
|
43
|
+
return results;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export default mapAsync;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import waitMs from '../waitMs';
|
|
2
|
+
import someAsync from './someAsync';
|
|
3
|
+
|
|
4
|
+
describe('someAsync', () => {
|
|
5
|
+
it('should return false if the array is empty', async () => {
|
|
6
|
+
const result = await someAsync([], () => {
|
|
7
|
+
return Promise.resolve(true);
|
|
8
|
+
});
|
|
9
|
+
expect(result).toBe(false);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('should return false if the operator function returns false for all items', async () => {
|
|
13
|
+
const array = [1, 2, 3, 4, 5];
|
|
14
|
+
const result = await someAsync(array, () => {
|
|
15
|
+
return Promise.resolve(false);
|
|
16
|
+
});
|
|
17
|
+
expect(result).toBe(false);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('should return true if the operator function returns true for any item', async () => {
|
|
21
|
+
const array = [1, 2, 3, 4, 5];
|
|
22
|
+
const result = await someAsync(array, (item) => {
|
|
23
|
+
return Promise.resolve(item === 3);
|
|
24
|
+
});
|
|
25
|
+
expect(result).toBe(true);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should pass the correct index to the operator function', async () => {
|
|
29
|
+
const array = [1, 2, 3, 4, 5];
|
|
30
|
+
const result = await someAsync(array, (item, index) => {
|
|
31
|
+
expect(index).toBeGreaterThanOrEqual(0);
|
|
32
|
+
expect(index).toBeLessThan(array.length);
|
|
33
|
+
return Promise.resolve(false);
|
|
34
|
+
});
|
|
35
|
+
expect(result).toBe(false);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should pass the correct array to the operator function', async () => {
|
|
39
|
+
const array = [1, 2, 3, 4, 5];
|
|
40
|
+
const result = await someAsync(array, (item, index, { array: arr }) => {
|
|
41
|
+
expect(arr).toBe(array);
|
|
42
|
+
return Promise.resolve(false);
|
|
43
|
+
});
|
|
44
|
+
expect(result).toBe(false);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should stop iterating and return true if the operator function returns true for an item and breakNow is called', async () => {
|
|
48
|
+
const array = [1, 2, 3, 4, 5];
|
|
49
|
+
const result = await someAsync(array, (item, index, { breakNow }) => {
|
|
50
|
+
if (item === 3) {
|
|
51
|
+
breakNow();
|
|
52
|
+
return Promise.resolve(true);
|
|
53
|
+
}
|
|
54
|
+
return Promise.resolve(false);
|
|
55
|
+
});
|
|
56
|
+
expect(result).toBe(true);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should handle asynchronous operator function', async () => {
|
|
60
|
+
const array = [1, 2, 3, 4, 5];
|
|
61
|
+
const result = await someAsync(array, async (item) => {
|
|
62
|
+
await waitMs(100);
|
|
63
|
+
return Promise.resolve(item === 3);
|
|
64
|
+
});
|
|
65
|
+
expect(result).toBe(true);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should handle rejected promises from the operator function', async () => {
|
|
69
|
+
const array = [1, 2, 3, 4, 5];
|
|
70
|
+
const result = await someAsync(array, () => {
|
|
71
|
+
return Promise.reject(new Error('Test error'));
|
|
72
|
+
});
|
|
73
|
+
expect(result).toBe(false);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should handle thrown errors from the operator function', async () => {
|
|
77
|
+
const array = [1, 2, 3, 4, 5];
|
|
78
|
+
const result = await someAsync(array, () => {
|
|
79
|
+
throw new Error('Test error');
|
|
80
|
+
});
|
|
81
|
+
expect(result).toBe(false);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should handle empty array and asynchronous operator function', async () => {
|
|
85
|
+
const array: number[] = [];
|
|
86
|
+
const result = await someAsync(array, async () => {
|
|
87
|
+
await waitMs(100);
|
|
88
|
+
return Promise.resolve(false);
|
|
89
|
+
});
|
|
90
|
+
expect(result).toBe(false);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run the operator function on each item in the array, returning true if
|
|
3
|
+
* the operator function returns true for any item in the array
|
|
4
|
+
* @author Gabe Abrams
|
|
5
|
+
* @param operatorFunction the operator function to apply. If it returns true
|
|
6
|
+
* for any item, this function will return true
|
|
7
|
+
* @returns true if the operator function returns true for any item in the array
|
|
8
|
+
*/
|
|
9
|
+
const someAsync = async <T>(
|
|
10
|
+
array: T[],
|
|
11
|
+
operatorFunction: (
|
|
12
|
+
item: T,
|
|
13
|
+
index: number,
|
|
14
|
+
opts: {
|
|
15
|
+
breakNow: () => void,
|
|
16
|
+
array: Array<T>,
|
|
17
|
+
},
|
|
18
|
+
) => Promise<any>,
|
|
19
|
+
): Promise<boolean> => {
|
|
20
|
+
// Create break logic
|
|
21
|
+
let done = false;
|
|
22
|
+
/**
|
|
23
|
+
* Break the loop (checking stops here)
|
|
24
|
+
* @author Gabe Abrams
|
|
25
|
+
*/
|
|
26
|
+
const breakNow = () => {
|
|
27
|
+
done = true;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Loop through each item, checking
|
|
31
|
+
for (let i = 0; i < array.length && !done; i++) {
|
|
32
|
+
const passed = await operatorFunction(
|
|
33
|
+
array[i],
|
|
34
|
+
i,
|
|
35
|
+
{
|
|
36
|
+
breakNow,
|
|
37
|
+
array,
|
|
38
|
+
},
|
|
39
|
+
);
|
|
40
|
+
if (passed && !done) {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Return false because none returned true
|
|
46
|
+
return false;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export default someAsync;
|
package/src/index.ts
CHANGED
|
@@ -85,6 +85,11 @@ import makeLinksClickable from './helpers/makeLinksClickable';
|
|
|
85
85
|
import combineClassNames from './helpers/combineClassNames';
|
|
86
86
|
import prefixWithAOrAn from './helpers/prefixWithAOrAn';
|
|
87
87
|
import useForceRender from './helpers/useForceRender';
|
|
88
|
+
import everyAsync from './helpers/asyncArrayFunctions/everyAsync';
|
|
89
|
+
import filterAsync from './helpers/asyncArrayFunctions/filterAsync';
|
|
90
|
+
import forEachAsync from './helpers/asyncArrayFunctions/forEachAsync';
|
|
91
|
+
import mapAsync from './helpers/asyncArrayFunctions/mapAsync';
|
|
92
|
+
import someAsync from './helpers/asyncArrayFunctions/someAsync';
|
|
88
93
|
|
|
89
94
|
// Import types
|
|
90
95
|
import ModalButtonType from './types/ModalButtonType';
|
|
@@ -181,6 +186,11 @@ export {
|
|
|
181
186
|
idify,
|
|
182
187
|
makeLinksClickable,
|
|
183
188
|
prefixWithAOrAn,
|
|
189
|
+
everyAsync,
|
|
190
|
+
filterAsync,
|
|
191
|
+
forEachAsync,
|
|
192
|
+
mapAsync,
|
|
193
|
+
someAsync,
|
|
184
194
|
// Client helpers
|
|
185
195
|
initClient,
|
|
186
196
|
visitServerEndpoint,
|