@xylabs/array 5.0.34 → 5.0.36

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xylabs/array",
3
- "version": "5.0.34",
3
+ "version": "5.0.36",
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.34"
47
+ "@xylabs/exists": "~5.0.36"
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.34",
52
+ "@xylabs/vitest-extended": "~5.0.36",
50
53
  "typescript": "~5.9.3",
51
54
  "vitest": "~4.0.9"
52
55
  },
@@ -1,2 +0,0 @@
1
- import '@xylabs/vitest-extended';
2
- //# sourceMappingURL=containsAll.spec.d.ts.map
@@ -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,2 +0,0 @@
1
- import '@xylabs/vitest-extended';
2
- //# sourceMappingURL=distinct.spec.d.ts.map
@@ -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,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=filterAsync.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"filterAsync.spec.d.ts","sourceRoot":"","sources":["../../../src/spec/filterAsync.spec.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=flatten.spec.d.ts.map
@@ -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
- })
@@ -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
- })