@@ -855,21 +855,31 @@ namespace Harness {
855855 // Local get canonical file name function, that depends on passed in parameter for useCaseSensitiveFileNames
856856 const getCanonicalFileName = ts . createGetCanonicalFileName ( useCaseSensitiveFileNames ) ;
857857
858- const fileMap : ts . FileMap < ts . SourceFile > = ts . createFileMap < ts . SourceFile > ( ) ;
858+ let realPathMap : ts . FileMap < string > ;
859+ const fileMap : ts . FileMap < ( ) => ts . SourceFile > = ts . createFileMap < ( ) => ts . SourceFile > ( ) ;
859860 for ( const file of inputFiles ) {
860861 if ( file . content !== undefined ) {
861862 const fileName = ts . normalizePath ( file . unitName ) ;
862- const sourceFile = createSourceFileAndAssertInvariants ( fileName , file . content , scriptTarget ) ;
863863 const path = ts . toPath ( file . unitName , currentDirectory , getCanonicalFileName ) ;
864- fileMap . set ( path , sourceFile ) ;
864+ if ( file . fileOptions && file . fileOptions [ "symlink" ] ) {
865+ const link = file . fileOptions [ "symlink" ] ;
866+ const linkPath = ts . toPath ( link , currentDirectory , getCanonicalFileName ) ;
867+ if ( ! realPathMap ) {
868+ realPathMap = ts . createFileMap < string > ( ) ;
869+ }
870+ realPathMap . set ( linkPath , fileName ) ;
871+ fileMap . set ( path , ( ) : ts . SourceFile => { throw new Error ( "Symlinks should always be resolved to a realpath first" ) ; } ) ;
872+ }
873+ const sourceFile = createSourceFileAndAssertInvariants ( fileName , file . content , scriptTarget ) ;
874+ fileMap . set ( path , ts . memoize ( ( ) => sourceFile ) ) ;
865875 }
866876 }
867877
868878 function getSourceFile ( fileName : string , languageVersion : ts . ScriptTarget ) {
869879 fileName = ts . normalizePath ( fileName ) ;
870880 const path = ts . toPath ( fileName , currentDirectory , getCanonicalFileName ) ;
871881 if ( fileMap . contains ( path ) ) {
872- return fileMap . get ( path ) ;
882+ return fileMap . get ( path ) ( ) ;
873883 }
874884 else if ( fileName === fourslashFileName ) {
875885 const tsFn = "tests/cases/fourslash/" + fourslashFileName ;
@@ -898,11 +908,16 @@ namespace Harness {
898908 useCaseSensitiveFileNames : ( ) => useCaseSensitiveFileNames ,
899909 getNewLine : ( ) => newLine ,
900910 fileExists : fileName => {
901- return fileMap . contains ( ts . toPath ( fileName , currentDirectory , getCanonicalFileName ) ) ;
911+ const path = ts . toPath ( fileName , currentDirectory , getCanonicalFileName ) ;
912+ return fileMap . contains ( path ) || ( realPathMap && realPathMap . contains ( path ) ) ;
902913 } ,
903914 readFile : ( fileName : string ) : string => {
904- return fileMap . get ( ts . toPath ( fileName , currentDirectory , getCanonicalFileName ) ) . getText ( ) ;
905- }
915+ return fileMap . get ( ts . toPath ( fileName , currentDirectory , getCanonicalFileName ) ) ( ) . getText ( ) ;
916+ } ,
917+ realpath : realPathMap && ( ( f : string ) => {
918+ const path = ts . toPath ( f , currentDirectory , getCanonicalFileName ) ;
919+ return realPathMap . contains ( path ) ? realPathMap . get ( path ) : path ;
920+ } )
906921 } ;
907922 }
908923
@@ -923,7 +938,8 @@ namespace Harness {
923938 { name : "libFiles" , type : "string" } ,
924939 { name : "noErrorTruncation" , type : "boolean" } ,
925940 { name : "suppressOutputPathCheck" , type : "boolean" } ,
926- { name : "noImplicitReferences" , type : "boolean" }
941+ { name : "noImplicitReferences" , type : "boolean" } ,
942+ { name : "symlink" , type : "string" }
927943 ] ;
928944
929945 let optionsIndex : ts . Map < ts . CommandLineOption > ;
@@ -978,6 +994,7 @@ namespace Harness {
978994 export interface TestFile {
979995 unitName : string ;
980996 content : string ;
997+ fileOptions ?: any ;
981998 }
982999
9831000 export interface CompilationOutput {
@@ -1415,10 +1432,8 @@ namespace Harness {
14151432 // Comment line, check for global/file @options and record them
14161433 optionRegex . lastIndex = 0 ;
14171434 const metaDataName = testMetaData [ 1 ] . toLowerCase ( ) ;
1418- if ( metaDataName === "filename" ) {
1419- currentFileOptions [ testMetaData [ 1 ] ] = testMetaData [ 2 ] ;
1420- }
1421- else {
1435+ currentFileOptions [ testMetaData [ 1 ] ] = testMetaData [ 2 ] ;
1436+ if ( metaDataName !== "filename" ) {
14221437 continue ;
14231438 }
14241439
0 commit comments