forked from microsoft/TypeScript
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcomparison.ts
More file actions
210 lines (184 loc) · 9.24 KB
/
Copy pathcomparison.ts
File metadata and controls
210 lines (184 loc) · 9.24 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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
/// <reference path="types.ts" />
/* @internal */
namespace ts {
export function equateValues<T>(a: T, b: T) {
return a === b;
}
/**
* Compare the equality of two strings using a case-sensitive ordinal comparison.
*
* Case-sensitive comparisons compare both strings one code-point at a time using the integer
* value of each code-point after applying `toUpperCase` to each string. We always map both
* strings to their upper-case form as some unicode characters do not properly round-trip to
* lowercase (such as `ẞ` (German sharp capital s)).
*/
export function equateStringsCaseInsensitive(a: string, b: string) {
return a === b
|| a !== undefined
&& b !== undefined
&& a.toUpperCase() === b.toUpperCase();
}
/**
* Compare the equality of two strings using a case-sensitive ordinal comparison.
*
* Case-sensitive comparisons compare both strings one code-point at a time using the
* integer value of each code-point.
*/
export function equateStringsCaseSensitive(a: string, b: string) {
return equateValues(a, b);
}
function compareComparableValues(a: string, b: string): Comparison;
function compareComparableValues(a: number, b: number): Comparison;
function compareComparableValues(a: string | number, b: string | number) {
return a === b ? Comparison.EqualTo :
a === undefined ? Comparison.LessThan :
b === undefined ? Comparison.GreaterThan :
a < b ? Comparison.LessThan :
Comparison.GreaterThan;
}
/**
* Compare two numeric values for their order relative to each other.
* To compare strings, use any of the `compareStrings` functions.
*/
export function compareValues(a: number, b: number) {
return compareComparableValues(a, b);
}
/**
* Compare two strings using a case-insensitive ordinal comparison.
*
* Ordinal comparisons are based on the difference between the unicode code points of both
* strings. Characters with multiple unicode representations are considered unequal. Ordinal
* comparisons provide predictable ordering, but place "a" after "B".
*
* Case-insensitive comparisons compare both strings one code-point at a time using the integer
* value of each code-point after applying `toUpperCase` to each string. We always map both
* strings to their upper-case form as some unicode characters do not properly round-trip to
* lowercase (such as `ẞ` (German sharp capital s)).
*/
export function compareStringsCaseInsensitive(a: string, b: string) {
if (a === b) return Comparison.EqualTo;
if (a === undefined) return Comparison.LessThan;
if (b === undefined) return Comparison.GreaterThan;
a = a.toUpperCase();
b = b.toUpperCase();
return a < b ? Comparison.LessThan : a > b ? Comparison.GreaterThan : Comparison.EqualTo;
}
/**
* Compare two strings using a case-sensitive ordinal comparison.
*
* Ordinal comparisons are based on the difference between the unicode code points of both
* strings. Characters with multiple unicode representations are considered unequal. Ordinal
* comparisons provide predictable ordering, but place "a" after "B".
*
* Case-sensitive comparisons compare both strings one code-point at a time using the integer
* value of each code-point.
*/
export function compareStringsCaseSensitive(a: string, b: string) {
return compareComparableValues(a, b);
}
/**
* Creates a string comparer for use with string collation in the UI.
*/
const createUIStringComparer = (() => {
let defaultComparer: Comparer<string> | undefined;
let enUSComparer: Comparer<string> | undefined;
const stringComparerFactory = getStringComparerFactory();
return createStringComparer;
function compareWithCallback(a: string | undefined, b: string | undefined, comparer: (a: string, b: string) => number) {
if (a === b) return Comparison.EqualTo;
if (a === undefined) return Comparison.LessThan;
if (b === undefined) return Comparison.GreaterThan;
const value = comparer(a, b);
return value < 0 ? Comparison.LessThan : value > 0 ? Comparison.GreaterThan : Comparison.EqualTo;
}
function createIntlCollatorStringComparer(locale: string | undefined): Comparer<string> {
// Intl.Collator.prototype.compare is bound to the collator. See NOTE in
// http://www.ecma-international.org/ecma-402/2.0/#sec-Intl.Collator.prototype.compare
const comparer = new Intl.Collator(locale, { usage: "sort", sensitivity: "variant" }).compare;
return (a, b) => compareWithCallback(a, b, comparer);
}
function createLocaleCompareStringComparer(locale: string | undefined): Comparer<string> {
// if the locale is not the default locale (`undefined`), use the fallback comparer.
if (locale !== undefined) return createFallbackStringComparer();
return (a, b) => compareWithCallback(a, b, compareStrings);
function compareStrings(a: string, b: string) {
return a.localeCompare(b);
}
}
function createFallbackStringComparer(): Comparer<string> {
// An ordinal comparison puts "A" after "b", but for the UI we want "A" before "b".
// We first sort case insensitively. So "Aaa" will come before "baa".
// Then we sort case sensitively, so "aaa" will come before "Aaa".
//
// For case insensitive comparisons we always map both strings to their
// upper-case form as some unicode characters do not properly round-trip to
// lowercase (such as `ẞ` (German sharp capital s)).
return (a, b) => compareWithCallback(a, b, compareDictionaryOrder);
function compareDictionaryOrder(a: string, b: string) {
return compareStrings(a.toUpperCase(), b.toUpperCase()) || compareStrings(a, b);
}
function compareStrings(a: string, b: string) {
return a < b ? Comparison.LessThan : a > b ? Comparison.GreaterThan : Comparison.EqualTo;
}
}
function getStringComparerFactory() {
// If the host supports Intl, we use it for comparisons using the default locale.
if (typeof Intl === "object" && typeof Intl.Collator === "function") {
return createIntlCollatorStringComparer;
}
// If the host does not support Intl, we fall back to localeCompare.
// localeCompare in Node v0.10 is just an ordinal comparison, so don't use it.
if (typeof String.prototype.localeCompare === "function" &&
typeof String.prototype.toLocaleUpperCase === "function" &&
"a".localeCompare("B") < 0) {
return createLocaleCompareStringComparer;
}
// Otherwise, fall back to ordinal comparison:
return createFallbackStringComparer;
}
function createStringComparer(locale: string | undefined) {
// Hold onto common string comparers. This avoids constantly reallocating comparers during
// tests.
if (locale === undefined) {
return defaultComparer || (defaultComparer = stringComparerFactory(locale));
}
else if (locale === "en-US") {
return enUSComparer || (enUSComparer = stringComparerFactory(locale));
}
else {
return stringComparerFactory(locale);
}
}
})();
let uiComparerCaseSensitive: Comparer<string> | undefined;
let uiLocale: string | undefined;
export function getUILocale() {
return uiLocale;
}
export function setUILocale(value: string) {
if (uiLocale !== value) {
uiLocale = value;
uiComparerCaseSensitive = undefined;
}
}
/**
* Compare two strings in a using the case-sensitive sort behavior of the UI locale.
*
* Ordering is not predictable between different host locales, but is best for displaying
* ordered data for UI presentation. Characters with multiple unicode representations may
* be considered equal.
*
* Case-sensitive comparisons compare strings that differ in base characters, or
* accents/diacritic marks, or case as unequal.
*/
export function compareStringsCaseSensitiveUI(a: string, b: string) {
const comparer = uiComparerCaseSensitive || (uiComparerCaseSensitive = createUIStringComparer(uiLocale));
return comparer(a, b);
}
export function compareProperties<T, K extends keyof T>(a: T, b: T, key: K, comparer: Comparer<T[K]>) {
return a === b ? Comparison.EqualTo :
a === undefined ? Comparison.LessThan :
b === undefined ? Comparison.GreaterThan :
comparer(a[key], b[key]);
}
}