| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							| 
									
										
										
										
											2020-05-19 12:08:49 -07:00
										 |  |  |  * Copyright Google LLC All Rights Reserved. | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Use of this source code is governed by an MIT-style license that can be | 
					
						
							|  |  |  |  * found in the LICENSE file at https://angular.io/license
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import * as chokidar from 'chokidar'; | 
					
						
							|  |  |  | import * as path from 'path'; | 
					
						
							|  |  |  | import * as ts from 'typescript'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-07 12:43:43 -07:00
										 |  |  | import {Diagnostics, exitCodeFromResult, ParsedConfiguration, performCompilation, PerformCompilationResult, readConfiguration} from './perform_compile'; | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  | import * as api from './transformers/api'; | 
					
						
							|  |  |  | import {createCompilerHost} from './transformers/entry_points'; | 
					
						
							| 
									
										
										
										
											2017-09-29 15:02:11 -07:00
										 |  |  | import {createMessageDiagnostic} from './transformers/util'; | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  | function totalCompilationTimeDiagnostic(timeInMillis: number): api.Diagnostic { | 
					
						
							|  |  |  |   let duration: string; | 
					
						
							|  |  |  |   if (timeInMillis > 1000) { | 
					
						
							|  |  |  |     duration = `${(timeInMillis / 1000).toPrecision(2)}s`; | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     duration = `${timeInMillis}ms`; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return { | 
					
						
							|  |  |  |     category: ts.DiagnosticCategory.Message, | 
					
						
							|  |  |  |     messageText: `Total time: ${duration}`, | 
					
						
							|  |  |  |     code: api.DEFAULT_ERROR_CODE, | 
					
						
							|  |  |  |     source: api.SOURCE, | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  | export enum FileChangeEvent { | 
					
						
							|  |  |  |   Change, | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |   CreateDelete, | 
					
						
							|  |  |  |   CreateDeleteDir, | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export interface PerformWatchHost { | 
					
						
							|  |  |  |   reportDiagnostics(diagnostics: Diagnostics): void; | 
					
						
							|  |  |  |   readConfiguration(): ParsedConfiguration; | 
					
						
							|  |  |  |   createCompilerHost(options: api.CompilerOptions): api.CompilerHost; | 
					
						
							| 
									
										
										
										
											2017-10-12 16:09:49 -07:00
										 |  |  |   createEmitCallback(options: api.CompilerOptions): api.TsEmitCallback|undefined; | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |   onFileChange( | 
					
						
							|  |  |  |       options: api.CompilerOptions, listener: (event: FileChangeEvent, fileName: string) => void, | 
					
						
							|  |  |  |       ready: () => void): {close: () => void}; | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |   setTimeout(callback: () => void, ms: number): any; | 
					
						
							|  |  |  |   clearTimeout(timeoutId: any): void; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function createPerformWatchHost( | 
					
						
							|  |  |  |     configFileName: string, reportDiagnostics: (diagnostics: Diagnostics) => void, | 
					
						
							| 
									
										
										
										
											2020-04-07 12:43:43 -07:00
										 |  |  |     existingOptions?: ts.CompilerOptions, | 
					
						
							|  |  |  |     createEmitCallback?: (options: api.CompilerOptions) => | 
					
						
							|  |  |  |         api.TsEmitCallback | undefined): PerformWatchHost { | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |   return { | 
					
						
							|  |  |  |     reportDiagnostics: reportDiagnostics, | 
					
						
							|  |  |  |     createCompilerHost: options => createCompilerHost({options}), | 
					
						
							| 
									
										
										
										
											2017-09-12 15:53:17 -07:00
										 |  |  |     readConfiguration: () => readConfiguration(configFileName, existingOptions), | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |     createEmitCallback: options => createEmitCallback ? createEmitCallback(options) : undefined, | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |     onFileChange: (options, listener, ready: () => void) => { | 
					
						
							|  |  |  |       if (!options.basePath) { | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |         reportDiagnostics([{ | 
					
						
							|  |  |  |           category: ts.DiagnosticCategory.Error, | 
					
						
							|  |  |  |           messageText: 'Invalid configuration option. baseDir not specified', | 
					
						
							|  |  |  |           source: api.SOURCE, | 
					
						
							|  |  |  |           code: api.DEFAULT_ERROR_CODE | 
					
						
							|  |  |  |         }]); | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |         return {close: () => {}}; | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |       const watcher = chokidar.watch(options.basePath, { | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |         // ignore .dotfiles, .js and .map files.
 | 
					
						
							|  |  |  |         // can't ignore other files as we e.g. want to recompile if an `.html` file changes as well.
 | 
					
						
							| 
									
										
										
										
											2019-04-26 15:29:27 +02:00
										 |  |  |         ignored: /((^[\/\\])\..)|(\.js$)|(\.map$)|(\.metadata\.json|node_modules)/, | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |         ignoreInitial: true, | 
					
						
							|  |  |  |         persistent: true, | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       watcher.on('all', (event: string, path: string) => { | 
					
						
							|  |  |  |         switch (event) { | 
					
						
							|  |  |  |           case 'change': | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |             listener(FileChangeEvent.Change, path); | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |             break; | 
					
						
							|  |  |  |           case 'unlink': | 
					
						
							|  |  |  |           case 'add': | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |             listener(FileChangeEvent.CreateDelete, path); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |           case 'unlinkDir': | 
					
						
							|  |  |  |           case 'addDir': | 
					
						
							|  |  |  |             listener(FileChangeEvent.CreateDeleteDir, path); | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |       watcher.on('ready', ready); | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |       return {close: () => watcher.close(), ready}; | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     setTimeout: (ts.sys.clearTimeout && ts.sys.setTimeout) || setTimeout, | 
					
						
							|  |  |  |     clearTimeout: (ts.sys.setTimeout && ts.sys.clearTimeout) || clearTimeout, | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  | interface CacheEntry { | 
					
						
							|  |  |  |   exists?: boolean; | 
					
						
							|  |  |  |   sf?: ts.SourceFile; | 
					
						
							|  |  |  |   content?: string; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-10 16:22:56 +01:00
										 |  |  | interface QueuedCompilationInfo { | 
					
						
							|  |  |  |   timerHandle: any; | 
					
						
							|  |  |  |   modifiedResourceFiles: Set<string>; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  | /** | 
					
						
							|  |  |  |  * The logic in this function is adapted from `tsc.ts` from TypeScript. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2017-09-12 15:53:17 -07:00
										 |  |  | export function performWatchCompilation(host: PerformWatchHost): | 
					
						
							|  |  |  |     {close: () => void, ready: (cb: () => void) => void, firstCompileResult: Diagnostics} { | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |   let cachedProgram: api.Program|undefined;            // Program cached from last compilation
 | 
					
						
							|  |  |  |   let cachedCompilerHost: api.CompilerHost|undefined;  // CompilerHost cached from last compilation
 | 
					
						
							|  |  |  |   let cachedOptions: ParsedConfiguration|undefined;  // CompilerOptions cached from last compilation
 | 
					
						
							| 
									
										
										
										
											2019-06-10 16:22:56 +01:00
										 |  |  |   let timerHandleForRecompilation: QueuedCompilationInfo| | 
					
						
							|  |  |  |       undefined;  // Handle for 0.25s wait timer to trigger recompilation
 | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-15 17:09:55 +08:00
										 |  |  |   const ignoreFilesForWatch = new Set<string>(); | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |   const fileCache = new Map<string, CacheEntry>(); | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const firstCompileResult = doCompilation(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |   // Watch basePath, ignoring .dotfiles
 | 
					
						
							|  |  |  |   let resolveReadyPromise: () => void; | 
					
						
							|  |  |  |   const readyPromise = new Promise(resolve => resolveReadyPromise = resolve); | 
					
						
							|  |  |  |   // Note: ! is ok as options are filled after the first compilation
 | 
					
						
							|  |  |  |   // Note: ! is ok as resolvedReadyPromise is filled by the previous call
 | 
					
						
							|  |  |  |   const fileWatcher = | 
					
						
							| 
									
										
										
										
											2020-04-07 12:43:43 -07:00
										 |  |  |       host.onFileChange(cachedOptions!.options, watchedFileChanged, resolveReadyPromise!); | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return {close, ready: cb => readyPromise.then(cb), firstCompileResult}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |   function cacheEntry(fileName: string): CacheEntry { | 
					
						
							| 
									
										
										
										
											2017-10-26 15:27:21 -07:00
										 |  |  |     fileName = path.normalize(fileName); | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |     let entry = fileCache.get(fileName); | 
					
						
							|  |  |  |     if (!entry) { | 
					
						
							|  |  |  |       entry = {}; | 
					
						
							|  |  |  |       fileCache.set(fileName, entry); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return entry; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |   function close() { | 
					
						
							|  |  |  |     fileWatcher.close(); | 
					
						
							|  |  |  |     if (timerHandleForRecompilation) { | 
					
						
							| 
									
										
										
										
											2019-06-10 16:22:56 +01:00
										 |  |  |       host.clearTimeout(timerHandleForRecompilation.timerHandle); | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |       timerHandleForRecompilation = undefined; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Invoked to perform initial compilation or re-compilation in watch mode
 | 
					
						
							| 
									
										
										
										
											2019-11-03 00:33:31 +01:00
										 |  |  |   function doCompilation(): Diagnostics { | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |     if (!cachedOptions) { | 
					
						
							|  |  |  |       cachedOptions = host.readConfiguration(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (cachedOptions.errors && cachedOptions.errors.length) { | 
					
						
							|  |  |  |       host.reportDiagnostics(cachedOptions.errors); | 
					
						
							| 
									
										
										
										
											2017-09-12 15:53:17 -07:00
										 |  |  |       return cachedOptions.errors; | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |     const startTime = Date.now(); | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |     if (!cachedCompilerHost) { | 
					
						
							|  |  |  |       cachedCompilerHost = host.createCompilerHost(cachedOptions.options); | 
					
						
							|  |  |  |       const originalWriteFileCallback = cachedCompilerHost.writeFile; | 
					
						
							|  |  |  |       cachedCompilerHost.writeFile = function( | 
					
						
							|  |  |  |           fileName: string, data: string, writeByteOrderMark: boolean, | 
					
						
							| 
									
										
										
										
											2017-12-22 09:36:47 -08:00
										 |  |  |           onError?: (message: string) => void, sourceFiles: ReadonlyArray<ts.SourceFile> = []) { | 
					
						
							| 
									
										
										
										
											2018-08-15 17:09:55 +08:00
										 |  |  |         ignoreFilesForWatch.add(path.normalize(fileName)); | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |         return originalWriteFileCallback(fileName, data, writeByteOrderMark, onError, sourceFiles); | 
					
						
							|  |  |  |       }; | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |       const originalFileExists = cachedCompilerHost.fileExists; | 
					
						
							|  |  |  |       cachedCompilerHost.fileExists = function(fileName: string) { | 
					
						
							|  |  |  |         const ce = cacheEntry(fileName); | 
					
						
							|  |  |  |         if (ce.exists == null) { | 
					
						
							|  |  |  |           ce.exists = originalFileExists.call(this, fileName); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-04-07 12:43:43 -07:00
										 |  |  |         return ce.exists!; | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |       }; | 
					
						
							|  |  |  |       const originalGetSourceFile = cachedCompilerHost.getSourceFile; | 
					
						
							|  |  |  |       cachedCompilerHost.getSourceFile = function( | 
					
						
							|  |  |  |           fileName: string, languageVersion: ts.ScriptTarget) { | 
					
						
							|  |  |  |         const ce = cacheEntry(fileName); | 
					
						
							|  |  |  |         if (!ce.sf) { | 
					
						
							|  |  |  |           ce.sf = originalGetSourceFile.call(this, fileName, languageVersion); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-04-07 12:43:43 -07:00
										 |  |  |         return ce.sf!; | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |       }; | 
					
						
							|  |  |  |       const originalReadFile = cachedCompilerHost.readFile; | 
					
						
							|  |  |  |       cachedCompilerHost.readFile = function(fileName: string) { | 
					
						
							|  |  |  |         const ce = cacheEntry(fileName); | 
					
						
							|  |  |  |         if (ce.content == null) { | 
					
						
							|  |  |  |           ce.content = originalReadFile.call(this, fileName); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-04-07 12:43:43 -07:00
										 |  |  |         return ce.content!; | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |       }; | 
					
						
							| 
									
										
										
										
											2019-06-10 16:22:56 +01:00
										 |  |  |       // Provide access to the file paths that triggered this rebuild
 | 
					
						
							| 
									
										
										
										
											2019-11-03 00:33:31 +01:00
										 |  |  |       cachedCompilerHost.getModifiedResourceFiles = function() { | 
					
						
							|  |  |  |         if (timerHandleForRecompilation === undefined) { | 
					
						
							|  |  |  |           return undefined; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return timerHandleForRecompilation.modifiedResourceFiles; | 
					
						
							|  |  |  |       }; | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-08-15 17:09:55 +08:00
										 |  |  |     ignoreFilesForWatch.clear(); | 
					
						
							| 
									
										
										
										
											2017-10-26 15:24:54 -07:00
										 |  |  |     const oldProgram = cachedProgram; | 
					
						
							|  |  |  |     // We clear out the `cachedProgram` here as a
 | 
					
						
							|  |  |  |     // program can only be used as `oldProgram` 1x
 | 
					
						
							|  |  |  |     cachedProgram = undefined; | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |     const compileResult = performCompilation({ | 
					
						
							|  |  |  |       rootNames: cachedOptions.rootNames, | 
					
						
							|  |  |  |       options: cachedOptions.options, | 
					
						
							|  |  |  |       host: cachedCompilerHost, | 
					
						
							| 
									
										
										
										
											2018-01-07 11:28:24 +01:00
										 |  |  |       oldProgram: oldProgram, | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |       emitCallback: host.createEmitCallback(cachedOptions.options) | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (compileResult.diagnostics.length) { | 
					
						
							|  |  |  |       host.reportDiagnostics(compileResult.diagnostics); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |     const endTime = Date.now(); | 
					
						
							|  |  |  |     if (cachedOptions.options.diagnostics) { | 
					
						
							|  |  |  |       const totalTime = (endTime - startTime) / 1000; | 
					
						
							|  |  |  |       host.reportDiagnostics([totalCompilationTimeDiagnostic(endTime - startTime)]); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-12 15:53:17 -07:00
										 |  |  |     const exitCode = exitCodeFromResult(compileResult.diagnostics); | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |     if (exitCode == 0) { | 
					
						
							|  |  |  |       cachedProgram = compileResult.program; | 
					
						
							| 
									
										
										
										
											2017-09-29 15:02:11 -07:00
										 |  |  |       host.reportDiagnostics( | 
					
						
							|  |  |  |           [createMessageDiagnostic('Compilation complete. Watching for file changes.')]); | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2017-09-29 15:02:11 -07:00
										 |  |  |       host.reportDiagnostics( | 
					
						
							|  |  |  |           [createMessageDiagnostic('Compilation failed. Watching for file changes.')]); | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 15:53:17 -07:00
										 |  |  |     return compileResult.diagnostics; | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function resetOptions() { | 
					
						
							|  |  |  |     cachedProgram = undefined; | 
					
						
							|  |  |  |     cachedCompilerHost = undefined; | 
					
						
							|  |  |  |     cachedOptions = undefined; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function watchedFileChanged(event: FileChangeEvent, fileName: string) { | 
					
						
							| 
									
										
										
										
											2019-11-23 21:06:37 +01:00
										 |  |  |     const normalizedPath = path.normalize(fileName); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |     if (cachedOptions && event === FileChangeEvent.Change && | 
					
						
							|  |  |  |         // TODO(chuckj): validate that this is sufficient to skip files that were written.
 | 
					
						
							|  |  |  |         // This assumes that the file path we write is the same file path we will receive in the
 | 
					
						
							|  |  |  |         // change notification.
 | 
					
						
							| 
									
										
										
										
											2019-11-23 21:06:37 +01:00
										 |  |  |         normalizedPath === path.normalize(cachedOptions.project)) { | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |       // If the configuration file changes, forget everything and start the recompilation timer
 | 
					
						
							|  |  |  |       resetOptions(); | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |     } else if ( | 
					
						
							|  |  |  |         event === FileChangeEvent.CreateDelete || event === FileChangeEvent.CreateDeleteDir) { | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |       // If a file was added or removed, reread the configuration
 | 
					
						
							|  |  |  |       // to determine the new list of root files.
 | 
					
						
							|  |  |  |       cachedOptions = undefined; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (event === FileChangeEvent.CreateDeleteDir) { | 
					
						
							|  |  |  |       fileCache.clear(); | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2019-11-23 21:06:37 +01:00
										 |  |  |       fileCache.delete(normalizedPath); | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-23 21:06:37 +01:00
										 |  |  |     if (!ignoreFilesForWatch.has(normalizedPath)) { | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |       // Ignore the file if the file is one that was written by the compiler.
 | 
					
						
							| 
									
										
										
										
											2019-11-23 21:06:37 +01:00
										 |  |  |       startTimerForRecompilation(normalizedPath); | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Upon detecting a file change, wait for 250ms and then perform a recompilation. This gives batch
 | 
					
						
							|  |  |  |   // operations (such as saving all modified files in an editor) a chance to complete before we kick
 | 
					
						
							|  |  |  |   // off a new compilation.
 | 
					
						
							| 
									
										
										
										
											2019-06-10 16:22:56 +01:00
										 |  |  |   function startTimerForRecompilation(changedPath: string) { | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |     if (timerHandleForRecompilation) { | 
					
						
							| 
									
										
										
										
											2019-06-10 16:22:56 +01:00
										 |  |  |       host.clearTimeout(timerHandleForRecompilation.timerHandle); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       timerHandleForRecompilation = { | 
					
						
							|  |  |  |         modifiedResourceFiles: new Set<string>(), | 
					
						
							|  |  |  |         timerHandle: undefined | 
					
						
							|  |  |  |       }; | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-06-10 16:22:56 +01:00
										 |  |  |     timerHandleForRecompilation.timerHandle = host.setTimeout(recompile, 250); | 
					
						
							|  |  |  |     timerHandleForRecompilation.modifiedResourceFiles.add(changedPath); | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function recompile() { | 
					
						
							|  |  |  |     host.reportDiagnostics( | 
					
						
							| 
									
										
										
										
											2017-09-29 15:02:11 -07:00
										 |  |  |         [createMessageDiagnostic('File change detected. Starting incremental compilation.')]); | 
					
						
							| 
									
										
										
										
											2019-11-03 00:33:31 +01:00
										 |  |  |     doCompilation(); | 
					
						
							| 
									
										
										
										
											2019-06-10 16:22:56 +01:00
										 |  |  |     timerHandleForRecompilation = undefined; | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-12-22 09:36:47 -08:00
										 |  |  | } |