@xylabs/array 5.0.34 → 5.0.35
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/package.json +7 -4
- package/dist/neutral/spec/containsAll.spec.d.ts +0 -2
- package/dist/neutral/spec/containsAll.spec.d.ts.map +0 -1
- package/dist/neutral/spec/distinct.spec.d.ts +0 -2
- package/dist/neutral/spec/distinct.spec.d.ts.map +0 -1
- package/dist/neutral/spec/filterAsync.spec.d.ts +0 -2
- package/dist/neutral/spec/filterAsync.spec.d.ts.map +0 -1
- package/dist/neutral/spec/flatten.spec.d.ts +0 -2
- package/dist/neutral/spec/flatten.spec.d.ts.map +0 -1
- package/src/spec/containsAll.spec.ts +0 -92
- package/src/spec/distinct.spec.ts +0 -73
- package/src/spec/filterAsync.spec.ts +0 -105
- package/src/spec/flatten.spec.ts +0 -18
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xylabs/array",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.35",
|
|
4
4
|
"description": "Base functionality used throughout XY Labs TypeScript/JavaScript libraries",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"xylabs",
|
|
@@ -38,15 +38,18 @@
|
|
|
38
38
|
"types": "./dist/neutral/index.d.ts",
|
|
39
39
|
"files": [
|
|
40
40
|
"dist",
|
|
41
|
-
"src"
|
|
41
|
+
"src",
|
|
42
|
+
"!**/*.bench.*",
|
|
43
|
+
"!**/*.spec.*",
|
|
44
|
+
"!**/*.test.*"
|
|
42
45
|
],
|
|
43
46
|
"dependencies": {
|
|
44
|
-
"@xylabs/exists": "~5.0.
|
|
47
|
+
"@xylabs/exists": "~5.0.35"
|
|
45
48
|
},
|
|
46
49
|
"devDependencies": {
|
|
47
50
|
"@xylabs/ts-scripts-yarn3": "~7.2.8",
|
|
48
51
|
"@xylabs/tsconfig": "~7.2.8",
|
|
49
|
-
"@xylabs/vitest-extended": "~5.0.
|
|
52
|
+
"@xylabs/vitest-extended": "~5.0.35",
|
|
50
53
|
"typescript": "~5.9.3",
|
|
51
54
|
"vitest": "~4.0.9"
|
|
52
55
|
},
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"containsAll.spec.d.ts","sourceRoot":"","sources":["../../../src/spec/containsAll.spec.ts"],"names":[],"mappings":"AAAA,OAAO,yBAAyB,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"distinct.spec.d.ts","sourceRoot":"","sources":["../../../src/spec/distinct.spec.ts"],"names":[],"mappings":"AAAA,OAAO,yBAAyB,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"filterAsync.spec.d.ts","sourceRoot":"","sources":["../../../src/spec/filterAsync.spec.ts"],"names":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"flatten.spec.d.ts","sourceRoot":"","sources":["../../../src/spec/flatten.spec.ts"],"names":[],"mappings":""}
|
|
@@ -1,92 +0,0 @@
|
|
|
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
|
-
})
|
|
@@ -1,73 +0,0 @@
|
|
|
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
|
-
})
|
|
@@ -1,105 +0,0 @@
|
|
|
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
|
-
})
|
package/src/spec/flatten.spec.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
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
|
-
})
|