@@ -10,10 +10,10 @@ import {compileClassMetadata, compileDeclareClassMetadata, compileDeclareInjecto
1010import ts from 'typescript' ;
1111
1212import { ErrorCode , FatalDiagnosticError , makeDiagnostic , makeRelatedInformation } from '../../../diagnostics' ;
13- import { assertSuccessfulReferenceEmit , Reference , ReferenceEmitter } from '../../../imports' ;
13+ import { assertSuccessfulReferenceEmit , LocalCompilationExtraImportsTracker , Reference , ReferenceEmitter } from '../../../imports' ;
1414import { isArrayEqual , isReferenceEqual , isSymbolEqual , SemanticDepGraphUpdater , SemanticReference , SemanticSymbol , } from '../../../incremental/semantic_graph' ;
1515import { ExportedProviderStatusResolver , MetadataReader , MetadataRegistry , MetaKind } from '../../../metadata' ;
16- import { PartialEvaluator , ResolvedValue , SyntheticValue } from '../../../partial_evaluator' ;
16+ import { DynamicValue , PartialEvaluator , ResolvedValue , SyntheticValue } from '../../../partial_evaluator' ;
1717import { PerfEvent , PerfRecorder } from '../../../perf' ;
1818import { ClassDeclaration , DeclarationNode , Decorator , ReflectionHost , reflectObjectLiteral , } from '../../../reflection' ;
1919import { LocalModuleScopeRegistry , ScopeData } from '../../../scope' ;
@@ -179,7 +179,9 @@ export class NgModuleDecoratorHandler implements
179179 private onlyPublishPublicTypings : boolean ,
180180 private injectableRegistry : InjectableClassRegistry , private perf : PerfRecorder ,
181181 private includeClassMetadata : boolean , private includeSelectorScope : boolean ,
182- private readonly compilationMode : CompilationMode ) { }
182+ private readonly compilationMode : CompilationMode ,
183+ private readonly localCompilationExtraImportsTracker : LocalCompilationExtraImportsTracker |
184+ null ) { }
183185
184186 readonly precedence = HandlerPrecedence . PRIMARY ;
185187 readonly name = 'NgModuleDecoratorHandler' ;
@@ -240,9 +242,10 @@ export class NgModuleDecoratorHandler implements
240242 const rawDeclarations : ts . Expression | null = ngModule . get ( 'declarations' ) ?? null ;
241243 if ( this . compilationMode !== CompilationMode . LOCAL && rawDeclarations !== null ) {
242244 const declarationMeta = this . evaluator . evaluate ( rawDeclarations , forwardRefResolver ) ;
243- declarationRefs =
244- this . resolveTypeList ( rawDeclarations , declarationMeta , name , 'declarations' , 0 )
245- . references ;
245+ declarationRefs = this . resolveTypeList (
246+ rawDeclarations , declarationMeta , name , 'declarations' , 0 ,
247+ /* allowUnresolvedReferences */ false )
248+ . references ;
246249
247250 // Look through the declarations to make sure they're all a part of the current compilation.
248251 for ( const ref of declarationRefs ) {
@@ -267,17 +270,41 @@ export class NgModuleDecoratorHandler implements
267270 // Resolving imports
268271 let importRefs : Reference < ClassDeclaration > [ ] = [ ] ;
269272 let rawImports : ts . Expression | null = ngModule . get ( 'imports' ) ?? null ;
270- if ( this . compilationMode !== CompilationMode . LOCAL && rawImports !== null ) {
273+ if ( rawImports !== null ) {
271274 const importsMeta = this . evaluator . evaluate ( rawImports , moduleResolvers ) ;
272- importRefs = this . resolveTypeList ( rawImports , importsMeta , name , 'imports' , 0 ) . references ;
275+
276+ const result = this . resolveTypeList (
277+ rawImports , importsMeta , name , 'imports' , 0 ,
278+ this . compilationMode === CompilationMode . LOCAL ) ;
279+
280+ if ( this . compilationMode === CompilationMode . LOCAL &&
281+ this . localCompilationExtraImportsTracker !== null ) {
282+ // For generating extra imports in local mode, the NgModule imports that are from external
283+ // files (i.e., outside of the compilation unit) are to be added to all the files in the
284+ // compilation unit. This is because any external component that is a dependency of some
285+ // component in the compilation unit must be imported by one of these NgModule's external
286+ // imports (or the external component cannot be a dependency of that internal component).
287+ // This approach can be further optimized by adding these NgModule external imports to a
288+ // subset of files in the compilation unit and not all. See comments in {@link
289+ // LocalCompilationExtraImportsTracker} and {@link
290+ // LocalCompilationExtraImportsTracker#addGlobalImportFromIdentifier } for more details.
291+ for ( const d of result . dynamicValues ) {
292+ this . localCompilationExtraImportsTracker . addGlobalImportFromIdentifier ( d . node ) ;
293+ }
294+ }
295+
296+ importRefs = result . references ;
273297 }
274298
275299 // Resolving exports
276300 let exportRefs : Reference < ClassDeclaration > [ ] = [ ] ;
277301 const rawExports : ts . Expression | null = ngModule . get ( 'exports' ) ?? null ;
278302 if ( this . compilationMode !== CompilationMode . LOCAL && rawExports !== null ) {
279303 const exportsMeta = this . evaluator . evaluate ( rawExports , moduleResolvers ) ;
280- exportRefs = this . resolveTypeList ( rawExports , exportsMeta , name , 'exports' , 0 ) . references ;
304+ exportRefs = this . resolveTypeList (
305+ rawExports , exportsMeta , name , 'exports' , 0 ,
306+ /* allowUnresolvedReferences */ false )
307+ . references ;
281308 this . referencesRegistry . add ( node , ...exportRefs ) ;
282309 }
283310
@@ -286,8 +313,10 @@ export class NgModuleDecoratorHandler implements
286313 const rawBootstrap : ts . Expression | null = ngModule . get ( 'bootstrap' ) ?? null ;
287314 if ( this . compilationMode !== CompilationMode . LOCAL && rawBootstrap !== null ) {
288315 const bootstrapMeta = this . evaluator . evaluate ( rawBootstrap , forwardRefResolver ) ;
289- bootstrapRefs =
290- this . resolveTypeList ( rawBootstrap , bootstrapMeta , name , 'bootstrap' , 0 ) . references ;
316+ bootstrapRefs = this . resolveTypeList (
317+ rawBootstrap , bootstrapMeta , name , 'bootstrap' , 0 ,
318+ /* allowUnresolvedReferences */ false )
319+ . references ;
291320
292321 // Verify that the `@NgModule.bootstrap` list doesn't have Standalone Components.
293322 for ( const ref of bootstrapRefs ) {
@@ -425,8 +454,9 @@ export class NgModuleDecoratorHandler implements
425454 for ( const importExpr of topLevelExpressions ) {
426455 const resolved = this . evaluator . evaluate ( importExpr , moduleResolvers ) ;
427456
428- const { references, hasModuleWithProviders} =
429- this . resolveTypeList ( importExpr , [ resolved ] , node . name . text , 'imports' , absoluteIndex ) ;
457+ const { references, hasModuleWithProviders} = this . resolveTypeList (
458+ importExpr , [ resolved ] , node . name . text , 'imports' , absoluteIndex ,
459+ /* allowUnresolvedReferences */ false ) ;
430460 absoluteIndex += references . length ;
431461
432462 topLevelImports . push ( {
@@ -840,11 +870,24 @@ export class NgModuleDecoratorHandler implements
840870 */
841871 private resolveTypeList (
842872 expr : ts . Node , resolvedList : ResolvedValue , className : string , arrayName : string ,
843- absoluteIndex : number ) :
844- { references : Reference < ClassDeclaration > [ ] , hasModuleWithProviders : boolean } {
873+ absoluteIndex : number , allowUnresolvedReferences : boolean ) : {
874+ references : Reference < ClassDeclaration > [ ] ,
875+ hasModuleWithProviders : boolean ,
876+ dynamicValues : DynamicValue [ ]
877+ } {
845878 let hasModuleWithProviders = false ;
846879 const refList : Reference < ClassDeclaration > [ ] = [ ] ;
880+ const dynamicValueSet = new Set < DynamicValue > ( ) ;
881+
847882 if ( ! Array . isArray ( resolvedList ) ) {
883+ if ( allowUnresolvedReferences ) {
884+ return {
885+ references : [ ] ,
886+ hasModuleWithProviders : false ,
887+ dynamicValues : [ ] ,
888+ } ;
889+ }
890+
848891 throw createValueHasWrongTypeError (
849892 expr , resolvedList ,
850893 `Expected array when reading the NgModule.${ arrayName } of ${ className } ` ) ;
@@ -864,9 +907,14 @@ export class NgModuleDecoratorHandler implements
864907
865908 if ( Array . isArray ( entry ) ) {
866909 // Recurse into nested arrays.
867- const recursiveResult =
868- this . resolveTypeList ( expr , entry , className , arrayName , absoluteIndex ) ;
910+ const recursiveResult = this . resolveTypeList (
911+ expr , entry , className , arrayName , absoluteIndex , allowUnresolvedReferences ) ;
869912 refList . push ( ...recursiveResult . references ) ;
913+
914+ for ( const d of recursiveResult . dynamicValues ) {
915+ dynamicValueSet . add ( d ) ;
916+ }
917+
870918 absoluteIndex += recursiveResult . references . length ;
871919 hasModuleWithProviders = hasModuleWithProviders || recursiveResult . hasModuleWithProviders ;
872920 } else if ( entry instanceof Reference ) {
@@ -878,6 +926,9 @@ export class NgModuleDecoratorHandler implements
878926 }
879927 refList . push ( entry ) ;
880928 absoluteIndex += 1 ;
929+ } else if ( entry instanceof DynamicValue && allowUnresolvedReferences ) {
930+ dynamicValueSet . add ( entry ) ;
931+ continue ;
881932 } else {
882933 // TODO(alxhub): Produce a better diagnostic here - the array index may be an inner array.
883934 throw createValueHasWrongTypeError (
@@ -890,6 +941,7 @@ export class NgModuleDecoratorHandler implements
890941 return {
891942 references : refList ,
892943 hasModuleWithProviders,
944+ dynamicValues : [ ...dynamicValueSet ] ,
893945 } ;
894946 }
895947}
0 commit comments