@@ -1483,110 +1483,78 @@ namespace ts {
14831483 return headChain ;
14841484 }
14851485
1486- function toComparison ( value : number ) {
1487- return value < 0 ? Comparison . LessThan : value > 0 ? Comparison . GreaterThan : Comparison . EqualTo ;
1488- }
1489-
1490- function compareNonNullValues < T > ( a : T , b : T ) : Comparison {
1491- return a < b ? Comparison . LessThan : a > b ? Comparison . GreaterThan : Comparison . EqualTo ;
1492- }
1493-
1494- function compareValuesWithCallback < T > ( a : T | undefined , b : T | undefined , comparer : ( a : T , b : T ) => number ) {
1486+ export function compareValues < T > ( a : T | undefined , b : T | undefined ) {
14951487 if ( a === b ) return Comparison . EqualTo ;
14961488 if ( a === undefined ) return Comparison . LessThan ;
14971489 if ( b === undefined ) return Comparison . GreaterThan ;
1498- return toComparison ( comparer ( a , b ) ) ;
1499- }
1500-
1501- export function compareValues < T > ( a : T | undefined , b : T | undefined ) : Comparison {
1502- return compareValuesWithCallback ( a , b , compareNonNullValues ) ;
1503- }
1504-
1505- interface StringComparers {
1506- caseSensitive ( a : string , b : string ) : number ;
1507- caseInsensitive ( a : string , b : string ) : number ;
1490+ return a < b ? Comparison . LessThan : Comparison . GreaterThan ;
15081491 }
15091492
15101493 // Gets string comparers compatible with the current host
1511- function createStringComparers ( ) {
1512- function createIntlComparers ( ) : StringComparers {
1513- // Strings that differ in base, accents/diacritic marks, or case compare as unequal.
1514- // An `undefined` locale uses the default locale of the host.
1515- const caseSensitiveCollator = new Intl . Collator ( /*locales*/ undefined , { usage : "sort" , sensitivity : "variant" } ) ;
1516-
1494+ function createCaseInsensitiveStringComparer ( ) : ( a : string , b : string ) => number {
1495+ // If the host supports Intl (ECMA-402), we use Intl for comparisons using the default
1496+ // locale:
1497+ if ( typeof Intl === "object" && typeof Intl . Collator === "function" ) {
15171498 // Strings that differ in base or accents/diacritic marks compare as unequal.
15181499 // An `undefined` locale uses the default locale of the host.
1519- const caseInsensitiveCollator = new Intl . Collator ( /*locales*/ undefined , { usage : "sort" , sensitivity : "accent" } ) ;
1520-
1521- return {
1522- caseSensitive : ( a , b ) => caseSensitiveCollator . compare ( a , b ) ,
1523- caseInsensitive : ( a , b ) => caseInsensitiveCollator . compare ( a , b )
1524- } ;
1525- }
1526-
1527- function createStringLocaleComparers ( ) : StringComparers {
1528- // for case-insensitive comparisons we always map both strings to their
1529- // upper-case form as some unicode characters do not properly round-trip to
1530- // lowercase (such as ẞ).
1531- return {
1532- caseSensitive : ( a , b ) => a . localeCompare ( b ) ,
1533- caseInsensitive : ( a , b ) => a . toLocaleUpperCase ( ) . localeCompare ( b . toLocaleUpperCase ( ) )
1534- } ;
1535- }
1536-
1537- function createOrdinalComparers ( ) : StringComparers {
1538- // for case-insensitive comparisons we always map both strings to their
1539- // upper-case form as some unicode characters do not properly round-trip to
1540- // lowercase (such as ẞ).
15411500 //
1542- // The ordinal comparison cannot properly handle comparison of the Turkish
1543- // (dotted) i and (dotless) ı to the uppercase forms of (dotted) İ and (dotless) I.
1544- // This is best handled by Intl and not supported in the fallback case.
1545- return {
1546- caseSensitive : compareNonNullValues ,
1547- caseInsensitive : ( a , b ) => compareNonNullValues ( a . toUpperCase ( ) , b . toUpperCase ( ) )
1548- } ;
1501+ // Intl.Collator.prototype.compare is bound to the collator. See NOTE in
1502+ // http://www.ecma-international.org/ecma-402/2.0/#sec-Intl.Collator.prototype.compare
1503+ return new Intl . Collator ( /*locales*/ undefined , { usage : "sort" , sensitivity : "accent" } ) . compare ;
15491504 }
15501505
1551- // If the host supports Intl (ECMA-402), we use Intl for comparisons using the default
1552- // locale.
1553- if ( typeof Intl === "object" && typeof Intl . Collator === "function" ) {
1554- return createIntlComparers ( ) ;
1555- }
1556-
1557- // If the host does not support Intl (Safari, Node v0.10), we fall back to localeCompare.
1506+ // If the host does not support Intl, we fall back to localeCompare:
1507+ //
15581508 // Node v0.10 provides incorrect results for comparisons using localeCompare, so we must
15591509 // verify the implementation.
15601510 if ( typeof String . prototype . localeCompare === "function" &&
15611511 typeof String . prototype . toLocaleUpperCase === "function" &&
15621512 "a" . localeCompare ( "B" ) < 0 ) {
1563- return createStringLocaleComparers ( ) ;
1564- }
1565-
1566- // fall back to ordinal comparison
1567- return createOrdinalComparers ( ) ;
1513+ // for case-insensitive comparisons we always map both strings to their
1514+ // upper-case form as some unicode characters do not properly round-trip to
1515+ // lowercase (such as ẞ).
1516+ return ( a , b ) => a . toLocaleUpperCase ( ) . localeCompare ( b . toLocaleUpperCase ( ) ) ;
1517+ }
1518+
1519+ // Otherwise, fall back to ordinal comparison:
1520+ //
1521+ // for case-insensitive comparisons we always map both strings to their
1522+ // upper-case form as some unicode characters do not properly round-trip to
1523+ // lowercase (such as ẞ).
1524+ //
1525+ // The ordinal comparison cannot properly handle comparison of the Turkish
1526+ // (dotted) i and (dotless) ı to the uppercase forms of (dotted) İ and (dotless) I.
1527+ // This is best handled by Intl and not supported in the fallback case.
1528+ return ( a , b ) => {
1529+ const upperA = a . toUpperCase ( ) ;
1530+ const upperB = b . toUpperCase ( ) ;
1531+ return upperA < upperB ? Comparison . LessThan :
1532+ upperA > upperB ? Comparison . GreaterThan :
1533+ Comparison . EqualTo ;
1534+ } ;
15681535 }
15691536
1570- const stringComparers = createStringComparers ( ) ;
1537+ const caseInsensitiveComparer = createCaseInsensitiveStringComparer ( ) ;
15711538
15721539 /**
1573- * Performs a case-sensitive comparison between two strings.
1540+ * Performs a case-insensitive comparison between two strings.
15741541 *
15751542 * If supported by the host, the default locale is used for comparisons. Otherwise, an ordinal
15761543 * comparison is used.
15771544 */
1578- export function compareStringsCaseSensitive ( a : string | undefined , b : string | undefined ) {
1579- return compareValuesWithCallback ( a , b , stringComparers . caseSensitive ) ;
1545+ export function compareStringsCaseInsensitive ( a : string | undefined , b : string | undefined ) {
1546+ if ( a === b ) return Comparison . EqualTo ;
1547+ if ( a === undefined ) return Comparison . LessThan ;
1548+ if ( b === undefined ) return Comparison . GreaterThan ;
1549+ const result = caseInsensitiveComparer ( a , b ) ;
1550+ return result < 0 ? Comparison . LessThan : result > 0 ? Comparison . GreaterThan : Comparison . EqualTo ;
15801551 }
15811552
15821553 /**
1583- * Performs a case-insensitive comparison between two strings.
1584- *
1585- * If supported by the host, the default locale is used for comparisons. Otherwise, an ordinal
1586- * comparison is used.
1554+ * Performs a case-sensitive comparison between two strings.
15871555 */
1588- export function compareStringsCaseInsensitive ( a : string | undefined , b : string | undefined ) {
1589- return compareValuesWithCallback ( a , b , stringComparers . caseInsensitive ) ;
1556+ export function compareStringsCaseSensitive ( a : string | undefined , b : string | undefined ) {
1557+ return compareValues ( a , b ) ;
15901558 }
15911559
15921560 export function compareStrings ( a : string | undefined , b : string | undefined , ignoreCase ?: boolean ) : Comparison {
0 commit comments