-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.ts
More file actions
118 lines (105 loc) · 3.34 KB
/
index.ts
File metadata and controls
118 lines (105 loc) · 3.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
export interface Compare {
<T>(func?: BaseComparator<T>): Comparator<T>;
on<T>(transform: (a: T) => any): Comparator<T>;
locale(locales?: string | string[], options?: Intl.CollatorOptions): LocaleComparator;
}
export type BaseComparator<T> = (a: T, b: T) => number;
export interface Comparator<T> extends BaseComparator<T> {
reverse(): Comparator<T>;
from<U>(transform: (a: U) => T): Comparator<U>;
append<U>(predicate: (a: T | U) => a is U, handler?: BaseComparator<U>): Comparator<T | U>;
append(predicate: (a: T) => boolean, handler?: BaseComparator<T>): Comparator<T>;
prepend<U>(predicate: (a: U | T) => a is U, handler?: BaseComparator<U>): Comparator<U | T>;
prepend(predicate: (a: T) => boolean, handler?: BaseComparator<T>): Comparator<T>;
then<U>(handler?: BaseComparator<U>): Comparator<T & U>;
}
export interface LocaleComparator extends Comparator<string> {
readonly collator: Intl.Collator;
}
function defaultComparator<T>(a: T, b: T): number {
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
return 0;
}
function reverse<T>(this: BaseComparator<T>): Comparator<T> {
return compare((a, b) => this(b, a));
}
function from<T, U>(this: BaseComparator<T>, transform: (a: U) => T): Comparator<U> {
return compare((a, b) => this(transform(a), transform(b)));
}
function append<T, U>(
this: BaseComparator<T>,
predicate: (a: T | U) => a is U,
handler: BaseComparator<U> = defaultComparator,
): Comparator<T | U> {
return compare((a, b) => {
if (predicate(a)) {
if (predicate(b)) {
return handler(a, b);
} else {
return 1;
}
} else {
if (predicate(b)) {
return -1;
} else {
return this(a, b);
}
}
});
}
function prepend<T, U>(
this: BaseComparator<T>,
predicate: (a: U | T) => a is U,
handler: BaseComparator<U> = defaultComparator,
): Comparator<T> {
return compare((a, b) => {
if (predicate(a)) {
if (predicate(b)) {
return handler(a, b);
} else {
return -1;
}
} else {
if (predicate(b)) {
return 1;
} else {
return this(a, b);
}
}
});
}
function then<T, U>(
this: BaseComparator<T>,
handler: BaseComparator<U> = defaultComparator,
): Comparator<T & U> {
return compare((a, b) => {
return this(a, b) || handler(a, b);
});
}
const compare: Compare = (<T> (func: BaseComparator<T> = defaultComparator): Comparator<T> => {
const result = func as any;
result.reverse = reverse;
result.from = from;
result.append = append;
result.prepend = prepend;
result.then = then;
return result;
}) as Compare;
compare.on = function on<T>(transform: (a: T) => any): Comparator<T> {
return this<any>().from(transform);
};
compare.locale = function locale(locales?: string | string[], options?: Intl.CollatorOptions): LocaleComparator {
const collator = new Intl.Collator(locales, options);
const result = this(collator.compare) as LocaleComparator;
Object.defineProperty(result, 'collator', {
value: collator,
writable: false,
});
return result;
};
export default compare;