1
|
|
|
import { SortOptions } from './types'; |
2
|
1 |
|
import { isSortablePrimitive, hasNullishValues } from './type-guards'; |
3
|
1 |
|
import { compareSortablePrimitives } from './comparators'; |
4
|
|
|
|
5
|
1 |
|
export function sortArray<T>(array: T[], options: SortOptions): T[] { |
6
|
72 |
|
if (shouldSortPrimitiveArray(array, options.sortPrimitiveArrays)) { |
7
|
34 |
|
return sortPrimitiveArray(array, options.ascending) as T[]; |
8
|
|
|
} |
9
|
|
|
|
10
|
106 |
|
return array.map((item) => sortRecursively(item, options)); |
11
|
|
|
} |
12
|
|
|
|
13
|
|
|
function shouldSortPrimitiveArray( |
14
|
|
|
array: unknown[], |
15
|
|
|
sortPrimitiveArrays: boolean |
16
|
|
|
): boolean { |
17
|
72 |
|
return sortPrimitiveArrays && canSortPrimitiveArray(array); |
18
|
|
|
} |
19
|
|
|
|
20
|
|
|
function canSortPrimitiveArray(array: unknown[]): boolean { |
21
|
45 |
|
return ( |
22
|
|
|
allItemsAreSortablePrimitives(array) && allItemsHaveSameSortableType(array) |
23
|
|
|
); |
24
|
|
|
} |
25
|
|
|
|
26
|
|
|
function allItemsAreSortablePrimitives(array: unknown[]): boolean { |
27
|
45 |
|
return array.every(isSortablePrimitive); |
28
|
|
|
} |
29
|
|
|
|
30
|
|
|
function sortPrimitiveArray(array: unknown[], ascending: boolean): unknown[] { |
31
|
|
|
// The array has already been validated as sortable in canSortPrimitiveArray |
32
|
|
|
// No need to check allItemsHaveSameSortableType again |
33
|
168 |
|
return [...array].sort((a, b) => compareSortablePrimitives(a, b, ascending)); |
34
|
|
|
} |
35
|
|
|
|
36
|
|
|
function allItemsHaveSameSortableType(array: unknown[]): boolean { |
37
|
34 |
|
if (array.length === 0) return true; |
38
|
|
|
|
39
|
|
|
// Don't sort arrays that contain null or undefined values |
40
|
|
|
// as they represent absence of value and don't have a natural ordering |
41
|
33 |
|
if (hasNullishValues(array)) { |
42
|
|
|
return false; |
43
|
|
|
} |
44
|
|
|
|
45
|
|
|
// For arrays with only sortable primitives, check if they have the same type |
46
|
33 |
|
const firstItem = array[0]; |
47
|
33 |
|
if (!isSortablePrimitive(firstItem)) return false; |
48
|
|
|
|
49
|
33 |
|
const expectedType = typeof firstItem; |
50
|
120 |
|
const allSameType = array.every((item) => typeof item === expectedType); |
51
|
|
|
|
52
|
|
|
// If all items are the same type, we can sort them normally |
53
|
33 |
|
if (allSameType) return true; |
54
|
|
|
|
55
|
|
|
// If we have mixed primitive types, we can still "sort" them |
56
|
|
|
// (the comparison function will return 0 for different types, maintaining order) |
57
|
|
|
// This allows us to cover the fallback case in compareSortablePrimitives |
58
|
5 |
|
return array.every(isSortablePrimitive); |
59
|
|
|
} |
60
|
|
|
|
61
|
|
|
import { sortRecursively } from './core'; |
62
|
|
|
|