@@ -34,9 +34,20 @@ namespace ts {
34
34
clearCache ( ) : void ;
35
35
}
36
36
37
+ type Canonicalized = string & { __canonicalized : void } ;
38
+
37
39
interface MutableFileSystemEntries {
38
40
readonly files : string [ ] ;
39
41
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 >
40
51
}
41
52
42
53
export function createCachedDirectoryStructureHost ( host : DirectoryStructureHost , currentDirectory : string , useCaseSensitiveFileNames : boolean ) : CachedDirectoryStructureHost | undefined {
@@ -45,7 +56,7 @@ namespace ts {
45
56
}
46
57
47
58
const cachedReadDirectoryResult = new Map < string , MutableFileSystemEntries | false > ( ) ;
48
- const getCanonicalFileName = createGetCanonicalFileName ( useCaseSensitiveFileNames ) ;
59
+ const getCanonicalFileName = createGetCanonicalFileName ( useCaseSensitiveFileNames ) as ( ( name : string ) => Canonicalized ) ;
49
60
return {
50
61
useCaseSensitiveFileNames,
51
62
fileExists,
@@ -70,7 +81,17 @@ namespace ts {
70
81
}
71
82
72
83
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 ;
74
95
}
75
96
76
97
function getBaseNameOfFileName ( fileName : string ) {
@@ -120,23 +141,10 @@ namespace ts {
120
141
}
121
142
}
122
143
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 ;
140
148
}
141
149
142
150
function writeFile ( fileName : string , data : string , writeByteOrderMark ?: boolean ) : void {
@@ -151,7 +159,7 @@ namespace ts {
151
159
function fileExists ( fileName : string ) : boolean {
152
160
const path = toPath ( fileName ) ;
153
161
const result = getCachedFileSystemEntriesForBaseDir ( path ) ;
154
- return result && hasEntry ( result . files , getBaseNameOfFileName ( fileName ) ) ||
162
+ return result && hasEntry ( result . sortedAndCanonicalizedFiles , getCanonicalFileName ( getBaseNameOfFileName ( fileName ) ) ) ||
155
163
host . fileExists ( fileName ) ;
156
164
}
157
165
@@ -163,9 +171,14 @@ namespace ts {
163
171
function createDirectory ( dirPath : string ) {
164
172
const path = toPath ( dirPath ) ;
165
173
const result = getCachedFileSystemEntriesForBaseDir ( path ) ;
166
- const baseFileName = getBaseNameOfFileName ( dirPath ) ;
167
174
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
+ }
169
182
}
170
183
host . createDirectory ! ( dirPath ) ;
171
184
}
@@ -242,7 +255,7 @@ namespace ts {
242
255
fileExists : host . fileExists ( fileOrDirectoryPath ) ,
243
256
directoryExists : host . directoryExists ( fileOrDirectoryPath )
244
257
} ;
245
- if ( fsQueryResult . directoryExists || hasEntry ( parentResult . directories , baseName ) ) {
258
+ if ( fsQueryResult . directoryExists || hasEntry ( parentResult . sortedAndCanonicalizedDirectories , getCanonicalFileName ( baseName ) ) ) {
246
259
// Folder added or removed, clear the cache instead of updating the folder and its structure
247
260
clearCache ( ) ;
248
261
}
@@ -265,8 +278,24 @@ namespace ts {
265
278
}
266
279
}
267
280
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
+ }
270
299
}
271
300
272
301
function clearCache ( ) {
0 commit comments