Skip to content

Commit d7e33c9

Browse files
author
Kanchalai Tanglertsampan
committed
Guard localeCompare function
1 parent 3b0515f commit d7e33c9

File tree

5 files changed

+26
-10
lines changed

5 files changed

+26
-10
lines changed

src/compiler/core.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,24 @@ namespace ts {
2020

2121
const createObject = Object.create;
2222

23+
// More efficient to create a collator once and use its `compare` than to call `a.localeCompare(b)` many times.
24+
export const collator: { compare(a: string, b: string): number } = typeof Intl === "object" && typeof Intl.Collator === "function" ? new Intl.Collator() : undefined;
25+
26+
/**
27+
* Use this function instead of calling "String.prototype.localeCompre". This function will preform appropriate check to make sure that
28+
* "typeof Intl" is correct as there are reported issues #11110 nad #11339.
29+
* @param a reference string to compare
30+
* @param b string to compare against
31+
* @param locales string of BCP 47 language tag or an array of string of BCP 47 language tag
32+
* @param options an object of Intl.CollatorOptions to specify localeCompare properties
33+
*/
34+
export function localeCompare(a: string, b: string, locales?: string | string[], options?: Intl.CollatorOptions): number | undefined {
35+
if (collator && String.prototype.localeCompare) {
36+
return a.localeCompare(b, locales, options);
37+
}
38+
return undefined;
39+
}
40+
2341
export function createMap<T>(template?: MapLike<T>): Map<T> {
2442
const map: Map<T> = createObject(null); // tslint:disable-line:no-null-keyword
2543

@@ -1016,8 +1034,8 @@ namespace ts {
10161034
if (a === undefined) return Comparison.LessThan;
10171035
if (b === undefined) return Comparison.GreaterThan;
10181036
if (ignoreCase) {
1019-
if (String.prototype.localeCompare) {
1020-
const result = a.localeCompare(b, /*locales*/ undefined, { usage: "sort", sensitivity: "accent" });
1037+
const result = localeCompare(a, b, /*locales*/ undefined, /*options*/ { usage: "sort", sensitivity: "accent" });
1038+
if (result) {
10211039
return result < 0 ? Comparison.LessThan : result > 0 ? Comparison.GreaterThan : Comparison.EqualTo;
10221040
}
10231041

src/harness/harness.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1634,7 +1634,7 @@ namespace Harness {
16341634

16351635
export function collateOutputs(outputFiles: Harness.Compiler.GeneratedFile[]): string {
16361636
// Collect, test, and sort the fileNames
1637-
outputFiles.sort((a, b) => cleanName(a.fileName).localeCompare(cleanName(b.fileName)));
1637+
outputFiles.sort((a, b) => ts.localeCompare(cleanName(a.fileName), cleanName(b.fileName)));
16381638

16391639
// Emit them
16401640
let result = "";

src/server/session.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -959,7 +959,7 @@ namespace ts.server {
959959
result.push({ name, kind, kindModifiers, sortText, replacementSpan: convertedSpan });
960960
}
961961
return result;
962-
}, []).sort((a, b) => a.name.localeCompare(b.name));
962+
}, []).sort((a, b) => localeCompare(a.name, b.name));
963963
}
964964
else {
965965
return completions;

src/services/navigateTo.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,8 @@ namespace ts.NavigateTo {
188188
// We first sort case insensitively. So "Aaa" will come before "bar".
189189
// Then we sort case sensitively, so "aaa" will come before "Aaa".
190190
return i1.matchKind - i2.matchKind ||
191-
i1.name.localeCompare(i2.name, undefined, baseSensitivity) ||
192-
i1.name.localeCompare(i2.name);
191+
ts.localeCompare(i1.name, i2.name, /*locales*/ undefined, /*options*/ baseSensitivity) ||
192+
ts.localeCompare(i1.name, i2.name);
193193
}
194194

195195
function createNavigateToItem(rawItem: RawNavigateToItem): NavigateToItem {

src/services/navigationBar.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -323,10 +323,8 @@ namespace ts.NavigationBar {
323323
}
324324
}
325325

326-
// More efficient to create a collator once and use its `compare` than to call `a.localeCompare(b)` many times.
327-
const collator: { compare(a: string, b: string): number } = typeof Intl === "object" && typeof Intl.Collator === "function" ? new Intl.Collator() : undefined;
328326
// Intl is missing in Safari, and node 0.10 treats "a" as greater than "B".
329-
const localeCompareIsCorrect = collator && collator.compare("a", "B") < 0;
327+
const localeCompareIsCorrect = ts.collator && ts.collator.compare("a", "B") < 0;
330328
const localeCompareFix: (a: string, b: string) => number = localeCompareIsCorrect ? collator.compare : function(a, b) {
331329
// This isn't perfect, but it passes all of our tests.
332330
for (let i = 0; i < Math.min(a.length, b.length); i++) {
@@ -337,7 +335,7 @@ namespace ts.NavigationBar {
337335
if (chA === "'" && chB === "\"") {
338336
return -1;
339337
}
340-
const cmp = chA.toLocaleLowerCase().localeCompare(chB.toLocaleLowerCase());
338+
const cmp = ts.localeCompare(chA.toLocaleLowerCase(), chB.toLocaleLowerCase());
341339
if (cmp !== 0) {
342340
return cmp;
343341
}

0 commit comments

Comments
 (0)