@@ -34,9 +34,20 @@ namespace ts {
3434 clearCache ( ) : void ;
3535 }
3636
37+ type Canonicalized = string & { __canonicalized : void } ;
38+
3739 interface MutableFileSystemEntries {
3840 readonly files : string [ ] ;
3941 readonly directories : string [ ] ;
42+ sortedAndCanonicalizedFiles ?: SortedArray < Canonicalized >
43+ sortedAndCanonicalizedDirectories ?: SortedArray < Canonicalized >
44+ }
45+
46+ interface SortedAndCanonicalizedMutableFileSystemEntries {
47+ readonly files : string [ ] ;
48+ readonly directories : string [ ] ;
49+ readonly sortedAndCanonicalizedFiles : SortedArray < Canonicalized >
50+ readonly sortedAndCanonicalizedDirectories : SortedArray < Canonicalized >
4051 }
4152
4253 export function createCachedDirectoryStructureHost ( host : DirectoryStructureHost , currentDirectory : string , useCaseSensitiveFileNames : boolean ) : CachedDirectoryStructureHost | undefined {
@@ -45,7 +56,7 @@ namespace ts {
4556 }
4657
4758 const cachedReadDirectoryResult = new Map < string , MutableFileSystemEntries | false > ( ) ;
48- const getCanonicalFileName = createGetCanonicalFileName ( useCaseSensitiveFileNames ) ;
59+ const getCanonicalFileName = createGetCanonicalFileName ( useCaseSensitiveFileNames ) as ( ( name : string ) => Canonicalized ) ;
4960 return {
5061 useCaseSensitiveFileNames,
5162 fileExists,
@@ -70,7 +81,17 @@ namespace ts {
7081 }
7182
7283 function getCachedFileSystemEntriesForBaseDir ( path : Path ) {
73- return getCachedFileSystemEntries ( getDirectoryPath ( path ) ) ;
84+ const entries = getCachedFileSystemEntries ( getDirectoryPath ( path ) ) ;
85+ if ( ! entries ) {
86+ return entries ;
87+ }
88+
89+ // If we're looking for the base directory, we're definitely going to search the entries
90+ if ( ! entries . sortedAndCanonicalizedFiles ) {
91+ entries . sortedAndCanonicalizedFiles = entries . files . map ( getCanonicalFileName ) . sort ( ) as SortedArray < Canonicalized > ;
92+ entries . sortedAndCanonicalizedDirectories = entries . directories . map ( getCanonicalFileName ) . sort ( ) as SortedArray < Canonicalized > ;
93+ }
94+ return entries as SortedAndCanonicalizedMutableFileSystemEntries ;
7495 }
7596
7697 function getBaseNameOfFileName ( fileName : string ) {
@@ -120,23 +141,10 @@ namespace ts {
120141 }
121142 }
122143
123- function fileNameEqual ( name1 : string , name2 : string ) {
124- return getCanonicalFileName ( name1 ) === getCanonicalFileName ( name2 ) ;
125- }
126-
127- function hasEntry ( entries : readonly string [ ] , name : string ) {
128- return some ( entries , file => fileNameEqual ( file , name ) ) ;
129- }
130-
131- function updateFileSystemEntry ( entries : string [ ] , baseName : string , isValid : boolean ) {
132- if ( hasEntry ( entries , baseName ) ) {
133- if ( ! isValid ) {
134- return filterMutate ( entries , entry => ! fileNameEqual ( entry , baseName ) ) ;
135- }
136- }
137- else if ( isValid ) {
138- return entries . push ( baseName ) ;
139- }
144+ function hasEntry ( entries : SortedReadonlyArray < Canonicalized > , name : Canonicalized ) {
145+ // Case-sensitive comparison since already canonicalized
146+ const index = binarySearch ( entries , name , identity , compareStringsCaseSensitive ) ;
147+ return index >= 0 ;
140148 }
141149
142150 function writeFile ( fileName : string , data : string , writeByteOrderMark ?: boolean ) : void {
@@ -151,7 +159,7 @@ namespace ts {
151159 function fileExists ( fileName : string ) : boolean {
152160 const path = toPath ( fileName ) ;
153161 const result = getCachedFileSystemEntriesForBaseDir ( path ) ;
154- return result && hasEntry ( result . files , getBaseNameOfFileName ( fileName ) ) ||
162+ return result && hasEntry ( result . sortedAndCanonicalizedFiles , getCanonicalFileName ( getBaseNameOfFileName ( fileName ) ) ) ||
155163 host . fileExists ( fileName ) ;
156164 }
157165
@@ -163,9 +171,14 @@ namespace ts {
163171 function createDirectory ( dirPath : string ) {
164172 const path = toPath ( dirPath ) ;
165173 const result = getCachedFileSystemEntriesForBaseDir ( path ) ;
166- const baseFileName = getBaseNameOfFileName ( dirPath ) ;
167174 if ( result ) {
168- updateFileSystemEntry ( result . directories , baseFileName , /*isValid*/ true ) ;
175+ const baseName = getBaseNameOfFileName ( dirPath ) ;
176+ const canonicalizedBaseName = getCanonicalFileName ( baseName ) ;
177+ const canonicalizedDirectories = result . sortedAndCanonicalizedDirectories ;
178+ // Case-sensitive comparison since already canonicalized
179+ if ( insertSorted ( canonicalizedDirectories , canonicalizedBaseName , compareStringsCaseSensitive ) ) {
180+ result . directories . push ( baseName ) ;
181+ }
169182 }
170183 host . createDirectory ! ( dirPath ) ;
171184 }
@@ -242,7 +255,7 @@ namespace ts {
242255 fileExists : host . fileExists ( fileOrDirectoryPath ) ,
243256 directoryExists : host . directoryExists ( fileOrDirectoryPath )
244257 } ;
245- if ( fsQueryResult . directoryExists || hasEntry ( parentResult . directories , baseName ) ) {
258+ if ( fsQueryResult . directoryExists || hasEntry ( parentResult . sortedAndCanonicalizedDirectories , getCanonicalFileName ( baseName ) ) ) {
246259 // Folder added or removed, clear the cache instead of updating the folder and its structure
247260 clearCache ( ) ;
248261 }
@@ -265,8 +278,24 @@ namespace ts {
265278 }
266279 }
267280
268- function updateFilesOfFileSystemEntry ( parentResult : MutableFileSystemEntries , baseName : string , fileExists : boolean ) {
269- updateFileSystemEntry ( parentResult . files , baseName , fileExists ) ;
281+ function updateFilesOfFileSystemEntry ( parentResult : SortedAndCanonicalizedMutableFileSystemEntries , baseName : string , fileExists : boolean ) : void {
282+ const canonicalizedFiles = parentResult . sortedAndCanonicalizedFiles ;
283+ const canonicalizedBaseName = getCanonicalFileName ( baseName ) ;
284+ if ( fileExists ) {
285+ // Case-sensitive comparison since already canonicalized
286+ if ( insertSorted ( canonicalizedFiles , canonicalizedBaseName , compareStringsCaseSensitive ) ) {
287+ parentResult . files . push ( baseName ) ;
288+ }
289+ }
290+ else {
291+ // Case-sensitive comparison since already canonicalized
292+ const sortedIndex = binarySearch ( canonicalizedFiles , canonicalizedBaseName , identity , compareStringsCaseSensitive ) ;
293+ if ( sortedIndex >= 0 ) {
294+ canonicalizedFiles . splice ( sortedIndex , 1 ) ;
295+ const unsortedIndex = parentResult . files . findIndex ( entry => getCanonicalFileName ( entry ) === canonicalizedBaseName ) ;
296+ parentResult . files . splice ( unsortedIndex , 1 ) ;
297+ }
298+ }
270299 }
271300
272301 function clearCache ( ) {
0 commit comments