@@ -148,6 +148,8 @@ namespace Utils {
148
148
} ) ;
149
149
}
150
150
151
+ export const canonicalizeForHarness = ts . createGetCanonicalFileName ( /*caseSensitive*/ false ) ; // This is done so tests work on windows _and_ linux
152
+
151
153
export function assertInvariants ( node : ts . Node , parent : ts . Node ) : void {
152
154
if ( node ) {
153
155
assert . isFalse ( node . pos < 0 , "node.pos < 0" ) ;
@@ -1446,10 +1448,7 @@ namespace Harness {
1446
1448
} ) ;
1447
1449
}
1448
1450
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 ) {
1453
1452
// The full walker simulates the types that you would get from doing a full
1454
1453
// compile. The pull walker simulates the types you get when you just do
1455
1454
// a type query for a random node (like how the LS would do it). Most of the
@@ -1465,16 +1464,8 @@ namespace Harness {
1465
1464
// These types are equivalent, but depend on what order the compiler observed
1466
1465
// certain parts of the program.
1467
1466
1468
- const program = result . program ;
1469
-
1470
1467
const fullWalker = new TypeWriterWalker ( program , /*fullTypeCheck*/ true ) ;
1471
1468
1472
- const fullResults = ts . createMap < TypeWriterResult [ ] > ( ) ;
1473
-
1474
- for ( const sourceFile of allFiles ) {
1475
- fullResults . set ( sourceFile . unitName , fullWalker . getTypeAndSymbols ( sourceFile . unitName ) ) ;
1476
- }
1477
-
1478
1469
// Produce baselines. The first gives the types for all expressions.
1479
1470
// The second gives symbols for all identifiers.
1480
1471
let typesError : Error , symbolsError : Error ;
@@ -1515,76 +1506,77 @@ namespace Harness {
1515
1506
baselinePath . replace ( / \. t s x ? / , "" ) : baselinePath ;
1516
1507
1517
1508
if ( ! multifile ) {
1518
- const fullBaseLine = generateBaseLine ( fullResults , isSymbolBaseLine ) ;
1509
+ const fullBaseLine = generateBaseLine ( isSymbolBaseLine , skipTypeAndSymbolbaselines ) ;
1519
1510
Harness . Baseline . runBaseline ( outputFileName + fullExtension , ( ) => fullBaseLine , opts ) ;
1520
1511
}
1521
1512
else {
1522
1513
Harness . Baseline . runMultifileBaseline ( outputFileName , fullExtension , ( ) => {
1523
- return iterateBaseLine ( fullResults , isSymbolBaseLine ) ;
1514
+ return iterateBaseLine ( isSymbolBaseLine , skipTypeAndSymbolbaselines ) ;
1524
1515
} , opts ) ;
1525
1516
}
1526
1517
}
1527
1518
1528
- function generateBaseLine ( typeWriterResults : ts . Map < TypeWriterResult [ ] > , isSymbolBaseline : boolean ) : string {
1519
+ function generateBaseLine ( isSymbolBaseline : boolean , skipTypeAndSymbolbaselines ? : boolean ) : string {
1529
1520
let result = "" ;
1530
- const gen = iterateBaseLine ( typeWriterResults , isSymbolBaseline ) ;
1521
+ const gen = iterateBaseLine ( isSymbolBaseline , skipTypeAndSymbolbaselines ) ;
1531
1522
for ( let { done, value} = gen . next ( ) ; ! done ; { done, value } = gen . next ( ) ) {
1532
1523
const [ , content ] = value ;
1533
1524
result += content ;
1534
1525
}
1535
- return result ;
1526
+ /* tslint:disable:no-null-keyword */
1527
+ return result || null ;
1528
+ /* tslint:enable:no-null-keyword */
1536
1529
}
1537
1530
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
+ }
1541
1535
const dupeCase = ts . createMap < number > ( ) ;
1542
1536
1543
1537
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 ( ) ) {
1547
1544
if ( isSymbolBaseline && ! result . symbol ) {
1548
1545
return ;
1549
1546
}
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 ;
1551
1557
const typeOrSymbolString = isSymbolBaseline ? result . symbol : result . type ;
1552
1558
const formattedLine = result . sourceText . replace ( / \r ? \n / g, "" ) + " : " + typeOrSymbolString ;
1553
- if ( ! typeMap [ key ] ) {
1554
- typeMap [ key ] = { } ;
1555
- }
1559
+ typeLines += ">" + formattedLine + "\r\n" ;
1560
+ }
1556
1561
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." ;
1561
1568
}
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" ;
1580
1574
}
1575
+ typeLines += codeLines . slice ( lastIndexWritten + 1 ) . join ( "\r\n" ) ;
1581
1576
}
1582
- else {
1583
- typeLines += "No type information for this code." ;
1584
- }
1577
+ typeLines += "\r\n" ;
1585
1578
}
1586
- yield [ checkDuplicatedFileName ( file . unitName , dupeCase ) , typeLines ] ;
1587
- typeLines = "" ;
1579
+ yield [ checkDuplicatedFileName ( unitName , dupeCase ) , typeLines ] ;
1588
1580
}
1589
1581
}
1590
1582
}
@@ -1726,7 +1718,7 @@ namespace Harness {
1726
1718
}
1727
1719
1728
1720
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 ) ;
1730
1722
}
1731
1723
1732
1724
// 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 {
2070
2062
export function runMultifileBaseline ( relativeFileBase : string , extension : string , generateContent : ( ) => IterableIterator < [ string , string , number ] > | IterableIterator < [ string , string ] > , opts ?: BaselineOptions , referencedExtensions ?: string [ ] ) : void {
2071
2063
const gen = generateContent ( ) ;
2072
2064
const writtenFiles = ts . createMap < true > ( ) ;
2073
- const canonicalize = ts . createGetCanonicalFileName ( /*caseSensitive*/ false ) ; // This is done so tests work on windows _and_ linux
2074
2065
/* tslint:disable-next-line:no-null-keyword */
2075
2066
const errors : Error [ ] = [ ] ;
2076
2067
if ( gen !== null ) {
@@ -2086,8 +2077,7 @@ namespace Harness {
2086
2077
catch ( e ) {
2087
2078
errors . push ( e ) ;
2088
2079
}
2089
- const path = ts . toPath ( relativeFileName , "" , canonicalize ) ;
2090
- writtenFiles . set ( path , true ) ;
2080
+ writtenFiles . set ( relativeFileName , true ) ;
2091
2081
}
2092
2082
}
2093
2083
@@ -2100,8 +2090,7 @@ namespace Harness {
2100
2090
const missing : string [ ] = [ ] ;
2101
2091
for ( const name of existing ) {
2102
2092
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 ) ) {
2105
2094
missing . push ( localCopy ) ;
2106
2095
}
2107
2096
}
@@ -2114,13 +2103,14 @@ namespace Harness {
2114
2103
if ( errors . length || missing . length ) {
2115
2104
let errorMsg = "" ;
2116
2105
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` : " ") } ` ;
2118
2107
}
2119
2108
if ( errors . length && missing . length ) {
2120
2109
errorMsg += "\n" ;
2121
2110
}
2122
2111
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` : "" ) } ` ;
2124
2114
}
2125
2115
throw new Error ( errorMsg ) ;
2126
2116
}
0 commit comments