@@ -7706,6 +7706,186 @@ namespace ts.projectSystem {
7706
7706
}
7707
7707
}
7708
7708
} ) ;
7709
+
7710
+ describe ( "module resolution when symlinked folder contents change and resolve modules" , ( ) => {
7711
+ const projectRootPath = "/users/username/projects/myproject" ;
7712
+ const packages = `${ projectRootPath } /javascript/packages` ;
7713
+ const recognizersDateTime = `${ packages } /recognizers-date-time` ;
7714
+ const recognizersText = `${ packages } /recognizers-text` ;
7715
+ const recognizersTextDist = `${ recognizersText } /dist` ;
7716
+ const moduleName = "@microsoft/recognizers-text" ;
7717
+ const moduleNameInFile = `"${ moduleName } "` ;
7718
+ const recognizersDateTimeSrcFile : File = {
7719
+ path : `${ recognizersDateTime } /src/datetime/baseDate.ts` ,
7720
+ content : `import {C} from ${ moduleNameInFile } ;
7721
+ new C();`
7722
+ } ;
7723
+ const recognizerDateTimeTsconfigPath = `${ recognizersDateTime } /tsconfig.json` ;
7724
+ const recognizerDateTimeTsconfigWithoutPathMapping : File = {
7725
+ path : recognizerDateTimeTsconfigPath ,
7726
+ content : JSON . stringify ( {
7727
+ include : [ "src" ]
7728
+ } )
7729
+ } ;
7730
+ const recognizerDateTimeTsconfigWithPathMapping : File = {
7731
+ path : recognizerDateTimeTsconfigPath ,
7732
+ content : JSON . stringify ( {
7733
+ compilerOptions : {
7734
+ rootDir : "src" ,
7735
+ baseUrl : "./" ,
7736
+ paths : {
7737
+ "@microsoft/*" : [ "../*" ]
7738
+ }
7739
+ } ,
7740
+ include : [ "src" ]
7741
+ } )
7742
+ } ;
7743
+ const nodeModulesRecorgnizersText : SymLink = {
7744
+ path : `${ recognizersDateTime } /node_modules/@microsoft/recognizers-text` ,
7745
+ symLink : recognizersText
7746
+ } ;
7747
+ const recognizerTextSrcFile : File = {
7748
+ path : `${ recognizersText } /src/recognizers-text.ts` ,
7749
+ content : `export class C { method () { return 10; } }`
7750
+ } ;
7751
+ const recongnizerTextDistTypingFile : File = {
7752
+ path : `${ recognizersTextDist } /types/recognizers-text.d.ts` ,
7753
+ content : `export class C { method(): number; }`
7754
+ } ;
7755
+ const recongnizerTextPackageJson : File = {
7756
+ path : `${ recognizersText } /package.json` ,
7757
+ content : JSON . stringify ( {
7758
+ typings : "dist/types/recognizers-text.d.ts"
7759
+ } )
7760
+ } ;
7761
+ const filesInProjectWithUnresolvedModule = [ recognizerDateTimeTsconfigPath , libFile . path , recognizersDateTimeSrcFile . path ] ;
7762
+ const filesInProjectWithResolvedModule = [ ...filesInProjectWithUnresolvedModule , recongnizerTextDistTypingFile . path ] ;
7763
+
7764
+ function verifyErrors ( session : TestSession , semanticErrors : protocol . Diagnostic [ ] ) {
7765
+ session . clearMessages ( ) ;
7766
+ const expectedSequenceId = session . getNextSeq ( ) ;
7767
+ session . executeCommandSeq < protocol . GeterrRequest > ( {
7768
+ command : server . CommandNames . Geterr ,
7769
+ arguments : {
7770
+ delay : 0 ,
7771
+ files : [ recognizersDateTimeSrcFile . path ] ,
7772
+ }
7773
+ } ) ;
7774
+
7775
+ const host = session . host ;
7776
+ host . checkTimeoutQueueLengthAndRun ( 1 ) ;
7777
+
7778
+ checkErrorMessage ( session , "syntaxDiag" , { file : recognizersDateTimeSrcFile . path , diagnostics : [ ] } ) ;
7779
+ session . clearMessages ( ) ;
7780
+
7781
+ host . runQueuedImmediateCallbacks ( 1 ) ;
7782
+
7783
+ checkErrorMessage ( session , "semanticDiag" , { file : recognizersDateTimeSrcFile . path , diagnostics : semanticErrors } ) ;
7784
+ session . clearMessages ( ) ;
7785
+
7786
+ host . runQueuedImmediateCallbacks ( 1 ) ;
7787
+
7788
+ checkErrorMessage ( session , "suggestionDiag" , {
7789
+ file : recognizersDateTimeSrcFile . path ,
7790
+ diagnostics : [ ] ,
7791
+ } ) ;
7792
+ checkCompleteEvent ( session , 2 , expectedSequenceId ) ;
7793
+ }
7794
+
7795
+ function createSingleWatchMap ( paths : string [ ] ) {
7796
+ return arrayToMap ( paths , p => p , ( ) => 1 ) ;
7797
+ }
7798
+
7799
+ function verifyWatchedFilesAndDirectories ( host : TestServerHost , files : string [ ] , directories : string [ ] ) {
7800
+ checkWatchedFilesDetailed ( host , createSingleWatchMap ( files . filter ( f => f !== recognizersDateTimeSrcFile . path ) ) ) ;
7801
+ checkWatchedDirectories ( host , emptyArray , /*recursive*/ false ) ;
7802
+ checkWatchedDirectoriesDetailed ( host , createSingleWatchMap ( directories ) , /*recursive*/ true ) ;
7803
+ }
7804
+
7805
+ function createSessionAndOpenFile ( host : TestServerHost ) {
7806
+ const session = createSession ( host , { canUseEvents : true } ) ;
7807
+ session . executeCommandSeq < protocol . OpenRequest > ( {
7808
+ command : protocol . CommandTypes . Open ,
7809
+ arguments : {
7810
+ file : recognizersDateTimeSrcFile . path ,
7811
+ projectRootPath
7812
+ }
7813
+ } ) ;
7814
+ return session ;
7815
+ }
7816
+
7817
+ function verifyModuleResolution ( withPathMapping : boolean ) {
7818
+ describe ( withPathMapping ? "when tsconfig file contains path mapping" : "when tsconfig does not contain path mapping" , ( ) => {
7819
+ const filesWithSources = [ libFile , recognizersDateTimeSrcFile , withPathMapping ? recognizerDateTimeTsconfigWithPathMapping : recognizerDateTimeTsconfigWithoutPathMapping , recognizerTextSrcFile , recongnizerTextPackageJson ] ;
7820
+ const filesWithNodeModulesSetup = [ ...filesWithSources , nodeModulesRecorgnizersText ] ;
7821
+ const filesAfterCompilation = [ ...filesWithNodeModulesSetup , recongnizerTextDistTypingFile ] ;
7822
+
7823
+ const watchedDirectoriesWithResolvedModule = [ `${ recognizersDateTime } /src` , withPathMapping ? packages : recognizersDateTime , ...getTypeRootsFromLocation ( recognizersDateTime ) ] ;
7824
+ const watchedDirectoriesWithUnresolvedModule = [ recognizersDateTime , ...watchedDirectoriesWithResolvedModule , ...getNodeModuleDirectories ( packages ) ] ;
7825
+
7826
+ function verifyProjectWithResolvedModule ( session : TestSession ) {
7827
+ const projectService = session . getProjectService ( ) ;
7828
+ const project = projectService . configuredProjects . get ( recognizerDateTimeTsconfigPath ) ;
7829
+ checkProjectActualFiles ( project , filesInProjectWithResolvedModule ) ;
7830
+ verifyWatchedFilesAndDirectories ( session . host , filesInProjectWithResolvedModule , watchedDirectoriesWithResolvedModule ) ;
7831
+ verifyErrors ( session , [ ] ) ;
7832
+ }
7833
+
7834
+ function verifyProjectWithUnresolvedModule ( session : TestSession ) {
7835
+ const projectService = session . getProjectService ( ) ;
7836
+ const project = projectService . configuredProjects . get ( recognizerDateTimeTsconfigPath ) ;
7837
+ checkProjectActualFiles ( project , filesInProjectWithUnresolvedModule ) ;
7838
+ verifyWatchedFilesAndDirectories ( session . host , filesInProjectWithUnresolvedModule , watchedDirectoriesWithUnresolvedModule ) ;
7839
+ const startOffset = recognizersDateTimeSrcFile . content . indexOf ( '"' ) + 1 ;
7840
+ verifyErrors ( session , [
7841
+ createDiagnostic ( { line : 1 , offset : startOffset } , { line : 1 , offset : startOffset + moduleNameInFile . length } , Diagnostics . Cannot_find_module_0 , [ moduleName ] )
7842
+ ] ) ;
7843
+ }
7844
+
7845
+ it ( "when project compiles from sources" , ( ) => {
7846
+ const host = createServerHost ( filesWithSources ) ;
7847
+ const session = createSessionAndOpenFile ( host ) ;
7848
+ verifyProjectWithUnresolvedModule ( session ) ;
7849
+
7850
+ host . reloadFS ( filesAfterCompilation ) ;
7851
+ host . runQueuedTimeoutCallbacks ( ) ;
7852
+
7853
+ verifyProjectWithResolvedModule ( session ) ;
7854
+ } ) ;
7855
+
7856
+ it ( "when project has node_modules setup but doesnt have modules in typings folder and then recompiles" , ( ) => {
7857
+ const host = createServerHost ( filesWithNodeModulesSetup ) ;
7858
+ const session = createSessionAndOpenFile ( host ) ;
7859
+ verifyProjectWithUnresolvedModule ( session ) ;
7860
+
7861
+ host . reloadFS ( filesAfterCompilation ) ;
7862
+ host . runQueuedTimeoutCallbacks ( ) ;
7863
+
7864
+ verifyProjectWithResolvedModule ( session ) ;
7865
+ } ) ;
7866
+
7867
+ it ( "when project recompiles after deleting generated folders" , ( ) => {
7868
+ const host = createServerHost ( filesAfterCompilation ) ;
7869
+ const session = createSessionAndOpenFile ( host ) ;
7870
+
7871
+ verifyProjectWithResolvedModule ( session ) ;
7872
+
7873
+ host . removeFolder ( recognizersTextDist , /*recursive*/ true ) ;
7874
+ host . runQueuedTimeoutCallbacks ( ) ;
7875
+
7876
+ verifyProjectWithUnresolvedModule ( session ) ;
7877
+
7878
+ host . ensureFileOrFolder ( recongnizerTextDistTypingFile ) ;
7879
+ host . runQueuedTimeoutCallbacks ( ) ;
7880
+
7881
+ verifyProjectWithResolvedModule ( session ) ;
7882
+ } ) ;
7883
+ } ) ;
7884
+ }
7885
+
7886
+ verifyModuleResolution ( /*withPathMapping*/ false ) ;
7887
+ verifyModuleResolution ( /*withPathMapping*/ true ) ;
7888
+ } ) ;
7709
7889
} ) ;
7710
7890
7711
7891
describe ( "tsserverProjectSystem forceConsistentCasingInFileNames" , ( ) => {
0 commit comments