6
6
* found in the LICENSE file at https://angular.io/license
7
7
*/
8
8
9
- import { AotCompiler , AotCompilerHost , AotCompilerOptions , EmitterVisitorContext , GeneratedFile , MessageBundle , NgAnalyzedFile , NgAnalyzedModules , ParseSourceSpan , Serializer , StubEmitFlags , TypeScriptEmitter , Xliff , Xliff2 , Xmb , core , createAotCompiler , getParseErrors , isSyntaxError } from '@angular/compiler' ;
9
+ import { AotCompiler , AotCompilerHost , AotCompilerOptions , EmitterVisitorContext , GeneratedFile , MessageBundle , NgAnalyzedFile , NgAnalyzedModules , ParseSourceSpan , Serializer , TypeScriptEmitter , Xliff , Xliff2 , Xmb , core , createAotCompiler , getParseErrors , isSyntaxError } from '@angular/compiler' ;
10
10
import * as fs from 'fs' ;
11
11
import * as path from 'path' ;
12
12
import * as ts from 'typescript' ;
@@ -63,7 +63,6 @@ class AngularCompilerProgram implements Program {
63
63
( { content, fileName} ) => this . summariesFromPreviousCompilations . set ( fileName , content ) ) ;
64
64
}
65
65
66
- this . rootNames = rootNames = rootNames . filter ( r => ! GENERATED_FILES . test ( r ) ) ;
67
66
if ( options . flatModuleOutFile ) {
68
67
const { host : bundleHost , indexName, errors} = createBundleIndexHost ( options , rootNames , host ) ;
69
68
if ( errors ) {
@@ -133,14 +132,15 @@ class AngularCompilerProgram implements Program {
133
132
if ( this . _analyzedModules ) {
134
133
throw new Error ( 'Angular structure already loaded' ) ;
135
134
}
136
- const { tmpProgram, analyzedFiles, hostAdapter} = this . _createProgramWithBasicStubs ( ) ;
135
+ const { tmpProgram, analyzedFiles, hostAdapter, rootNames } = this . _createProgramWithBasicStubs ( ) ;
137
136
return this . _compiler . loadFilesAsync ( analyzedFiles )
138
137
. catch ( this . catchAnalysisError . bind ( this ) )
139
138
. then ( analyzedModules => {
140
139
if ( this . _analyzedModules ) {
141
140
throw new Error ( 'Angular structure loaded both synchronously and asynchronsly' ) ;
142
141
}
143
- this . _updateProgramWithTypeCheckStubs ( tmpProgram , analyzedModules , hostAdapter ) ;
142
+ this . _updateProgramWithTypeCheckStubs (
143
+ tmpProgram , analyzedModules , hostAdapter , rootNames ) ;
144
144
} ) ;
145
145
}
146
146
@@ -177,7 +177,7 @@ class AngularCompilerProgram implements Program {
177
177
program : this . tsProgram ,
178
178
host : this . host ,
179
179
options : this . options ,
180
- writeFile : createWriteFileCallback ( emitFlags , this . host , outSrcMapping ) ,
180
+ writeFile : createWriteFileCallback ( genFiles , this . host , outSrcMapping ) ,
181
181
emitOnlyDtsFiles : ( emitFlags & ( EmitFlags . DTS | EmitFlags . JS ) ) == EmitFlags . DTS ,
182
182
customTransformers : this . calculateTransforms ( genFiles , customTransformers )
183
183
} ) ;
@@ -291,20 +291,21 @@ class AngularCompilerProgram implements Program {
291
291
if ( this . _analyzedModules ) {
292
292
return ;
293
293
}
294
- const { tmpProgram, analyzedFiles, hostAdapter} = this . _createProgramWithBasicStubs ( ) ;
294
+ const { tmpProgram, analyzedFiles, hostAdapter, rootNames } = this . _createProgramWithBasicStubs ( ) ;
295
295
let analyzedModules : NgAnalyzedModules ;
296
296
try {
297
297
analyzedModules = this . _compiler . loadFilesSync ( analyzedFiles ) ;
298
298
} catch ( e ) {
299
299
analyzedModules = this . catchAnalysisError ( e ) ;
300
300
}
301
- this . _updateProgramWithTypeCheckStubs ( tmpProgram , analyzedModules , hostAdapter ) ;
301
+ this . _updateProgramWithTypeCheckStubs ( tmpProgram , analyzedModules , hostAdapter , rootNames ) ;
302
302
}
303
303
304
304
private _createProgramWithBasicStubs ( ) : {
305
305
tmpProgram : ts . Program ,
306
306
analyzedFiles : NgAnalyzedFile [ ] ,
307
- hostAdapter : TsCompilerAotCompilerTypeCheckHostAdapter
307
+ hostAdapter : TsCompilerAotCompilerTypeCheckHostAdapter ,
308
+ rootNames : string [ ] ,
308
309
} {
309
310
if ( this . _analyzedModules ) {
310
311
throw new Error ( `Internal Error: already initalized!` ) ;
@@ -330,17 +331,31 @@ class AngularCompilerProgram implements Program {
330
331
this . _typeCheckHost = hostAdapter ;
331
332
this . _structuralDiagnostics = [ ] ;
332
333
333
- const tmpProgram = ts . createProgram ( this . rootNames , this . options , hostAdapter , oldTsProgram ) ;
334
- return { tmpProgram, analyzedFiles, hostAdapter} ;
334
+ let rootNames =
335
+ this . rootNames . filter ( fn => ! GENERATED_FILES . test ( fn ) || ! hostAdapter . isSourceFile ( fn ) ) ;
336
+ if ( this . options . noResolve ) {
337
+ this . rootNames . forEach ( rootName => {
338
+ const sf =
339
+ hostAdapter . getSourceFile ( rootName , this . options . target || ts . ScriptTarget . Latest ) ;
340
+ sf . referencedFiles . forEach ( ( fileRef ) => {
341
+ if ( GENERATED_FILES . test ( fileRef . fileName ) ) {
342
+ rootNames . push ( fileRef . fileName ) ;
343
+ }
344
+ } ) ;
345
+ } ) ;
346
+ }
347
+
348
+ const tmpProgram = ts . createProgram ( rootNames , this . options , hostAdapter , oldTsProgram ) ;
349
+ return { tmpProgram, analyzedFiles, hostAdapter, rootNames} ;
335
350
}
336
351
337
352
private _updateProgramWithTypeCheckStubs (
338
353
tmpProgram : ts . Program , analyzedModules : NgAnalyzedModules ,
339
- hostAdapter : TsCompilerAotCompilerTypeCheckHostAdapter ) {
354
+ hostAdapter : TsCompilerAotCompilerTypeCheckHostAdapter , rootNames : string [ ] ) {
340
355
this . _analyzedModules = analyzedModules ;
341
356
const genFiles = this . _compiler . emitTypeCheckStubs ( analyzedModules ) ;
342
357
genFiles . forEach ( gf => hostAdapter . updateGeneratedFile ( gf ) ) ;
343
- this . _tsProgram = ts . createProgram ( this . rootNames , this . options , hostAdapter , tmpProgram ) ;
358
+ this . _tsProgram = ts . createProgram ( rootNames , this . options , hostAdapter , tmpProgram ) ;
344
359
// Note: the new ts program should be completely reusable by TypeScript as:
345
360
// - we cache all the files in the hostAdapter
346
361
// - new new stubs use the exactly same imports/exports as the old once (we assert that in
@@ -453,17 +468,24 @@ function getAotCompilerOptions(options: CompilerOptions): AotCompilerOptions {
453
468
}
454
469
455
470
function createWriteFileCallback (
456
- emitFlags : EmitFlags , host : ts . CompilerHost ,
471
+ generatedFiles : GeneratedFile [ ] , host : ts . CompilerHost ,
457
472
outSrcMapping : Array < { sourceFile : ts . SourceFile , outFileName : string } > ) {
473
+ const genFileByFileName = new Map < string , GeneratedFile > ( ) ;
474
+ generatedFiles . forEach ( genFile => genFileByFileName . set ( genFile . genFileUrl , genFile ) ) ;
458
475
return ( fileName : string , data : string , writeByteOrderMark : boolean ,
459
476
onError ?: ( message : string ) => void , sourceFiles ?: ts . SourceFile [ ] ) => {
460
477
const sourceFile = sourceFiles && sourceFiles . length == 1 ? sourceFiles [ 0 ] : null ;
461
- const isGenerated = GENERATED_FILES . test ( fileName ) ;
462
478
if ( sourceFile ) {
463
479
outSrcMapping . push ( { outFileName : fileName , sourceFile} ) ;
464
480
}
465
- if ( isGenerated && ! ( emitFlags & EmitFlags . Codegen ) ) {
466
- return ;
481
+ const isGenerated = GENERATED_FILES . test ( fileName ) ;
482
+ if ( isGenerated && sourceFile ) {
483
+ // Filter out generated files for which we didn't generate code.
484
+ // This can happen as the stub caclulation is not completely exact.
485
+ const genFile = genFileByFileName . get ( sourceFile . fileName ) ;
486
+ if ( ! genFile || ! genFile . stmts || genFile . stmts . length === 0 ) {
487
+ return ;
488
+ }
467
489
}
468
490
host . writeFile ( fileName , data , writeByteOrderMark , onError , sourceFiles ) ;
469
491
} ;
0 commit comments