@@ -104,14 +104,14 @@ namespace ts {
104
104
} ;
105
105
}
106
106
107
- export function getPreEmitDiagnostics ( program : Program , sourceFile ?: SourceFile ) : Diagnostic [ ] {
108
- let diagnostics = program . getOptionsDiagnostics ( ) . concat (
109
- program . getSyntacticDiagnostics ( sourceFile ) ,
110
- program . getGlobalDiagnostics ( ) ,
111
- program . getSemanticDiagnostics ( sourceFile ) ) ;
107
+ export function getPreEmitDiagnostics ( program : Program , sourceFile ?: SourceFile , cancellationToken ?: CancellationToken ) : Diagnostic [ ] {
108
+ let diagnostics = program . getOptionsDiagnostics ( cancellationToken ) . concat (
109
+ program . getSyntacticDiagnostics ( sourceFile , cancellationToken ) ,
110
+ program . getGlobalDiagnostics ( cancellationToken ) ,
111
+ program . getSemanticDiagnostics ( sourceFile , cancellationToken ) ) ;
112
112
113
113
if ( program . getCompilerOptions ( ) . declaration ) {
114
- diagnostics . concat ( program . getDeclarationDiagnostics ( sourceFile ) ) ;
114
+ diagnostics . concat ( program . getDeclarationDiagnostics ( sourceFile , cancellationToken ) ) ;
115
115
}
116
116
117
117
return sortAndDeduplicateDiagnostics ( diagnostics ) ;
@@ -233,10 +233,15 @@ namespace ts {
233
233
return noDiagnosticsTypeChecker || ( noDiagnosticsTypeChecker = createTypeChecker ( program , /*produceDiagnostics:*/ false ) ) ;
234
234
}
235
235
236
- function emit ( sourceFile ?: SourceFile , writeFileCallback ?: WriteFileCallback ) : EmitResult {
236
+ function emit ( sourceFile ?: SourceFile , writeFileCallback ?: WriteFileCallback , cancellationToken ?: CancellationToken ) : EmitResult {
237
+ return runWithCancellationToken ( ( ) => emitWorker ( this , sourceFile , writeFileCallback , cancellationToken ) ) ;
238
+ }
239
+
240
+ function emitWorker ( program : Program , sourceFile : SourceFile , writeFileCallback : WriteFileCallback , cancellationToken : CancellationToken ) : EmitResult {
237
241
// If the noEmitOnError flag is set, then check if we have any errors so far. If so,
238
- // immediately bail out.
239
- if ( options . noEmitOnError && getPreEmitDiagnostics ( this ) . length > 0 ) {
242
+ // immediately bail out. Note that we pass 'undefined' for 'sourceFile' so that we
243
+ // get any preEmit diagnostics, not just the ones
244
+ if ( options . noEmitOnError && getPreEmitDiagnostics ( program , /*sourceFile:*/ undefined , cancellationToken ) . length > 0 ) {
240
245
return { diagnostics : [ ] , sourceMaps : undefined , emitSkipped : true } ;
241
246
}
242
247
@@ -265,53 +270,86 @@ namespace ts {
265
270
return filesByName . get ( fileName ) ;
266
271
}
267
272
268
- function getDiagnosticsHelper ( sourceFile : SourceFile , getDiagnostics : ( sourceFile : SourceFile ) => Diagnostic [ ] ) : Diagnostic [ ] {
273
+ function getDiagnosticsHelper (
274
+ sourceFile : SourceFile ,
275
+ getDiagnostics : ( sourceFile : SourceFile , cancellationToken : CancellationToken ) => Diagnostic [ ] ,
276
+ cancellationToken : CancellationToken ) : Diagnostic [ ] {
269
277
if ( sourceFile ) {
270
- return getDiagnostics ( sourceFile ) ;
278
+ return getDiagnostics ( sourceFile , cancellationToken ) ;
271
279
}
272
280
273
281
let allDiagnostics : Diagnostic [ ] = [ ] ;
274
282
forEach ( program . getSourceFiles ( ) , sourceFile => {
275
- addRange ( allDiagnostics , getDiagnostics ( sourceFile ) ) ;
283
+ if ( cancellationToken ) {
284
+ cancellationToken . throwIfCancellationRequested ( ) ;
285
+ }
286
+ addRange ( allDiagnostics , getDiagnostics ( sourceFile , cancellationToken ) ) ;
276
287
} ) ;
277
288
278
289
return sortAndDeduplicateDiagnostics ( allDiagnostics ) ;
279
290
}
280
291
281
- function getSyntacticDiagnostics ( sourceFile ? : SourceFile ) : Diagnostic [ ] {
282
- return getDiagnosticsHelper ( sourceFile , getSyntacticDiagnosticsForFile ) ;
292
+ function getSyntacticDiagnostics ( sourceFile : SourceFile , cancellationToken : CancellationToken ) : Diagnostic [ ] {
293
+ return getDiagnosticsHelper ( sourceFile , getSyntacticDiagnosticsForFile , cancellationToken ) ;
283
294
}
284
295
285
- function getSemanticDiagnostics ( sourceFile ? : SourceFile ) : Diagnostic [ ] {
286
- return getDiagnosticsHelper ( sourceFile , getSemanticDiagnosticsForFile ) ;
296
+ function getSemanticDiagnostics ( sourceFile : SourceFile , cancellationToken : CancellationToken ) : Diagnostic [ ] {
297
+ return getDiagnosticsHelper ( sourceFile , getSemanticDiagnosticsForFile , cancellationToken ) ;
287
298
}
288
299
289
- function getDeclarationDiagnostics ( sourceFile ? : SourceFile ) : Diagnostic [ ] {
290
- return getDiagnosticsHelper ( sourceFile , getDeclarationDiagnosticsForFile ) ;
300
+ function getDeclarationDiagnostics ( sourceFile : SourceFile , cancellationToken : CancellationToken ) : Diagnostic [ ] {
301
+ return getDiagnosticsHelper ( sourceFile , getDeclarationDiagnosticsForFile , cancellationToken ) ;
291
302
}
292
303
293
- function getSyntacticDiagnosticsForFile ( sourceFile : SourceFile ) : Diagnostic [ ] {
304
+ function getSyntacticDiagnosticsForFile ( sourceFile : SourceFile , cancellationToken : CancellationToken ) : Diagnostic [ ] {
294
305
return sourceFile . parseDiagnostics ;
295
306
}
296
307
297
- function getSemanticDiagnosticsForFile ( sourceFile : SourceFile ) : Diagnostic [ ] {
298
- let typeChecker = getDiagnosticsProducingTypeChecker ( ) ;
308
+ function runWithCancellationToken < T > ( func : ( ) => T ) : T {
309
+ try {
310
+ return func ( ) ;
311
+ }
312
+ catch ( e ) {
313
+ if ( e instanceof OperationCanceledException ) {
314
+ // We were canceled while performing the operation. Because our type checker
315
+ // might be a bad state, we need to throw it away.
316
+ //
317
+ // Note: we are overly agressive here. We do not actually *have* to throw away
318
+ // the "noDiagnosticsTypeChecker". However, for simplicity, i'd like to keep
319
+ // the lifetimes of these two TypeCheckers the same. Also, we generally only
320
+ // cancel when the user has made a change anyways. And, in that case, we (the
321
+ // program instance) will get thrown away anyways. So trying to keep one of
322
+ // these type checkers alive doesn't serve much purpose.
323
+ noDiagnosticsTypeChecker = undefined ;
324
+ diagnosticsProducingTypeChecker = undefined ;
325
+ }
299
326
300
- Debug . assert ( ! ! sourceFile . bindDiagnostics ) ;
301
- let bindDiagnostics = sourceFile . bindDiagnostics ;
302
- let checkDiagnostics = typeChecker . getDiagnostics ( sourceFile ) ;
303
- let programDiagnostics = diagnostics . getDiagnostics ( sourceFile . fileName ) ;
327
+ throw e ;
328
+ }
329
+ }
330
+
331
+ function getSemanticDiagnosticsForFile ( sourceFile : SourceFile , cancellationToken : CancellationToken ) : Diagnostic [ ] {
332
+ return runWithCancellationToken ( ( ) => {
333
+ let typeChecker = getDiagnosticsProducingTypeChecker ( ) ;
304
334
305
- return bindDiagnostics . concat ( checkDiagnostics ) . concat ( programDiagnostics ) ;
335
+ Debug . assert ( ! ! sourceFile . bindDiagnostics ) ;
336
+ let bindDiagnostics = sourceFile . bindDiagnostics ;
337
+ let checkDiagnostics = typeChecker . getDiagnostics ( sourceFile , cancellationToken ) ;
338
+ let programDiagnostics = diagnostics . getDiagnostics ( sourceFile . fileName ) ;
339
+
340
+ return bindDiagnostics . concat ( checkDiagnostics ) . concat ( programDiagnostics ) ;
341
+ } ) ;
306
342
}
307
343
308
- function getDeclarationDiagnosticsForFile ( sourceFile : SourceFile ) : Diagnostic [ ] {
309
- if ( ! isDeclarationFile ( sourceFile ) ) {
310
- let resolver = getDiagnosticsProducingTypeChecker ( ) . getEmitResolver ( sourceFile ) ;
311
- // Don't actually write any files since we're just getting diagnostics.
312
- var writeFile : WriteFileCallback = ( ) => { } ;
313
- return ts . getDeclarationDiagnostics ( getEmitHost ( writeFile ) , resolver , sourceFile ) ;
314
- }
344
+ function getDeclarationDiagnosticsForFile ( sourceFile : SourceFile , cancellationToken : CancellationToken ) : Diagnostic [ ] {
345
+ return runWithCancellationToken ( ( ) => {
346
+ if ( ! isDeclarationFile ( sourceFile ) ) {
347
+ let resolver = getDiagnosticsProducingTypeChecker ( ) . getEmitResolver ( sourceFile , cancellationToken ) ;
348
+ // Don't actually write any files since we're just getting diagnostics.
349
+ var writeFile : WriteFileCallback = ( ) => { } ;
350
+ return ts . getDeclarationDiagnostics ( getEmitHost ( writeFile ) , resolver , sourceFile ) ;
351
+ }
352
+ } ) ;
315
353
}
316
354
317
355
function getOptionsDiagnostics ( ) : Diagnostic [ ] {
0 commit comments