@@ -148,6 +148,8 @@ namespace Utils {
148148 } ) ;
149149 }
150150
151+ export const canonicalizeForHarness = ts . createGetCanonicalFileName ( /*caseSensitive*/ false ) ; // This is done so tests work on windows _and_ linux
152+
151153 export function assertInvariants ( node : ts . Node , parent : ts . Node ) : void {
152154 if ( node ) {
153155 assert . isFalse ( node . pos < 0 , "node.pos < 0" ) ;
@@ -1446,10 +1448,7 @@ namespace Harness {
14461448 } ) ;
14471449 }
14481450
1449- export function doTypeAndSymbolBaseline ( baselinePath : string , result : CompilerResult , allFiles : { unitName : string , content : string } [ ] , opts ?: Harness . Baseline . BaselineOptions , multifile ?: boolean ) {
1450- if ( result . errors . length !== 0 ) {
1451- return ;
1452- }
1451+ export function doTypeAndSymbolBaseline ( baselinePath : string , program : ts . Program , allFiles : { unitName : string , content : string } [ ] , opts ?: Harness . Baseline . BaselineOptions , multifile ?: boolean , skipTypeAndSymbolbaselines ?: boolean ) {
14531452 // The full walker simulates the types that you would get from doing a full
14541453 // compile. The pull walker simulates the types you get when you just do
14551454 // a type query for a random node (like how the LS would do it). Most of the
@@ -1465,16 +1464,8 @@ namespace Harness {
14651464 // These types are equivalent, but depend on what order the compiler observed
14661465 // certain parts of the program.
14671466
1468- const program = result . program ;
1469-
14701467 const fullWalker = new TypeWriterWalker ( program , /*fullTypeCheck*/ true ) ;
14711468
1472- const fullResults = ts . createMap < TypeWriterResult [ ] > ( ) ;
1473-
1474- for ( const sourceFile of allFiles ) {
1475- fullResults . set ( sourceFile . unitName , fullWalker . getTypeAndSymbols ( sourceFile . unitName ) ) ;
1476- }
1477-
14781469 // Produce baselines. The first gives the types for all expressions.
14791470 // The second gives symbols for all identifiers.
14801471 let typesError : Error , symbolsError : Error ;
@@ -1515,76 +1506,77 @@ namespace Harness {
15151506 baselinePath . replace ( / \. t s x ? / , "" ) : baselinePath ;
15161507
15171508 if ( ! multifile ) {
1518- const fullBaseLine = generateBaseLine ( fullResults , isSymbolBaseLine ) ;
1509+ const fullBaseLine = generateBaseLine ( isSymbolBaseLine , skipTypeAndSymbolbaselines ) ;
15191510 Harness . Baseline . runBaseline ( outputFileName + fullExtension , ( ) => fullBaseLine , opts ) ;
15201511 }
15211512 else {
15221513 Harness . Baseline . runMultifileBaseline ( outputFileName , fullExtension , ( ) => {
1523- return iterateBaseLine ( fullResults , isSymbolBaseLine ) ;
1514+ return iterateBaseLine ( isSymbolBaseLine , skipTypeAndSymbolbaselines ) ;
15241515 } , opts ) ;
15251516 }
15261517 }
15271518
1528- function generateBaseLine ( typeWriterResults : ts . Map < TypeWriterResult [ ] > , isSymbolBaseline : boolean ) : string {
1519+ function generateBaseLine ( isSymbolBaseline : boolean , skipTypeAndSymbolbaselines ? : boolean ) : string {
15291520 let result = "" ;
1530- const gen = iterateBaseLine ( typeWriterResults , isSymbolBaseline ) ;
1521+ const gen = iterateBaseLine ( isSymbolBaseline , skipTypeAndSymbolbaselines ) ;
15311522 for ( let { done, value} = gen . next ( ) ; ! done ; { done, value } = gen . next ( ) ) {
15321523 const [ , content ] = value ;
15331524 result += content ;
15341525 }
1535- return result ;
1526+ /* tslint:disable:no-null-keyword */
1527+ return result || null ;
1528+ /* tslint:enable:no-null-keyword */
15361529 }
15371530
1538- function * iterateBaseLine ( typeWriterResults : ts . Map < TypeWriterResult [ ] > , isSymbolBaseline : boolean ) : IterableIterator < [ string , string ] > {
1539- let typeLines = "" ;
1540- const typeMap : { [ fileName : string ] : { [ lineNum : number ] : string [ ] ; } } = { } ;
1531+ function * iterateBaseLine ( isSymbolBaseline : boolean , skipTypeAndSymbolbaselines ?: boolean ) : IterableIterator < [ string , string ] > {
1532+ if ( skipTypeAndSymbolbaselines ) {
1533+ return ;
1534+ }
15411535 const dupeCase = ts . createMap < number > ( ) ;
15421536
15431537 for ( const file of allFiles ) {
1544- const codeLines = file . content . split ( "\n" ) ;
1545- const key = file . unitName ;
1546- typeWriterResults . get ( file . unitName ) . forEach ( result => {
1538+ const { unitName } = file ;
1539+ let typeLines = "=== " + unitName + " ===\r\n" ;
1540+ const codeLines = ts . flatMap ( file . content . split ( / \r ? \n / g) , e => e . split ( / [ \r \u2028 \u2029 ] / g) ) ;
1541+ const gen : IterableIterator < TypeWriterResult > = isSymbolBaseline ? fullWalker . getSymbols ( unitName ) : fullWalker . getTypes ( unitName ) ;
1542+ let lastIndexWritten : number | undefined ;
1543+ for ( let { done, value : result } = gen . next ( ) ; ! done ; { done, value : result } = gen . next ( ) ) {
15471544 if ( isSymbolBaseline && ! result . symbol ) {
15481545 return ;
15491546 }
1550-
1547+ if ( lastIndexWritten === undefined ) {
1548+ typeLines += codeLines . slice ( 0 , result . line + 1 ) . join ( "\r\n" ) + "\r\n" ;
1549+ }
1550+ else if ( result . line !== lastIndexWritten ) {
1551+ if ( ! ( ( lastIndexWritten + 1 < codeLines . length ) && ( codeLines [ lastIndexWritten + 1 ] . match ( / ^ \s * [ { | } ] \s * $ / ) || codeLines [ lastIndexWritten + 1 ] . trim ( ) === "" ) ) ) {
1552+ typeLines += "\r\n" ;
1553+ }
1554+ typeLines += codeLines . slice ( lastIndexWritten + 1 , result . line + 1 ) . join ( "\r\n" ) + "\r\n" ;
1555+ }
1556+ lastIndexWritten = result . line ;
15511557 const typeOrSymbolString = isSymbolBaseline ? result . symbol : result . type ;
15521558 const formattedLine = result . sourceText . replace ( / \r ? \n / g, "" ) + " : " + typeOrSymbolString ;
1553- if ( ! typeMap [ key ] ) {
1554- typeMap [ key ] = { } ;
1555- }
1559+ typeLines += ">" + formattedLine + "\r\n" ;
1560+ }
15561561
1557- let typeInfo = [ formattedLine ] ;
1558- const existingTypeInfo = typeMap [ key ] [ result . line ] ;
1559- if ( existingTypeInfo ) {
1560- typeInfo = existingTypeInfo . concat ( typeInfo ) ;
1562+ // Preserve legacy behavior
1563+ if ( lastIndexWritten === undefined ) {
1564+ for ( let i = 0 ; i < codeLines . length ; i ++ ) {
1565+ const currentCodeLine = codeLines [ i ] ;
1566+ typeLines += currentCodeLine + "\r\n" ;
1567+ typeLines += "No type information for this code." ;
15611568 }
1562- typeMap [ key ] [ result . line ] = typeInfo ;
1563- } ) ;
1564-
1565- typeLines += "=== " + file . unitName + " ===\r\n" ;
1566- for ( let i = 0 ; i < codeLines . length ; i ++ ) {
1567- const currentCodeLine = codeLines [ i ] ;
1568- typeLines += currentCodeLine + "\r\n" ;
1569- if ( typeMap [ key ] ) {
1570- const typeInfo = typeMap [ key ] [ i ] ;
1571- if ( typeInfo ) {
1572- typeInfo . forEach ( ty => {
1573- typeLines += ">" + ty + "\r\n" ;
1574- } ) ;
1575- if ( i + 1 < codeLines . length && ( codeLines [ i + 1 ] . match ( / ^ \s * [ { | } ] \s * $ / ) || codeLines [ i + 1 ] . trim ( ) === "" ) ) {
1576- }
1577- else {
1578- typeLines += "\r\n" ;
1579- }
1569+ }
1570+ else {
1571+ if ( lastIndexWritten + 1 < codeLines . length ) {
1572+ if ( ! ( ( lastIndexWritten + 1 < codeLines . length ) && ( codeLines [ lastIndexWritten + 1 ] . match ( / ^ \s * [ { | } ] \s * $ / ) || codeLines [ lastIndexWritten + 1 ] . trim ( ) === "" ) ) ) {
1573+ typeLines += "\r\n" ;
15801574 }
1575+ typeLines += codeLines . slice ( lastIndexWritten + 1 ) . join ( "\r\n" ) ;
15811576 }
1582- else {
1583- typeLines += "No type information for this code." ;
1584- }
1577+ typeLines += "\r\n" ;
15851578 }
1586- yield [ checkDuplicatedFileName ( file . unitName , dupeCase ) , typeLines ] ;
1587- typeLines = "" ;
1579+ yield [ checkDuplicatedFileName ( unitName , dupeCase ) , typeLines ] ;
15881580 }
15891581 }
15901582 }
@@ -1726,7 +1718,7 @@ namespace Harness {
17261718 }
17271719
17281720 function sanitizeTestFilePath ( name : string ) {
1729- return ts . normalizeSlashes ( name . replace ( / [ \^ < > : " | ? * % ] / g, "_" ) ) . replace ( / \. \. \/ / g, "__dotdot/" ) . toLowerCase ( ) ;
1721+ return ts . toPath ( ts . normalizeSlashes ( name . replace ( / [ \^ < > : " | ? * % ] / g, "_" ) ) . replace ( / \. \. \/ / g, "__dotdot/" ) , "" , Utils . canonicalizeForHarness ) ;
17301722 }
17311723
17321724 // This does not need to exist strictly speaking, but many tests will need to be updated if it's removed
@@ -2070,7 +2062,6 @@ namespace Harness {
20702062 export function runMultifileBaseline ( relativeFileBase : string , extension : string , generateContent : ( ) => IterableIterator < [ string , string , number ] > | IterableIterator < [ string , string ] > , opts ?: BaselineOptions , referencedExtensions ?: string [ ] ) : void {
20712063 const gen = generateContent ( ) ;
20722064 const writtenFiles = ts . createMap < true > ( ) ;
2073- const canonicalize = ts . createGetCanonicalFileName ( /*caseSensitive*/ false ) ; // This is done so tests work on windows _and_ linux
20742065 /* tslint:disable-next-line:no-null-keyword */
20752066 const errors : Error [ ] = [ ] ;
20762067 if ( gen !== null ) {
@@ -2086,8 +2077,7 @@ namespace Harness {
20862077 catch ( e ) {
20872078 errors . push ( e ) ;
20882079 }
2089- const path = ts . toPath ( relativeFileName , "" , canonicalize ) ;
2090- writtenFiles . set ( path , true ) ;
2080+ writtenFiles . set ( relativeFileName , true ) ;
20912081 }
20922082 }
20932083
@@ -2100,8 +2090,7 @@ namespace Harness {
21002090 const missing : string [ ] = [ ] ;
21012091 for ( const name of existing ) {
21022092 const localCopy = name . substring ( referenceDir . length - relativeFileBase . length ) ;
2103- const path = ts . toPath ( localCopy , "" , canonicalize ) ;
2104- if ( ! writtenFiles . has ( path ) ) {
2093+ if ( ! writtenFiles . has ( localCopy ) ) {
21052094 missing . push ( localCopy ) ;
21062095 }
21072096 }
@@ -2114,13 +2103,14 @@ namespace Harness {
21142103 if ( errors . length || missing . length ) {
21152104 let errorMsg = "" ;
21162105 if ( errors . length ) {
2117- errorMsg += `The baseline for ${ relativeFileBase } has changed:${ "\n " + errors . map ( e => e . message ) . join ( "\n " ) } ` ;
2106+ errorMsg += `The baseline for ${ relativeFileBase } in ${ errors . length } files has changed:${ "\n " + errors . slice ( 0 , 5 ) . map ( e => e . message ) . join ( "\n " ) + ( errors . length > 5 ? "\n" + ` and ${ errors . length - 5 } more` : " ") } ` ;
21182107 }
21192108 if ( errors . length && missing . length ) {
21202109 errorMsg += "\n" ;
21212110 }
21222111 if ( missing . length ) {
2123- errorMsg += `Baseline missing files:${ "\n " + missing . join ( "\n " ) + "\n" } Written:${ "\n " + ts . arrayFrom ( writtenFiles . keys ( ) ) . join ( "\n " ) } ` ;
2112+ const writtenFilesArray = ts . arrayFrom ( writtenFiles . keys ( ) ) ;
2113+ errorMsg += `Baseline missing ${ missing . length } files:${ "\n " + missing . slice ( 0 , 5 ) . join ( "\n " ) + ( missing . length > 5 ? "\n" + ` and ${ missing . length - 5 } more` : "" ) + "\n" } Written ${ writtenFiles . size } files:${ "\n " + writtenFilesArray . slice ( 0 , 5 ) . join ( "\n " ) + ( writtenFilesArray . length > 5 ? "\n" + ` and ${ writtenFilesArray . length - 5 } more` : "" ) } ` ;
21242114 }
21252115 throw new Error ( errorMsg ) ;
21262116 }
0 commit comments