@@ -104,11 +104,13 @@ namespace ts {
104104 } ;
105105 }
106106
107- export function getPreEmitDiagnostics ( program : Program , sourceFile ?: SourceFile ) : Diagnostic [ ] {
108- let diagnostics = program . getSyntacticDiagnostics ( sourceFile ) . concat ( program . getGlobalDiagnostics ( ) ) . concat ( program . getSemanticDiagnostics ( sourceFile ) ) ;
107+ export function getPreEmitDiagnostics ( program : Program , sourceFile ?: SourceFile , cancellationToken ?: CancellationTokenObject ) : Diagnostic [ ] {
108+ let diagnostics = program . getSyntacticDiagnostics ( sourceFile , cancellationToken ) . concat (
109+ program . getGlobalDiagnostics ( cancellationToken ) ) . concat (
110+ program . getSemanticDiagnostics ( sourceFile , cancellationToken ) ) ;
109111
110112 if ( program . getCompilerOptions ( ) . declaration ) {
111- diagnostics . concat ( program . getDeclarationDiagnostics ( sourceFile ) ) ;
113+ diagnostics . concat ( program . getDeclarationDiagnostics ( sourceFile , cancellationToken ) ) ;
112114 }
113115
114116 return sortAndDeduplicateDiagnostics ( diagnostics ) ;
@@ -230,10 +232,15 @@ namespace ts {
230232 return noDiagnosticsTypeChecker || ( noDiagnosticsTypeChecker = createTypeChecker ( program , /*produceDiagnostics:*/ false ) ) ;
231233 }
232234
233- function emit ( sourceFile ?: SourceFile , writeFileCallback ?: WriteFileCallback ) : EmitResult {
235+ function emit ( sourceFile ?: SourceFile , writeFileCallback ?: WriteFileCallback , cancellationToken ?: CancellationTokenObject ) : EmitResult {
236+ return runWithCancellationToken ( ( ) => emitWorker ( this , sourceFile , writeFileCallback , cancellationToken ) ) ;
237+ }
238+
239+ function emitWorker ( program : Program , sourceFile : SourceFile , writeFileCallback : WriteFileCallback , cancellationToken : CancellationTokenObject ) : EmitResult {
234240 // If the noEmitOnError flag is set, then check if we have any errors so far. If so,
235- // immediately bail out.
236- if ( options . noEmitOnError && getPreEmitDiagnostics ( this ) . length > 0 ) {
241+ // immediately bail out. Note that we pass 'undefined' for 'sourceFile' so that we
242+ // get any preEmit diagnostics, not just the ones
243+ if ( options . noEmitOnError && getPreEmitDiagnostics ( program , /*sourceFile:*/ undefined , cancellationToken ) . length > 0 ) {
237244 return { diagnostics : [ ] , sourceMaps : undefined , emitSkipped : true } ;
238245 }
239246
@@ -262,53 +269,79 @@ namespace ts {
262269 return filesByName . get ( fileName ) ;
263270 }
264271
265- function getDiagnosticsHelper ( sourceFile : SourceFile , getDiagnostics : ( sourceFile : SourceFile ) => Diagnostic [ ] ) : Diagnostic [ ] {
272+ function getDiagnosticsHelper (
273+ sourceFile : SourceFile ,
274+ getDiagnostics : ( sourceFile : SourceFile , cancellationToken : CancellationTokenObject ) => Diagnostic [ ] ,
275+ cancellationToken : CancellationTokenObject ) : Diagnostic [ ] {
266276 if ( sourceFile ) {
267- return getDiagnostics ( sourceFile ) ;
277+ return getDiagnostics ( sourceFile , cancellationToken ) ;
268278 }
269279
270280 let allDiagnostics : Diagnostic [ ] = [ ] ;
271281 forEach ( program . getSourceFiles ( ) , sourceFile => {
272- addRange ( allDiagnostics , getDiagnostics ( sourceFile ) ) ;
282+ if ( cancellationToken ) {
283+ cancellationToken . throwIfCancellationRequested ( ) ;
284+ }
285+ addRange ( allDiagnostics , getDiagnostics ( sourceFile , cancellationToken ) ) ;
273286 } ) ;
274287
275288 return sortAndDeduplicateDiagnostics ( allDiagnostics ) ;
276289 }
277290
278- function getSyntacticDiagnostics ( sourceFile ? : SourceFile ) : Diagnostic [ ] {
279- return getDiagnosticsHelper ( sourceFile , getSyntacticDiagnosticsForFile ) ;
291+ function getSyntacticDiagnostics ( sourceFile : SourceFile , cancellationToken : CancellationTokenObject ) : Diagnostic [ ] {
292+ return getDiagnosticsHelper ( sourceFile , getSyntacticDiagnosticsForFile , cancellationToken ) ;
280293 }
281294
282- function getSemanticDiagnostics ( sourceFile ? : SourceFile ) : Diagnostic [ ] {
283- return getDiagnosticsHelper ( sourceFile , getSemanticDiagnosticsForFile ) ;
295+ function getSemanticDiagnostics ( sourceFile : SourceFile , cancellationToken : CancellationTokenObject ) : Diagnostic [ ] {
296+ return getDiagnosticsHelper ( sourceFile , getSemanticDiagnosticsForFile , cancellationToken ) ;
284297 }
285298
286- function getDeclarationDiagnostics ( sourceFile ? : SourceFile ) : Diagnostic [ ] {
287- return getDiagnosticsHelper ( sourceFile , getDeclarationDiagnosticsForFile ) ;
299+ function getDeclarationDiagnostics ( sourceFile : SourceFile , cancellationToken : CancellationTokenObject ) : Diagnostic [ ] {
300+ return getDiagnosticsHelper ( sourceFile , getDeclarationDiagnosticsForFile , cancellationToken ) ;
288301 }
289302
290- function getSyntacticDiagnosticsForFile ( sourceFile : SourceFile ) : Diagnostic [ ] {
303+ function getSyntacticDiagnosticsForFile ( sourceFile : SourceFile , cancellationToken : CancellationTokenObject ) : Diagnostic [ ] {
291304 return sourceFile . parseDiagnostics ;
292305 }
293306
294- function getSemanticDiagnosticsForFile ( sourceFile : SourceFile ) : Diagnostic [ ] {
295- let typeChecker = getDiagnosticsProducingTypeChecker ( ) ;
307+ function runWithCancellationToken < T > ( func : ( ) => T ) : T {
308+ try {
309+ return func ( ) ;
310+ }
311+ catch ( e ) {
312+ if ( e instanceof OperationCanceledException ) {
313+ // We were canceled while performing the operation. Because our type checker
314+ // might be a bad state, we need to throw it away.
315+ noDiagnosticsTypeChecker = undefined ;
316+ diagnosticsProducingTypeChecker = undefined ;
317+ }
296318
297- Debug . assert ( ! ! sourceFile . bindDiagnostics ) ;
298- let bindDiagnostics = sourceFile . bindDiagnostics ;
299- let checkDiagnostics = typeChecker . getDiagnostics ( sourceFile ) ;
300- let programDiagnostics = diagnostics . getDiagnostics ( sourceFile . fileName ) ;
319+ throw e ;
320+ }
321+ }
322+
323+ function getSemanticDiagnosticsForFile ( sourceFile : SourceFile , cancellationToken : CancellationTokenObject ) : Diagnostic [ ] {
324+ return runWithCancellationToken ( ( ) => {
325+ let typeChecker = getDiagnosticsProducingTypeChecker ( ) ;
326+
327+ Debug . assert ( ! ! sourceFile . bindDiagnostics ) ;
328+ let bindDiagnostics = sourceFile . bindDiagnostics ;
329+ let checkDiagnostics = typeChecker . getDiagnostics ( sourceFile , cancellationToken ) ;
330+ let programDiagnostics = diagnostics . getDiagnostics ( sourceFile . fileName ) ;
301331
302- return bindDiagnostics . concat ( checkDiagnostics ) . concat ( programDiagnostics ) ;
332+ return bindDiagnostics . concat ( checkDiagnostics ) . concat ( programDiagnostics ) ;
333+ } ) ;
303334 }
304335
305- function getDeclarationDiagnosticsForFile ( sourceFile : SourceFile ) : Diagnostic [ ] {
306- if ( ! isDeclarationFile ( sourceFile ) ) {
307- let resolver = getDiagnosticsProducingTypeChecker ( ) . getEmitResolver ( sourceFile ) ;
308- // Don't actually write any files since we're just getting diagnostics.
309- var writeFile : WriteFileCallback = ( ) => { } ;
310- return ts . getDeclarationDiagnostics ( getEmitHost ( writeFile ) , resolver , sourceFile ) ;
311- }
336+ function getDeclarationDiagnosticsForFile ( sourceFile : SourceFile , cancellationToken : CancellationTokenObject ) : Diagnostic [ ] {
337+ return runWithCancellationToken ( ( ) => {
338+ if ( ! isDeclarationFile ( sourceFile ) ) {
339+ let resolver = getDiagnosticsProducingTypeChecker ( ) . getEmitResolver ( sourceFile , cancellationToken ) ;
340+ // Don't actually write any files since we're just getting diagnostics.
341+ var writeFile : WriteFileCallback = ( ) => { } ;
342+ return ts . getDeclarationDiagnostics ( getEmitHost ( writeFile ) , resolver , sourceFile ) ;
343+ }
344+ } ) ;
312345 }
313346
314347 function getCompilerOptionsDiagnostics ( ) : Diagnostic [ ] {
0 commit comments