@@ -502,6 +502,12 @@ function parseWithNodeMaps<T extends TSESTreeOptions = TSESTreeOptions>(
502
502
return parseWithNodeMapsInternal ( code , options , true ) ;
503
503
}
504
504
505
+ let parseAndGenerateServicesCalls : { [ fileName : string ] : number } = { } ;
506
+ // Privately exported utility intended for use in typescript-eslint unit tests only
507
+ function clearParseAndGenerateServicesCalls ( ) : void {
508
+ parseAndGenerateServicesCalls = { } ;
509
+ }
510
+
505
511
function parseAndGenerateServices < T extends TSESTreeOptions = TSESTreeOptions > (
506
512
code : string ,
507
513
options : T ,
@@ -572,12 +578,41 @@ function parseAndGenerateServices<T extends TSESTreeOptions = TSESTreeOptions>(
572
578
*/
573
579
const shouldProvideParserServices =
574
580
extra . programs != null || ( extra . projects && extra . projects . length > 0 ) ;
575
- const { ast, program } = getProgramAndAST (
576
- code ,
577
- extra . programs ,
578
- shouldProvideParserServices ,
579
- extra . createDefaultProgram ,
580
- ) ! ;
581
+
582
+ /**
583
+ * If we are in singleRun mode but the parseAndGenerateServices() function has been called more than once for the current file,
584
+ * it must mean that we are in the middle of an ESLint automated fix cycle (in which parsing can be performed up to an additional
585
+ * 10 times in order to apply all possible fixes for the file).
586
+ *
587
+ * In this scenario we cannot rely upon the singleRun AOT compiled programs because the SourceFiles will not contain the source
588
+ * with the latest fixes applied. Therefore we fallback to creating the quickest possible isolated program from the updated source.
589
+ */
590
+ let ast : ts . SourceFile ;
591
+ let program : ts . Program ;
592
+
593
+ if ( extra . singleRun && options . filePath ) {
594
+ parseAndGenerateServicesCalls [ options . filePath ] =
595
+ ( parseAndGenerateServicesCalls [ options . filePath ] || 0 ) + 1 ;
596
+ }
597
+
598
+ if (
599
+ extra . singleRun &&
600
+ options . filePath &&
601
+ parseAndGenerateServicesCalls [ options . filePath ] > 1
602
+ ) {
603
+ const isolatedAstAndProgram = createIsolatedProgram ( code , extra ) ;
604
+ ast = isolatedAstAndProgram . ast ;
605
+ program = isolatedAstAndProgram . program ;
606
+ } else {
607
+ const astAndProgram = getProgramAndAST (
608
+ code ,
609
+ extra . programs ,
610
+ shouldProvideParserServices ,
611
+ extra . createDefaultProgram ,
612
+ ) ! ;
613
+ ast = astAndProgram . ast ;
614
+ program = astAndProgram . program ;
615
+ }
581
616
582
617
/**
583
618
* Convert the TypeScript AST to an ESTree-compatible one, and optionally preserve
@@ -620,4 +655,5 @@ export {
620
655
ParseAndGenerateServicesResult ,
621
656
ParseWithNodeMapsResult ,
622
657
clearProgramCache ,
658
+ clearParseAndGenerateServicesCalls ,
623
659
} ;
0 commit comments