@@ -5864,6 +5864,9 @@ export function createDiagnosticCollection(): DiagnosticCollection {
58645864 if ( result >= 0 ) {
58655865 return diagnostics [ result ] ;
58665866 }
5867+ if ( ~ result > 0 && diagnosticsEqualityComparer ( diagnostic , diagnostics [ ~ result - 1 ] ) ) {
5868+ return diagnostics [ ~ result - 1 ] ;
5869+ }
58675870 return undefined ;
58685871 }
58695872
@@ -5887,7 +5890,7 @@ export function createDiagnosticCollection(): DiagnosticCollection {
58875890 diagnostics = nonFileDiagnostics ;
58885891 }
58895892
5890- insertSorted ( diagnostics , diagnostic , compareDiagnosticsSkipRelatedInformation ) ;
5893+ insertSorted ( diagnostics , diagnostic , compareDiagnosticsSkipRelatedInformation , diagnosticsEqualityComparer ) ;
58915894 }
58925895
58935896 function getGlobalDiagnostics ( ) : Diagnostic [ ] {
@@ -8545,58 +8548,130 @@ export function compareDiagnosticsSkipRelatedInformation(d1: Diagnostic, d2: Dia
85458548 Comparison . EqualTo ;
85468549}
85478550
8551+ // A diagnostic with more elaboration should be considered *less than* a diagnostic
8552+ // with less elaboration that is otherwise similar.
85488553function compareRelatedInformation ( d1 : Diagnostic , d2 : Diagnostic ) : Comparison {
85498554 if ( ! d1 . relatedInformation && ! d2 . relatedInformation ) {
85508555 return Comparison . EqualTo ;
85518556 }
85528557 if ( d1 . relatedInformation && d2 . relatedInformation ) {
8553- return compareValues ( d1 . relatedInformation . length , d2 . relatedInformation . length ) || forEach ( d1 . relatedInformation , ( d1i , index ) => {
8558+ return compareValues ( d2 . relatedInformation . length , d1 . relatedInformation . length ) || forEach ( d1 . relatedInformation , ( d1i , index ) => {
85548559 const d2i = d2 . relatedInformation ! [ index ] ;
85558560 return compareDiagnostics ( d1i , d2i ) ; // EqualTo is 0, so falsy, and will cause the next item to be compared
85568561 } ) || Comparison . EqualTo ;
85578562 }
85588563 return d1 . relatedInformation ? Comparison . LessThan : Comparison . GreaterThan ;
85598564}
85608565
8561- function compareMessageText ( t1 : string | DiagnosticMessageChain , t2 : string | DiagnosticMessageChain ) : Comparison {
8566+ // An diagnostic message with more elaboration should be considered *less than* a diagnostic message
8567+ // with less elaboration that is otherwise similar.
8568+ function compareMessageText (
8569+ t1 : string | Pick < DiagnosticMessageChain , "messageText" | "next" > ,
8570+ t2 : string | Pick < DiagnosticMessageChain , "messageText" | "next" > ,
8571+ ) : Comparison {
85628572 if ( typeof t1 === "string" && typeof t2 === "string" ) {
85638573 return compareStringsCaseSensitive ( t1 , t2 ) ;
85648574 }
8565- else if ( typeof t1 === "string" ) {
8566- return Comparison . LessThan ;
8575+
8576+ if ( typeof t1 === "string" ) {
8577+ t1 = { messageText : t1 } ;
85678578 }
8568- else if ( typeof t2 === "string" ) {
8569- return Comparison . GreaterThan ;
8579+ if ( typeof t2 === "string" ) {
8580+ t2 = { messageText : t2 } ;
85708581 }
8571- let res = compareStringsCaseSensitive ( t1 . messageText , t2 . messageText ) ;
8582+ const res = compareStringsCaseSensitive ( t1 . messageText , t2 . messageText ) ;
85728583 if ( res ) {
85738584 return res ;
85748585 }
8575- if ( ! t1 . next && ! t2 . next ) {
8586+
8587+ return compareMessageChain ( t1 . next , t2 . next ) ;
8588+ }
8589+
8590+ // First compare by size of the message chain,
8591+ // then compare by content of the message chain.
8592+ function compareMessageChain (
8593+ c1 : DiagnosticMessageChain [ ] | undefined ,
8594+ c2 : DiagnosticMessageChain [ ] | undefined ,
8595+ ) : Comparison {
8596+ if ( c1 === undefined && c2 === undefined ) {
85768597 return Comparison . EqualTo ;
85778598 }
8578- if ( ! t1 . next ) {
8599+ if ( c1 === undefined ) {
8600+ return Comparison . GreaterThan ;
8601+ }
8602+ if ( c2 === undefined ) {
85798603 return Comparison . LessThan ;
85808604 }
8581- if ( ! t2 . next ) {
8605+
8606+ return compareMessageChainSize ( c1 , c2 ) || compareMessageChainContent ( c1 , c2 ) ;
8607+ }
8608+
8609+ function compareMessageChainSize (
8610+ c1 : DiagnosticMessageChain [ ] | undefined ,
8611+ c2 : DiagnosticMessageChain [ ] | undefined ,
8612+ ) : Comparison {
8613+ if ( c1 === undefined && c2 === undefined ) {
8614+ return Comparison . EqualTo ;
8615+ }
8616+ if ( c1 === undefined ) {
85828617 return Comparison . GreaterThan ;
85838618 }
8584- const len = Math . min ( t1 . next . length , t2 . next . length ) ;
8585- for ( let i = 0 ; i < len ; i ++ ) {
8586- res = compareMessageText ( t1 . next [ i ] , t2 . next [ i ] ) ;
8619+ if ( c2 === undefined ) {
8620+ return Comparison . LessThan ;
8621+ }
8622+
8623+ let res = compareValues ( c2 . length , c1 . length ) ;
8624+ if ( res ) {
8625+ return res ;
8626+ }
8627+
8628+ for ( let i = 0 ; i < c2 . length ; i ++ ) {
8629+ res = compareMessageChainSize ( c1 [ i ] . next , c2 [ i ] . next ) ;
85878630 if ( res ) {
85888631 return res ;
85898632 }
85908633 }
8591- if ( t1 . next . length < t2 . next . length ) {
8592- return Comparison . LessThan ;
8593- }
8594- else if ( t1 . next . length > t2 . next . length ) {
8595- return Comparison . GreaterThan ;
8634+
8635+ return Comparison . EqualTo ;
8636+ }
8637+
8638+ // Assumes the two chains have the same shape.
8639+ function compareMessageChainContent (
8640+ c1 : DiagnosticMessageChain [ ] ,
8641+ c2 : DiagnosticMessageChain [ ] ,
8642+ ) : Comparison {
8643+ let res ;
8644+ for ( let i = 0 ; i < c2 . length ; i ++ ) {
8645+ res = compareStringsCaseSensitive ( c1 [ i ] . messageText , c2 [ i ] . messageText ) ;
8646+ if ( res ) {
8647+ return res ;
8648+ }
8649+ if ( c1 [ i ] . next === undefined ) {
8650+ continue ;
8651+ }
8652+ res = compareMessageChainContent ( c1 [ i ] . next ! , c2 [ i ] . next ! ) ;
8653+ if ( res ) {
8654+ return res ;
8655+ }
85968656 }
85978657 return Comparison . EqualTo ;
85988658}
85998659
8660+ /** @internal */
8661+ export function diagnosticsEqualityComparer ( d1 : Diagnostic , d2 : Diagnostic ) : boolean {
8662+ return compareStringsCaseSensitive ( getDiagnosticFilePath ( d1 ) , getDiagnosticFilePath ( d2 ) ) === Comparison . EqualTo &&
8663+ compareValues ( d1 . start , d2 . start ) === Comparison . EqualTo &&
8664+ compareValues ( d1 . length , d2 . length ) === Comparison . EqualTo &&
8665+ compareValues ( d1 . code , d2 . code ) === Comparison . EqualTo &&
8666+ messageTextEqualityComparer ( d1 . messageText , d2 . messageText ) ;
8667+ }
8668+
8669+ function messageTextEqualityComparer ( m1 : string | DiagnosticMessageChain , m2 : string | DiagnosticMessageChain ) : boolean {
8670+ const t1 = typeof m1 === "string" ? m1 : m1 . messageText ;
8671+ const t2 = typeof m2 === "string" ? m2 : m2 . messageText ;
8672+ return compareStringsCaseSensitive ( t1 , t2 ) === Comparison . EqualTo ;
8673+ }
8674+
86008675/** @internal */
86018676export function getLanguageVariant ( scriptKind : ScriptKind ) {
86028677 // .tsx and .jsx files are treated as jsx language variant.
0 commit comments