@xylabs/array 4.13.19 → 4.13.21

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/README.md CHANGED
@@ -12,13 +12,326 @@
12
12
  [![snyk-badge][]][snyk-link]
13
13
  [![socket-badge][]][socket-link]
14
14
 
15
- Version: 4.13.15
16
15
 
17
16
  Base functionality used throughout XY Labs TypeScript/JavaScript libraries
18
17
 
19
- ## Documentation
18
+ ## API Documentation
19
+
20
+ **@xylabs/array**
21
+
22
+ ***
23
+
24
+ ## Functions
25
+
26
+ - [containsAll](#functions/containsAll)
27
+ - [distinct](#functions/distinct)
28
+ - [filterAs](#functions/filterAs)
29
+ - [filterAsync](#functions/filterAsync)
30
+ - [findAs](#functions/findAs)
31
+ - [findLastAs](#functions/findLastAs)
32
+ - [flatten](#functions/flatten)
33
+ - [uniq](#functions/uniq)
34
+ - [uniqBy](#functions/uniqBy)
35
+
36
+ ### functions
37
+
38
+ ### <a id="containsAll"></a>containsAll
39
+
40
+ [**@xylabs/array**](#../README)
41
+
42
+ ***
43
+
44
+ ```ts
45
+ function containsAll<T>(source, target): boolean;
46
+ ```
47
+
48
+ ## Type Parameters
49
+
50
+ ### T
51
+
52
+ `T`
53
+
54
+ ## Parameters
55
+
56
+ ### source
57
+
58
+ `T`[]
59
+
60
+ ### target
61
+
62
+ `T`[]
63
+
64
+ ## Returns
65
+
66
+ `boolean`
67
+
68
+ ### <a id="distinct"></a>distinct
69
+
70
+ [**@xylabs/array**](#../README)
71
+
72
+ ***
73
+
74
+ ```ts
75
+ function distinct<T>(
76
+ value,
77
+ index,
78
+ array): boolean;
79
+ ```
80
+
81
+ ## Type Parameters
82
+
83
+ ### T
84
+
85
+ `T`
86
+
87
+ ## Parameters
88
+
89
+ ### value
90
+
91
+ `T`
92
+
93
+ ### index
94
+
95
+ `number`
96
+
97
+ ### array
98
+
99
+ `T`[]
100
+
101
+ ## Returns
102
+
103
+ `boolean`
104
+
105
+ ### <a id="filterAs"></a>filterAs
106
+
107
+ [**@xylabs/array**](#../README)
108
+
109
+ ***
110
+
111
+ ```ts
112
+ function filterAs<In, Out>(x, predicate): NonNullable<Out>[];
113
+ ```
114
+
115
+ ## Type Parameters
116
+
117
+ ### In
118
+
119
+ `In`
120
+
121
+ ### Out
122
+
123
+ `Out`
124
+
125
+ ## Parameters
126
+
127
+ ### x
128
+
129
+ `In`[]
130
+
131
+ ### predicate
132
+
133
+ (`a`) => `Out`
134
+
135
+ ## Returns
136
+
137
+ `NonNullable`\<`Out`\>[]
138
+
139
+ ### <a id="filterAsync"></a>filterAsync
140
+
141
+ [**@xylabs/array**](#../README)
142
+
143
+ ***
144
+
145
+ ```ts
146
+ function filterAsync<T>(array, predicate): Promise<T[]>;
147
+ ```
148
+
149
+ Returns the elements of an array that meet the condition specified in a callback function.
150
+
151
+ ## Type Parameters
152
+
153
+ ### T
154
+
155
+ `T`
156
+
157
+ ## Parameters
158
+
159
+ ### array
160
+
161
+ `T`[]
162
+
163
+ The array to filter.
164
+
165
+ ### predicate
166
+
167
+ (`value`, `index`, `array`) => `Promise`\<`boolean`\>
168
+
169
+ A function that accepts up to three arguments. The filter method calls the predicate function one time for each element in the array.
170
+
171
+ ## Returns
172
+
173
+ `Promise`\<`T`[]\>
174
+
175
+ The elements of an array that meet the condition specified in a callback function.
176
+
177
+ ### <a id="findAs"></a>findAs
178
+
179
+ [**@xylabs/array**](#../README)
180
+
181
+ ***
182
+
183
+ ```ts
184
+ function findAs<In, Out>(x, predicate): undefined | NonNullable<Out>;
185
+ ```
186
+
187
+ ## Type Parameters
188
+
189
+ ### In
190
+
191
+ `In`
192
+
193
+ ### Out
194
+
195
+ `Out`
196
+
197
+ ## Parameters
198
+
199
+ ### x
200
+
201
+ `In`[]
202
+
203
+ ### predicate
204
+
205
+ (`a`) => `Out`
206
+
207
+ ## Returns
208
+
209
+ `undefined` \| `NonNullable`\<`Out`\>
210
+
211
+ ### <a id="findLastAs"></a>findLastAs
212
+
213
+ [**@xylabs/array**](#../README)
214
+
215
+ ***
216
+
217
+ ```ts
218
+ function findLastAs<In, Out>(x, predicate): undefined | NonNullable<Out>;
219
+ ```
220
+
221
+ ## Type Parameters
222
+
223
+ ### In
224
+
225
+ `In`
226
+
227
+ ### Out
228
+
229
+ `Out`
230
+
231
+ ## Parameters
232
+
233
+ ### x
234
+
235
+ `In`[]
236
+
237
+ ### predicate
238
+
239
+ (`a`) => `Out`
240
+
241
+ ## Returns
242
+
243
+ `undefined` \| `NonNullable`\<`Out`\>
244
+
245
+ ### <a id="flatten"></a>flatten
246
+
247
+ [**@xylabs/array**](#../README)
248
+
249
+ ***
250
+
251
+ ```ts
252
+ function flatten<T>(a?, b?): T[];
253
+ ```
254
+
255
+ ## Type Parameters
256
+
257
+ ### T
258
+
259
+ `T`
260
+
261
+ ## Parameters
262
+
263
+ ### a?
264
+
265
+ `T` | `ConcatArray`\<`T`\>
266
+
267
+ ### b?
268
+
269
+ `T` | `ConcatArray`\<`T`\>
270
+
271
+ ## Returns
272
+
273
+ `T`[]
274
+
275
+ ### <a id="uniq"></a>uniq
276
+
277
+ [**@xylabs/array**](#../README)
278
+
279
+ ***
280
+
281
+ ```ts
282
+ function uniq<T>(arr): T[];
283
+ ```
284
+
285
+ ## Type Parameters
286
+
287
+ ### T
288
+
289
+ `T`
290
+
291
+ ## Parameters
292
+
293
+ ### arr
294
+
295
+ `T`[]
296
+
297
+ ## Returns
298
+
299
+ `T`[]
300
+
301
+ ### <a id="uniqBy"></a>uniqBy
302
+
303
+ [**@xylabs/array**](#../README)
304
+
305
+ ***
306
+
307
+ ```ts
308
+ function uniqBy<T, I>(arr, iteratee): T[];
309
+ ```
310
+
311
+ ## Type Parameters
312
+
313
+ ### T
314
+
315
+ `T`
316
+
317
+ ### I
318
+
319
+ `I`
320
+
321
+ ## Parameters
322
+
323
+ ### arr
324
+
325
+ `T`[]
326
+
327
+ ### iteratee
328
+
329
+ (`item`) => `I`
330
+
331
+ ## Returns
332
+
333
+ `T`[]
20
334
 
21
- Coming Soon!
22
335
 
23
336
  Part of [sdk-js](https://www.npmjs.com/package/@xyo-network/sdk-js)
24
337
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xylabs/array",
3
- "version": "4.13.19",
3
+ "version": "4.13.21",
4
4
  "description": "Base functionality used throughout XY Labs TypeScript/JavaScript libraries",
5
5
  "keywords": [
6
6
  "xylabs",
@@ -28,19 +28,25 @@
28
28
  "exports": {
29
29
  ".": {
30
30
  "types": "./dist/neutral/index.d.ts",
31
+ "source": "./src/index.ts",
31
32
  "default": "./dist/neutral/index.mjs"
32
33
  },
33
34
  "./package.json": "./package.json"
34
35
  },
35
36
  "module": "./dist/neutral/index.mjs",
37
+ "source": "./src/index.ts",
36
38
  "types": "./dist/neutral/index.d.ts",
39
+ "files": [
40
+ "dist",
41
+ "src"
42
+ ],
37
43
  "dependencies": {
38
- "@xylabs/exists": "^4.13.19"
44
+ "@xylabs/exists": "^4.13.21"
39
45
  },
40
46
  "devDependencies": {
41
- "@xylabs/ts-scripts-yarn3": "^7.0.0-rc.27",
42
- "@xylabs/tsconfig": "^7.0.0-rc.27",
43
- "@xylabs/vitest-extended": "^4.13.19",
47
+ "@xylabs/ts-scripts-yarn3": "^7.0.0",
48
+ "@xylabs/tsconfig": "^7.0.0",
49
+ "@xylabs/vitest-extended": "^4.13.21",
44
50
  "typescript": "^5.8.3",
45
51
  "vitest": "^3.2.4"
46
52
  },
@@ -0,0 +1,92 @@
1
+ import '@xylabs/vitest-extended'
2
+
3
+ import {
4
+ describe, expect, it,
5
+ } from 'vitest'
6
+
7
+ import { containsAll } from '../containsAll.ts'
8
+
9
+ describe('containsAll', () => {
10
+ describe('when the source array contains all the target elements', () => {
11
+ const testCases: [unknown[], unknown[]][] = [
12
+ [
13
+ [1, 2, 3, 4, 5, 6],
14
+ [1, 2, 3],
15
+ ],
16
+ [
17
+ ['f', 'e', 'd', 'c', 'b', 'a'],
18
+ ['a', 'b', 'c'],
19
+ ],
20
+ ]
21
+ it.each(testCases)('returns true', (source, target) => {
22
+ expect(containsAll(source, target)).toBeTrue()
23
+ })
24
+ })
25
+ describe('when the source array does not contain all the target elements', () => {
26
+ const testCases: [unknown[], unknown[]][] = [
27
+ [
28
+ [1, 2, 3, 4, 5, 6],
29
+ [5, 6, 7],
30
+ ],
31
+ [
32
+ ['f', 'e', 'd', 'c', 'b', 'a'],
33
+ ['d', 'e', 'f', 'g'],
34
+ ],
35
+ ]
36
+ it.each(testCases)('returns false', (source, target) => {
37
+ expect(containsAll(source, target)).toBeFalse()
38
+ })
39
+ })
40
+
41
+ // Edge cases with empty arrays
42
+ describe('when working with empty arrays', () => {
43
+ const testCases: [unknown[], unknown[], boolean][] = [
44
+ [[], [], true], // Empty source, empty target should be true
45
+ [[1, 2, 3], [], true], // Non-empty source, empty target should be true
46
+ [[], [1, 2, 3], false], // Empty source, non-empty target should be false
47
+ ]
48
+ it.each(testCases)('handles the case correctly', (source, target, expected) => {
49
+ expect(containsAll(source, target)).toBe(expected)
50
+ })
51
+ })
52
+
53
+ // Cases with duplicate elements
54
+ describe('when arrays contain duplicate elements', () => {
55
+ const testCases: [unknown[], unknown[]][] = [
56
+ [[1, 2, 2, 3, 3, 3], [2, 3]], // Duplicates in source
57
+ [[1, 2, 3], [2, 2, 3, 3]], // Duplicates in target (should still work if source has at least one of each)
58
+ ]
59
+ it.each(testCases)('returns true when all unique elements are pxresent', (source, target) => {
60
+ expect(containsAll(source, target)).toBeTrue()
61
+ })
62
+ })
63
+
64
+ // Objects and reference types
65
+ describe('when arrays contain objects', () => {
66
+ const obj1 = { id: 1 }
67
+ const obj2 = { id: 2 }
68
+ const obj3 = { id: 3 }
69
+
70
+ it('checks object references correctly', () => {
71
+ // Same objects (by reference)
72
+ expect(containsAll([obj1, obj2, obj3], [obj1, obj2])).toBeTrue()
73
+
74
+ // Different objects with same content
75
+ expect(containsAll([obj1, obj2, obj3], [{ id: 1 }, { id: 2 }])).toBeFalse()
76
+ })
77
+ })
78
+
79
+ // Special values
80
+ describe('when arrays contain special values', () => {
81
+ it('handles null and undefined correctly', () => {
82
+ expect(containsAll([null, undefined, 1, 2], [null, undefined])).toBeTrue()
83
+ expect(containsAll([1, 2, 3], [undefined])).toBeFalse()
84
+ })
85
+
86
+ it('handles NaN correctly', () => {
87
+ // Note: This depends on how containsAll is implemented
88
+ // NaN !== NaN in JavaScript, so this might fail depending on implementation
89
+ expect(containsAll([Number.NaN, 1, 2], [Number.NaN])).toBeTrue()
90
+ })
91
+ })
92
+ })
@@ -0,0 +1,73 @@
1
+ import '@xylabs/vitest-extended'
2
+
3
+ import {
4
+ describe, expect, it,
5
+ } from 'vitest'
6
+
7
+ import { distinct } from '../distinct.ts'
8
+
9
+ describe('distinct', () => {
10
+ describe('basic scenarios', () => {
11
+ const testCases: [unknown[], unknown[]][] = [
12
+ [
13
+ [1, 2, 3, 3, 2, 1],
14
+ [1, 2, 3],
15
+ ],
16
+ [
17
+ ['a', 'b', 'c', 'c', 'b', 'a'],
18
+ ['a', 'b', 'c'],
19
+ ],
20
+ ]
21
+ it.each(testCases)('removes duplicates', (input, expected) => {
22
+ expect(input.filter(distinct)).toEqual(expected)
23
+ })
24
+ })
25
+
26
+ describe('edge cases', () => {
27
+ it('handles empty arrays', () => {
28
+ expect([].filter(distinct)).toEqual([])
29
+ })
30
+
31
+ it('handles arrays with a single element', () => {
32
+ expect([5].filter(distinct)).toEqual([5])
33
+ })
34
+
35
+ it('preserves order of first occurrence', () => {
36
+ expect([3, 1, 2, 3, 2, 1].filter(distinct)).toEqual([3, 1, 2])
37
+ })
38
+ })
39
+
40
+ describe('special values', () => {
41
+ it('handles null and undefined', () => {
42
+ expect([null, undefined, null, undefined].filter(distinct)).toEqual([null, undefined])
43
+ })
44
+
45
+ it('handles mixed types', () => {
46
+ expect([1, '1', true, 1, '1', true].filter(distinct)).toEqual([1, '1', true])
47
+ })
48
+
49
+ it('handles NaN values', () => {
50
+ const result = [Number.NaN, Number.NaN, 1, 2].filter(distinct)
51
+ expect(result.length).toBe(3)
52
+ expect(Number.isNaN(result[0])).toBeTrue()
53
+ expect(result.slice(1)).toEqual([1, 2])
54
+ })
55
+ })
56
+
57
+ describe('objects and references', () => {
58
+ it('distinguishes objects by reference', () => {
59
+ const obj1 = { id: 1 }
60
+ const obj2 = { id: 2 }
61
+ const obj3 = { id: 1 } // Same content as obj1, different reference
62
+
63
+ expect([obj1, obj2, obj1, obj3].filter(distinct)).toEqual([obj1, obj2, obj3])
64
+ })
65
+
66
+ it('works with complex nested objects', () => {
67
+ const obj1 = { user: { name: 'Alice', id: 1 } }
68
+ const obj2 = { user: { name: 'Bob', id: 2 } }
69
+
70
+ expect([obj1, obj2, obj1].filter(distinct)).toEqual([obj1, obj2])
71
+ })
72
+ })
73
+ })
@@ -0,0 +1,105 @@
1
+ import {
2
+ describe, expect, it,
3
+ } from 'vitest'
4
+
5
+ import { filterAsync } from '../filterAsync.ts'
6
+
7
+ describe('filterAsync', () => {
8
+ const evenNumbers = async (value: number) => await Promise.resolve(value % 2 === 0) // Keep even numbers
9
+ it('filters an array based on an asynchronous predicate', async () => {
10
+ const array = [1, 2, 3, 4, 5]
11
+ const result = await filterAsync(array, evenNumbers)
12
+ expect(result).toEqual([2, 4])
13
+ })
14
+
15
+ it('returns an empty array if no elements match the predicate', async () => {
16
+ const array = [1, 3, 5]
17
+ const result = await filterAsync(array, evenNumbers)
18
+ expect(result).toEqual([])
19
+ })
20
+
21
+ it('returns the original array if all elements match the predicate', async () => {
22
+ const array = [2, 4, 6]
23
+ const result = await filterAsync(array, evenNumbers)
24
+ expect(result).toEqual([2, 4, 6])
25
+ })
26
+
27
+ it('handles an empty array', async () => {
28
+ const array: number[] = []
29
+ const result = await filterAsync(array, evenNumbers)
30
+ expect(result).toEqual([])
31
+ })
32
+
33
+ it('handles predicates that depend on the index', async () => {
34
+ const array = [10, 20, 30, 40, 50]
35
+ const evenIndices = async (_value: number, index: number) =>
36
+ await Promise.resolve(index % 2 === 0) // Keep elements at even indices
37
+ const result = await filterAsync(array, evenIndices)
38
+ expect(result).toEqual([10, 30, 50])
39
+ })
40
+
41
+ it('handles predicates that depend on the entire array', async () => {
42
+ const array = [1, 2, 3, 4, 5]
43
+ const greaterThanMin = async (value: number, _index: number, arr: number[]) =>
44
+ await Promise.resolve(value > Math.min(...arr)) // Keep elements greater than the smallest element
45
+ const result = await filterAsync(array, greaterThanMin)
46
+ expect(result).toEqual([2, 3, 4, 5])
47
+ })
48
+
49
+ it('processes all items concurrently', async () => {
50
+ // This test verifies that all predicate functions are called before any are awaited
51
+ const executionOrder: number[] = []
52
+ const delayedEvenNumbers = async (value: number) => {
53
+ executionOrder.push(value) // Record when this function was called
54
+ // Delay longer for even numbers to ensure non-sequential execution is visible
55
+ const delay = value % 2 === 0 ? 50 : 10
56
+ await new Promise(resolve => setTimeout(resolve, delay))
57
+ return value % 2 === 0
58
+ }
59
+
60
+ const array = [1, 2, 3, 4, 5]
61
+ const result = await filterAsync(array, delayedEvenNumbers)
62
+
63
+ // All items should be processed before any promises resolve
64
+ expect(executionOrder).toEqual([1, 2, 3, 4, 5])
65
+ expect(result).toEqual([2, 4])
66
+ })
67
+
68
+ it('handles rejection in the predicate function', async () => {
69
+ const rejectingPredicate = async (value: number) => {
70
+ if (value === 3) {
71
+ throw new Error('Test error')
72
+ }
73
+ return await Promise.resolve(value % 2 === 0)
74
+ }
75
+
76
+ const array = [1, 2, 3, 4, 5]
77
+ await expect(filterAsync(array, rejectingPredicate)).rejects.toThrow('Test error')
78
+ })
79
+
80
+ it('works with a predicate that sometimes returns synchronously', async () => {
81
+ const mixedPredicate = (value: number) => {
82
+ if (value % 2 === 0) {
83
+ // Return synchronously for even numbers
84
+ return Promise.resolve(true)
85
+ }
86
+ // Return asynchronously for odd numbers
87
+ return Promise.resolve(false)
88
+ }
89
+
90
+ const array = [1, 2, 3, 4, 5]
91
+ const result = await filterAsync(array, mixedPredicate)
92
+ expect(result).toEqual([2, 4])
93
+ })
94
+
95
+ it('handles a large array efficiently', async () => {
96
+ const largeArray = Array.from({ length: 1000 }, (_, i) => i)
97
+ const start = performance.now()
98
+
99
+ const result = await filterAsync(largeArray, evenNumbers)
100
+
101
+ const end = performance.now()
102
+ expect(result.length).toBe(500) // Should have 500 even numbers
103
+ expect(end - start).toBeLessThan(1000) // Should complete in a reasonable time
104
+ })
105
+ })
@@ -0,0 +1,18 @@
1
+ import {
2
+ describe, expect, it,
3
+ } from 'vitest'
4
+
5
+ import { flatten } from '../flatten.ts'
6
+
7
+ describe('flatten', () => {
8
+ const testCases: [unknown | unknown[], unknown | unknown[], unknown | unknown[]][] = [
9
+ [['a'], ['b', 'c'], ['a', 'b', 'c']],
10
+ ['a', ['b', 'c'], ['a', 'b', 'c']],
11
+ [['a', 'b'], undefined, ['a', 'b']],
12
+ [undefined, undefined, []],
13
+ [['a'], [1, 2], ['a', 1, 2]],
14
+ ]
15
+ it.each(testCases)('flattens inputs', (a, b, expected) => {
16
+ expect(flatten(a, b)).toEqual(expected)
17
+ })
18
+ })
package/xy.config.ts DELETED
@@ -1,10 +0,0 @@
1
- import type { XyTsupConfig } from '@xylabs/ts-scripts-yarn3'
2
- const config: XyTsupConfig = {
3
- compile: {
4
- browser: {},
5
- neutral: { src: true },
6
- node: {},
7
- },
8
- }
9
-
10
- export default config