@@ -130,6 +130,10 @@ module ts {
130130 reportStatisticalValue ( name , ( time / 1000 ) . toFixed ( 2 ) + "s" ) ;
131131 }
132132
133+ function isJSONSupported ( ) {
134+ return typeof JSON === "object" && typeof JSON . parse === "function" ;
135+ }
136+
133137 function findConfigFile ( ) : string {
134138 var searchPath = normalizePath ( sys . getCurrentDirectory ( ) ) ;
135139 var filename = "tsconfig.json" ;
@@ -151,17 +155,17 @@ module ts {
151155 var commandLine = parseCommandLine ( args ) ;
152156 var configFilename : string ; // Configuration file name (if any)
153157 var configFileWatcher : FileWatcher ; // Configuration file watcher
154- var cachedSourceFiles : Map < SourceFile > ; // Cached SourceFile objects
158+ var cachedProgram : Program ; // Program cached from last compilation
155159 var rootFilenames : string [ ] ; // Root filenames for compilation
156160 var compilerOptions : CompilerOptions ; // Compiler options for compilation
157161 var compilerHost : CompilerHost ; // Compiler host
158162 var hostGetSourceFile : typeof compilerHost . getSourceFile ; // getSourceFile method from default host
159163 var timerHandle : number ; // Handle for 0.25s wait timer
160164
161165 if ( commandLine . options . locale ) {
162- if ( typeof JSON === "undefined" ) {
166+ if ( ! isJSONSupported ( ) ) {
163167 reportDiagnostic ( createCompilerDiagnostic ( Diagnostics . The_current_host_does_not_support_the_0_option , "--locale" ) ) ;
164- return sys . exit ( 1 ) ;
168+ return sys . exit ( EmitReturnStatus . CompilerOptionsErrors ) ;
165169 }
166170 validateLocaleAndSetLanguage ( commandLine . options . locale , commandLine . errors ) ;
167171 }
@@ -185,13 +189,17 @@ module ts {
185189 }
186190
187191 if ( commandLine . options . project ) {
192+ if ( ! isJSONSupported ( ) ) {
193+ reportDiagnostic ( createCompilerDiagnostic ( Diagnostics . The_current_host_does_not_support_the_0_option , "--project" ) ) ;
194+ return sys . exit ( EmitReturnStatus . CompilerOptionsErrors ) ;
195+ }
188196 configFilename = normalizePath ( combinePaths ( commandLine . options . project , "tsconfig.json" ) ) ;
189197 if ( commandLine . filenames . length !== 0 ) {
190198 reportDiagnostic ( createCompilerDiagnostic ( Diagnostics . Option_project_cannot_be_mixed_with_source_files_on_a_command_line ) ) ;
191199 return sys . exit ( EmitReturnStatus . CompilerOptionsErrors ) ;
192200 }
193201 }
194- else if ( commandLine . filenames . length === 0 ) {
202+ else if ( commandLine . filenames . length === 0 && isJSONSupported ( ) ) {
195203 configFilename = findConfigFile ( ) ;
196204 }
197205
@@ -216,7 +224,7 @@ module ts {
216224 // Invoked to perform initial compilation or re-compilation in watch mode
217225 function performCompilation ( ) {
218226
219- if ( ! cachedSourceFiles ) {
227+ if ( ! cachedProgram ) {
220228 if ( configFilename ) {
221229 var configObject = readConfigFile ( configFilename ) ;
222230 if ( ! configObject ) {
@@ -246,80 +254,53 @@ module ts {
246254 return sys . exit ( compileResult . exitStatus ) ;
247255 }
248256
249- updateSourceFileCache ( compileResult . program . getSourceFiles ( ) ) ;
257+ setCachedProgram ( compileResult . program ) ;
250258 reportDiagnostic ( createCompilerDiagnostic ( Diagnostics . Compilation_complete_Watching_for_file_changes ) ) ;
251259 }
252260
253261 function getSourceFile ( filename : string , languageVersion : ScriptTarget , onError ?: ( message : string ) => void ) {
254262 // Return existing SourceFile object if one is available
255- if ( cachedSourceFiles ) {
256- var canonicalName = compilerHost . getCanonicalFileName ( filename ) ;
257- if ( hasProperty ( cachedSourceFiles , canonicalName ) ) {
258- return cachedSourceFiles [ canonicalName ] ;
263+ if ( cachedProgram ) {
264+ var sourceFile = cachedProgram . getSourceFile ( filename ) ;
265+ // A modified source file has no watcher and should not be reused
266+ if ( sourceFile && sourceFile . fileWatcher ) {
267+ return sourceFile ;
259268 }
260269 }
261270 // Use default host function
262271 var sourceFile = hostGetSourceFile ( filename , languageVersion , onError ) ;
263- // Cache the source file in -watch mode
264272 if ( sourceFile && commandLine . options . watch ) {
265- cacheSourceFile ( sourceFile ) ;
273+ // Attach a file watcher
274+ sourceFile . fileWatcher = sys . watchFile ( sourceFile . filename , ( ) => sourceFileChanged ( sourceFile ) ) ;
266275 }
267276 return sourceFile ;
268277 }
269278
270- // Cache the given source file and watch for changes
271- function cacheSourceFile ( sourceFile : SourceFile ) {
272- cachedSourceFiles = cachedSourceFiles || { } ;
273- cachedSourceFiles [ compilerHost . getCanonicalFileName ( sourceFile . filename ) ] = sourceFile ;
274- sourceFile . fileWatcher = sys . watchFile ( sourceFile . filename , sourceFileChanged ) ;
275- }
276-
277- // Remove the given source file from the cache
278- function forgetSourceFile ( sourceFile : SourceFile ) {
279- if ( sourceFile . fileWatcher ) {
280- sourceFile . fileWatcher . close ( ) ;
281- sourceFile . fileWatcher = undefined ;
282- delete cachedSourceFiles [ sourceFile . filename ] ;
283- }
284- }
285-
286- // Update the cache to contain only source files in the given list
287- function updateSourceFileCache ( keepSourceFiles : SourceFile [ ] ) {
288- for ( var filename in cachedSourceFiles ) {
289- var sourceFile = cachedSourceFiles [ filename ] ;
290- if ( sourceFile ) {
291- if ( ! contains ( keepSourceFiles , sourceFile ) ) {
292- forgetSourceFile ( sourceFile ) ;
279+ // Change cached program to the given program
280+ function setCachedProgram ( program : Program ) {
281+ if ( cachedProgram ) {
282+ var newSourceFiles = program ? program . getSourceFiles ( ) : undefined ;
283+ forEach ( cachedProgram . getSourceFiles ( ) , sourceFile => {
284+ if ( ! ( newSourceFiles && contains ( newSourceFiles , sourceFile ) ) ) {
285+ if ( sourceFile . fileWatcher ) {
286+ sourceFile . fileWatcher . close ( ) ;
287+ sourceFile . fileWatcher = undefined ;
288+ }
293289 }
294- }
290+ } ) ;
295291 }
292+ cachedProgram = program ;
296293 }
297294
298- // Remove all source files from the cache
299- function clearSourceFileCache ( ) {
300- if ( cachedSourceFiles ) {
301- for ( var filename in cachedSourceFiles ) {
302- var sourceFile = cachedSourceFiles [ filename ] ;
303- if ( sourceFile ) {
304- forgetSourceFile ( sourceFile ) ;
305- }
306- }
307- }
308- cachedSourceFiles = undefined ;
309- }
310-
311- // If a source file changes, remove that file from the cache and start the recompilation timer
312- function sourceFileChanged ( filename : string ) {
313- var sourceFile = cachedSourceFiles [ filename ] ;
314- if ( sourceFile ) {
315- forgetSourceFile ( sourceFile ) ;
316- startTimer ( ) ;
317- }
295+ // If a source file changes, mark it as unwatched and start the recompilation timer
296+ function sourceFileChanged ( sourceFile : SourceFile ) {
297+ sourceFile . fileWatcher = undefined ;
298+ startTimer ( ) ;
318299 }
319300
320- // If the configuration file changes, clear the cache and start the recompilation timer
301+ // If the configuration file changes, forget cached program and start the recompilation timer
321302 function configFileChanged ( ) {
322- clearSourceFileCache ( ) ;
303+ setCachedProgram ( undefined ) ;
323304 startTimer ( ) ;
324305 }
325306
0 commit comments