@@ -4,15 +4,21 @@ import path from 'path';
4
4
import ts from 'typescript' ;
5
5
import { Extra } from '../parser-options' ;
6
6
import { WatchCompilerHostOfConfigFile } from '../WatchCompilerHostOfConfigFile' ;
7
- import { getTsconfigPath , DEFAULT_COMPILER_OPTIONS } from './shared' ;
7
+ import {
8
+ canonicalDirname ,
9
+ CanonicalPath ,
10
+ getTsconfigPath ,
11
+ DEFAULT_COMPILER_OPTIONS ,
12
+ getCanonicalFileName ,
13
+ } from './shared' ;
8
14
9
15
const log = debug ( 'typescript-eslint:typescript-estree:createWatchProgram' ) ;
10
16
11
17
/**
12
18
* Maps tsconfig paths to their corresponding file contents and resulting watches
13
19
*/
14
20
const knownWatchProgramMap = new Map <
15
- string ,
21
+ CanonicalPath ,
16
22
ts . WatchOfConfigFile < ts . SemanticDiagnosticsBuilderProgram >
17
23
> ( ) ;
18
24
@@ -21,25 +27,25 @@ const knownWatchProgramMap = new Map<
21
27
* There may be more than one per file/folder if a file/folder is shared between projects
22
28
*/
23
29
const fileWatchCallbackTrackingMap = new Map <
24
- string ,
30
+ CanonicalPath ,
25
31
Set < ts . FileWatcherCallback >
26
32
> ( ) ;
27
33
const folderWatchCallbackTrackingMap = new Map <
28
- string ,
34
+ CanonicalPath ,
29
35
Set < ts . FileWatcherCallback >
30
36
> ( ) ;
31
37
32
38
/**
33
39
* Stores the list of known files for each program
34
40
*/
35
- const programFileListCache = new Map < string , Set < string > > ( ) ;
41
+ const programFileListCache = new Map < CanonicalPath , Set < CanonicalPath > > ( ) ;
36
42
37
43
/**
38
44
* Caches the last modified time of the tsconfig files
39
45
*/
40
- const tsconfigLsatModifiedTimestampCache = new Map < string , number > ( ) ;
46
+ const tsconfigLastModifiedTimestampCache = new Map < CanonicalPath , number > ( ) ;
41
47
42
- const parsedFilesSeen = new Set < string > ( ) ;
48
+ const parsedFilesSeen = new Set < CanonicalPath > ( ) ;
43
49
44
50
/**
45
51
* Clear all of the parser caches.
@@ -51,7 +57,7 @@ function clearCaches(): void {
51
57
folderWatchCallbackTrackingMap . clear ( ) ;
52
58
parsedFilesSeen . clear ( ) ;
53
59
programFileListCache . clear ( ) ;
54
- tsconfigLsatModifiedTimestampCache . clear ( ) ;
60
+ tsconfigLastModifiedTimestampCache . clear ( ) ;
55
61
}
56
62
57
63
function saveWatchCallback (
@@ -61,7 +67,7 @@ function saveWatchCallback(
61
67
fileName : string ,
62
68
callback : ts . FileWatcherCallback ,
63
69
) : ts . FileWatcher => {
64
- const normalizedFileName = path . normalize ( fileName ) ;
70
+ const normalizedFileName = getCanonicalFileName ( path . normalize ( fileName ) ) ;
65
71
const watchers = ( ( ) : Set < ts . FileWatcherCallback > => {
66
72
let watchers = trackingMap . get ( normalizedFileName ) ;
67
73
if ( ! watchers ) {
@@ -83,9 +89,9 @@ function saveWatchCallback(
83
89
/**
84
90
* Holds information about the file currently being linted
85
91
*/
86
- const currentLintOperationState = {
92
+ const currentLintOperationState : { code : string ; filePath : CanonicalPath } = {
87
93
code : '' ,
88
- filePath : '' ,
94
+ filePath : '' as CanonicalPath ,
89
95
} ;
90
96
91
97
/**
@@ -101,16 +107,17 @@ function diagnosticReporter(diagnostic: ts.Diagnostic): void {
101
107
/**
102
108
* Calculate project environments using options provided by consumer and paths from config
103
109
* @param code The code being linted
104
- * @param filePath The path of the file being parsed
110
+ * @param filePathIn The path of the file being parsed
105
111
* @param extra.tsconfigRootDir The root directory for relative tsconfig paths
106
112
* @param extra.projects Provided tsconfig paths
107
113
* @returns The programs corresponding to the supplied tsconfig paths
108
114
*/
109
115
function getProgramsForProjects (
110
116
code : string ,
111
- filePath : string ,
117
+ filePathIn : string ,
112
118
extra : Extra ,
113
119
) : ts . Program [ ] {
120
+ const filePath = getCanonicalFileName ( filePathIn ) ;
114
121
const results = [ ] ;
115
122
116
123
// preserve reference to code and file being linted
@@ -145,7 +152,9 @@ function getProgramsForProjects(
145
152
let updatedProgram : ts . Program | null = null ;
146
153
if ( ! fileList ) {
147
154
updatedProgram = existingWatch . getProgram ( ) . getProgram ( ) ;
148
- fileList = new Set ( updatedProgram . getRootFileNames ( ) ) ;
155
+ fileList = new Set (
156
+ updatedProgram . getRootFileNames ( ) . map ( f => getCanonicalFileName ( f ) ) ,
157
+ ) ;
149
158
programFileListCache . set ( tsconfigPath , fileList ) ;
150
159
}
151
160
@@ -215,7 +224,8 @@ function createWatchProgram(
215
224
216
225
// ensure readFile reads the code being linted instead of the copy on disk
217
226
const oldReadFile = watchCompilerHost . readFile ;
218
- watchCompilerHost . readFile = ( filePath , encoding ) : string | undefined => {
227
+ watchCompilerHost . readFile = ( filePathIn , encoding ) : string | undefined => {
228
+ const filePath = getCanonicalFileName ( filePathIn ) ;
219
229
parsedFilesSeen . add ( filePath ) ;
220
230
return path . normalize ( filePath ) ===
221
231
path . normalize ( currentLintOperationState . filePath )
@@ -297,14 +307,14 @@ function createWatchProgram(
297
307
return ts . createWatchProgram ( watchCompilerHost ) ;
298
308
}
299
309
300
- function hasTSConfigChanged ( tsconfigPath : string ) : boolean {
310
+ function hasTSConfigChanged ( tsconfigPath : CanonicalPath ) : boolean {
301
311
const stat = fs . statSync ( tsconfigPath ) ;
302
312
const lastModifiedAt = stat . mtimeMs ;
303
- const cachedLastModifiedAt = tsconfigLsatModifiedTimestampCache . get (
313
+ const cachedLastModifiedAt = tsconfigLastModifiedTimestampCache . get (
304
314
tsconfigPath ,
305
315
) ;
306
316
307
- tsconfigLsatModifiedTimestampCache . set ( tsconfigPath , lastModifiedAt ) ;
317
+ tsconfigLastModifiedTimestampCache . set ( tsconfigPath , lastModifiedAt ) ;
308
318
309
319
if ( cachedLastModifiedAt === undefined ) {
310
320
return false ;
@@ -315,8 +325,8 @@ function hasTSConfigChanged(tsconfigPath: string): boolean {
315
325
316
326
function maybeInvalidateProgram (
317
327
existingWatch : ts . WatchOfConfigFile < ts . SemanticDiagnosticsBuilderProgram > ,
318
- filePath : string ,
319
- tsconfigPath : string ,
328
+ filePath : CanonicalPath ,
329
+ tsconfigPath : CanonicalPath ,
320
330
) : ts . Program | null {
321
331
/*
322
332
* By calling watchProgram.getProgram(), it will trigger a resync of the program based on
@@ -355,21 +365,22 @@ function maybeInvalidateProgram(
355
365
log ( 'File was not found in program - triggering folder update. %s' , filePath ) ;
356
366
357
367
// Find the correct directory callback by climbing the folder tree
358
- let current : string | null = null ;
359
- let next : string | null = path . dirname ( filePath ) ;
368
+ const currentDir = canonicalDirname ( filePath ) ;
369
+ let current : CanonicalPath | null = null ;
370
+ let next = currentDir ;
360
371
let hasCallback = false ;
361
372
while ( current !== next ) {
362
373
current = next ;
363
374
const folderWatchCallbacks = folderWatchCallbackTrackingMap . get ( current ) ;
364
375
if ( folderWatchCallbacks ) {
365
376
folderWatchCallbacks . forEach ( cb =>
366
- cb ( current ! , ts . FileWatcherEventKind . Changed ) ,
377
+ cb ( currentDir , ts . FileWatcherEventKind . Changed ) ,
367
378
) ;
368
379
hasCallback = true ;
369
380
break ;
370
381
}
371
382
372
- next = path . dirname ( current ) ;
383
+ next = canonicalDirname ( current ) ;
373
384
}
374
385
if ( ! hasCallback ) {
375
386
/*
@@ -410,7 +421,9 @@ function maybeInvalidateProgram(
410
421
return null ;
411
422
}
412
423
413
- const fileWatchCallbacks = fileWatchCallbackTrackingMap . get ( deletedFile ) ;
424
+ const fileWatchCallbacks = fileWatchCallbackTrackingMap . get (
425
+ getCanonicalFileName ( deletedFile ) ,
426
+ ) ;
414
427
if ( ! fileWatchCallbacks ) {
415
428
// shouldn't happen, but just in case
416
429
log ( 'Could not find watch callbacks for root file. %s' , deletedFile ) ;
0 commit comments