@@ -1483,38 +1483,35 @@ namespace ts {
14831483 return headChain ;
14841484 }
14851485
1486- /**
1487- * Compare two values for their equality.
1488- */
1489- export function equateValues < T > ( a : T , b : T ) {
1486+ function equateValues < T > ( a : T , b : T ) {
14901487 return a === b ;
14911488 }
14921489
14931490 /**
1494- * Compare equality between two strings using an ordinal comparison.
1491+ * Compare the equality of two strings using a case-sensitive ordinal comparison.
14951492 *
1496- * Case-insensitive comparisons compare both strings after applying `toUpperCase` to
1497- * each string.
1493+ * Case-sensitive comparisons compare both strings one code-point at a time using the integer
1494+ * value of each code-point after applying `toUpperCase` to each string. We always map both
1495+ * strings to their upper-case form as some unicode characters do not properly round-trip to
1496+ * lowercase (such as `ẞ` (German sharp capital s)).
14981497 */
1499- export function equateStrings ( a : string , b : string , ignoreCase : boolean ) {
1500- return ignoreCase ? equateStringsCaseInsensitive ( a , b ) : equateStringsCaseSensitive ( a , b ) ;
1501- }
1502-
15031498 export function equateStringsCaseInsensitive ( a : string , b : string ) {
15041499 return a === b
15051500 || a !== undefined
15061501 && b !== undefined
15071502 && a . toUpperCase ( ) === b . toUpperCase ( ) ;
15081503 }
15091504
1505+ /**
1506+ * Compare the equality of two strings using a case-sensitive ordinal comparison.
1507+ *
1508+ * Case-sensitive comparisons compare both strings one code-point at a time using the
1509+ * integer value of each code-point.
1510+ */
15101511 export function equateStringsCaseSensitive ( a : string , b : string ) {
15111512 return equateValues ( a , b ) ;
15121513 }
15131514
1514- export function getStringEqualityComparer ( ignoreCase : boolean ) {
1515- return ignoreCase ? equateStringsCaseInsensitive : equateStringsCaseSensitive ;
1516- }
1517-
15181515 /**
15191516 * Compare two values for their order relative to each other.
15201517 */
@@ -1527,19 +1524,17 @@ namespace ts {
15271524 }
15281525
15291526 /**
1530- * Compare two strings using an ordinal comparison.
1527+ * Compare two strings using a case-insensitive ordinal comparison.
15311528 *
1532- * Ordinal comparisons are based on the difference between the unicode code points of
1533- * both strings. Characters with multiple unicode representations are considered
1534- * unequal. Ordinal comparisons provide predictable ordering, but place "a" after "B".
1529+ * Ordinal comparisons are based on the difference between the unicode code points of both
1530+ * strings. Characters with multiple unicode representations are considered unequal. Ordinal
1531+ * comparisons provide predictable ordering, but place "a" after "B".
15351532 *
1536- * Case-insensitive comparisons compare both strings after applying `toUpperCase` to
1537- * each string.
1533+ * Case-insensitive comparisons compare both strings one code-point at a time using the integer
1534+ * value of each code-point after applying `toUpperCase` to each string. We always map both
1535+ * strings to their upper-case form as some unicode characters do not properly round-trip to
1536+ * lowercase (such as `ẞ` (German sharp capital s)).
15381537 */
1539- export function compareStrings ( a : string , b : string , ignoreCase : boolean ) {
1540- return ignoreCase ? compareStringsCaseInsensitive ( a , b ) : compareStringsCaseSensitive ( a , b ) ;
1541- }
1542-
15431538 export function compareStringsCaseInsensitive ( a : string , b : string ) {
15441539 if ( a === b ) return Comparison . EqualTo ;
15451540 if ( a === undefined ) return Comparison . LessThan ;
@@ -1549,26 +1544,18 @@ namespace ts {
15491544 return a < b ? Comparison . LessThan : a > b ? Comparison . GreaterThan : Comparison . EqualTo ;
15501545 }
15511546
1552- export function compareStringsCaseSensitive ( a : string , b : string ) {
1553- return compareValues ( a , b ) ;
1554- }
1555-
1556- export function getStringComparer ( ignoreCase : boolean ) {
1557- return ignoreCase ? compareStringsCaseInsensitive : compareStringsCaseSensitive ;
1558- }
1559-
15601547 /**
1561- * Compare two strings using the sort behavior of the UI locale .
1548+ * Compare two strings using a case-sensitive ordinal comparison .
15621549 *
1563- * Ordering is not predictable between different host locales, but is best for displaying
1564- * ordered data for UI presentation . Characters with multiple unicode representations may
1565- * be considered equal .
1550+ * Ordinal comparisons are based on the difference between the unicode code points of both
1551+ * strings . Characters with multiple unicode representations are considered unequal. Ordinal
1552+ * comparisons provide predictable ordering, but place "a" after "B" .
15661553 *
1567- * Case-insensitive comparisons compare strings that differ in only base characters or
1568- * accents/diacritic marks as unequal .
1554+ * Case-sensitive comparisons compare both strings one code-point at a time using the integer
1555+ * value of each code-point .
15691556 */
1570- export function compareStringsUI ( a : string , b : string , ignoreCase : boolean ) {
1571- return ignoreCase ? compareStringsCaseInsensitiveUI ( a , b ) : compareStringsCaseSensitiveUI ( a , b ) ;
1557+ export function compareStringsCaseSensitive ( a : string , b : string ) {
1558+ return compareValues ( a , b ) ;
15721559 }
15731560
15741561 /**
@@ -1656,6 +1643,10 @@ namespace ts {
16561643 let uiCI : Comparer < string > | undefined ;
16571644 let uiLocale : string | undefined ;
16581645
1646+ export function getUILocale ( ) {
1647+ return uiLocale ;
1648+ }
1649+
16591650 export function setUILocale ( value : string ) {
16601651 if ( uiLocale !== value ) {
16611652 uiLocale = value ;
@@ -1664,33 +1655,49 @@ namespace ts {
16641655 }
16651656 }
16661657
1658+ /**
1659+ * Compare two strings using the case-insensitive sort behavior of the UI locale.
1660+ *
1661+ * Ordering is not predictable between different host locales, but is best for displaying
1662+ * ordered data for UI presentation. Characters with multiple unicode representations may
1663+ * be considered equal.
1664+ *
1665+ * Case-insensitive comparisons compare strings that differ in only base characters or
1666+ * accents/diacritic marks as unequal.
1667+ */
16671668 export function compareStringsCaseInsensitiveUI ( a : string , b : string ) {
1668- const comparer = uiCS || ( uiCS = createStringComparer ( uiLocale , /*caseInsensitive*/ false ) ) ;
1669+ const comparer = uiCI || ( uiCI = createStringComparer ( uiLocale , /*caseInsensitive*/ true ) ) ;
16691670 return comparer ( a , b ) ;
16701671 }
16711672
1673+ /**
1674+ * Compare two strings in a using the case-sensitive sort behavior of the UI locale.
1675+ *
1676+ * Ordering is not predictable between different host locales, but is best for displaying
1677+ * ordered data for UI presentation. Characters with multiple unicode representations may
1678+ * be considered equal.
1679+ *
1680+ * Case-sensitive comparisons compare strings that differ in base characters, or
1681+ * accents/diacritic marks, or case as unequal.
1682+ */
16721683 export function compareStringsCaseSensitiveUI ( a : string , b : string ) {
1673- const comparer = uiCI || ( uiCI = createStringComparer ( uiLocale , /*caseInsensitive*/ true ) ) ;
1684+ const comparer = uiCS || ( uiCS = createStringComparer ( uiLocale , /*caseInsensitive*/ false ) ) ;
16741685 return comparer ( a , b ) ;
16751686 }
16761687
1677- export function getStringComparerUI ( ignoreCase : boolean ) {
1678- return ignoreCase ? compareStringsCaseInsensitiveUI : compareStringsCaseSensitiveUI ;
1679- }
1680-
1681- export function compareProperties < T > ( a : T , b : T , key : keyof T ) {
1688+ export function compareProperties < T , K extends keyof T > ( a : T , b : T , key : K , comparer : Comparer < T [ K ] > ) {
16821689 return a === b ? Comparison . EqualTo :
16831690 a === undefined ? Comparison . LessThan :
16841691 b === undefined ? Comparison . GreaterThan :
1685- compareValues ( a [ key ] , b [ key ] ) ;
1692+ comparer ( a [ key ] , b [ key ] ) ;
16861693 }
16871694
16881695 function getDiagnosticFileName ( diagnostic : Diagnostic ) : string {
16891696 return diagnostic . file ? diagnostic . file . fileName : undefined ;
16901697 }
16911698
16921699 export function compareDiagnostics ( d1 : Diagnostic , d2 : Diagnostic ) : Comparison {
1693- return compareValues ( getDiagnosticFileName ( d1 ) , getDiagnosticFileName ( d2 ) ) ||
1700+ return compareStringsCaseSensitive ( getDiagnosticFileName ( d1 ) , getDiagnosticFileName ( d2 ) ) ||
16941701 compareValues ( d1 . start , d2 . start ) ||
16951702 compareValues ( d1 . length , d2 . length ) ||
16961703 compareValues ( d1 . code , d2 . code ) ||
@@ -1704,7 +1711,7 @@ namespace ts {
17041711 const string1 = isString ( text1 ) ? text1 : text1 . messageText ;
17051712 const string2 = isString ( text2 ) ? text2 : text2 . messageText ;
17061713
1707- const res = compareValues ( string1 , string2 ) ;
1714+ const res = compareStringsCaseSensitive ( string1 , string2 ) ;
17081715 if ( res ) {
17091716 return res ;
17101717 }
@@ -2067,7 +2074,7 @@ namespace ts {
20672074 const aComponents = getNormalizedPathComponents ( a , currentDirectory ) ;
20682075 const bComponents = getNormalizedPathComponents ( b , currentDirectory ) ;
20692076 const sharedLength = Math . min ( aComponents . length , bComponents . length ) ;
2070- const comparer = getStringComparer ( ignoreCase ) ;
2077+ const comparer = ignoreCase ? compareStringsCaseInsensitive : compareStringsCaseSensitive ;
20712078 for ( let i = 0 ; i < sharedLength ; i ++ ) {
20722079 const result = comparer ( aComponents [ i ] , bComponents [ i ] ) ;
20732080 if ( result !== Comparison . EqualTo ) {
@@ -2091,7 +2098,7 @@ namespace ts {
20912098 }
20922099
20932100 // File-system comparisons should use predictable ordering
2094- const equalityComparer = getStringEqualityComparer ( ignoreCase ) ;
2101+ const equalityComparer = ignoreCase ? equateStringsCaseInsensitive : equateStringsCaseSensitive ;
20952102 for ( let i = 0 ; i < parentComponents . length ; i ++ ) {
20962103 if ( ! equalityComparer ( parentComponents [ i ] , childComponents [ i ] ) ) {
20972104 return false ;
@@ -2338,6 +2345,7 @@ namespace ts {
23382345 path = normalizePath ( path ) ;
23392346 currentDirectory = normalizePath ( currentDirectory ) ;
23402347
2348+ const comparer = useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive ;
23412349 const patterns = getFileMatcherPatterns ( path , excludes , includes , useCaseSensitiveFileNames , currentDirectory ) ;
23422350
23432351 const regexFlag = useCaseSensitiveFileNames ? "" : "i" ;
@@ -2349,7 +2357,6 @@ namespace ts {
23492357 // If there are no "includes", then just put everything in results[0].
23502358 const results : string [ ] [ ] = includeFileRegexes ? includeFileRegexes . map ( ( ) => [ ] ) : [ [ ] ] ;
23512359
2352- const comparer = getStringComparer ( ! useCaseSensitiveFileNames ) ;
23532360 for ( const basePath of patterns . basePaths ) {
23542361 visitDirectory ( basePath , combinePaths ( currentDirectory , basePath ) , depth ) ;
23552362 }
@@ -2414,7 +2421,7 @@ namespace ts {
24142421 }
24152422
24162423 // Sort the offsets array using either the literal or canonical path representations.
2417- includeBasePaths . sort ( getStringComparer ( ! useCaseSensitiveFileNames ) ) ;
2424+ includeBasePaths . sort ( useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive ) ;
24182425
24192426 // Iterate over each include base path and include unique base paths that are not a
24202427 // subpath of an existing base path
0 commit comments