From 9ab401f4d303ab4835694cb484ee619c37c46b39 Mon Sep 17 00:00:00 2001 From: Tobias Bosch Date: Tue, 29 Nov 2016 08:08:22 -0800 Subject: [PATCH] refactor(compiler): simplify `NgModuleSymmaryMetadata` - merge `NgModuleInjectorSummary` and `NgModuleDirectiveSummary` - remove `directiveLoaders` from the summary --- modules/@angular/compiler/src/aot/compiler.ts | 28 ++-- .../@angular/compiler/src/compile_metadata.ts | 64 ++----- .../@angular/compiler/src/i18n/extractor.ts | 52 +++--- modules/@angular/compiler/src/jit/compiler.ts | 10 +- .../compiler/src/metadata_resolver.ts | 158 +++++++++--------- .../compiler/src/provider_analyzer.ts | 7 +- .../compiler/test/metadata_resolver_spec.ts | 59 ++++--- 7 files changed, 173 insertions(+), 205 deletions(-) diff --git a/modules/@angular/compiler/src/aot/compiler.ts b/modules/@angular/compiler/src/aot/compiler.ts index a89a01d9d1..5043339fcf 100644 --- a/modules/@angular/compiler/src/aot/compiler.ts +++ b/modules/@angular/compiler/src/aot/compiler.ts @@ -49,12 +49,16 @@ export class AotCompiler { const programSymbols = extractProgramSymbols(this._staticReflector, rootFiles, this._options); const {ngModuleByPipeOrDirective, files, ngModules} = analyzeAndValidateNgModules(programSymbols, this._options, this._metadataResolver); - return loadNgModuleDirectives(ngModules).then(() => { - const sourceModules = files.map( - file => this._compileSrcFile( - file.srcUrl, ngModuleByPipeOrDirective, file.directives, file.ngModules)); - return ListWrapper.flatten(sourceModules); - }); + return Promise + .all(ngModules.map( + ngModule => this._metadataResolver.loadNgModuleDirectiveAndPipeMetadata( + ngModule.type.reference, false))) + .then(() => { + const sourceModules = files.map( + file => this._compileSrcFile( + file.srcUrl, ngModuleByPipeOrDirective, file.directives, file.ngModules)); + return ListWrapper.flatten(sourceModules); + }); } private _compileSrcFile( @@ -313,14 +317,6 @@ export function analyzeAndValidateNgModules( return result; } -// Wait for the directives in the given modules have been loaded -export function loadNgModuleDirectives(ngModules: CompileNgModuleMetadata[]) { - return Promise - .all(ListWrapper.flatten(ngModules.map( - (ngModule) => ngModule.transitiveModule.directiveLoaders.map(loader => loader())))) - .then(() => {}); -} - function _analyzeNgModules( ngModuleMetas: CompileNgModuleMetadata[], symbolsMissingModule: StaticSymbol[]): NgAnalyzedModules { @@ -417,13 +413,13 @@ function _createNgModules( if (ngModules.has(staticSymbol) || !_filterFileByPatterns(staticSymbol.filePath, options)) { return false; } - const ngModule = metadataResolver.getUnloadedNgModuleMetadata(staticSymbol, false, false); + const ngModule = metadataResolver.getNgModuleMetadata(staticSymbol, false); if (ngModule) { ngModules.set(ngModule.type.reference, ngModule); ngModule.declaredDirectives.forEach((dir) => ngModulePipesAndDirective.add(dir.reference)); ngModule.declaredPipes.forEach((pipe) => ngModulePipesAndDirective.add(pipe.reference)); // For every input module add the list of transitively included modules - ngModule.transitiveModule.modules.forEach(modMeta => addNgModule(modMeta.type.reference)); + ngModule.transitiveModule.modules.forEach(modMeta => addNgModule(modMeta.reference)); } return !!ngModule; }; diff --git a/modules/@angular/compiler/src/compile_metadata.ts b/modules/@angular/compiler/src/compile_metadata.ts index 504762ea6e..594730b851 100644 --- a/modules/@angular/compiler/src/compile_metadata.ts +++ b/modules/@angular/compiler/src/compile_metadata.ts @@ -499,30 +499,21 @@ export class CompilePipeMetadata { // Note: This should only use interfaces as nested data types // as we need to be able to serialize this from/to JSON! -export interface CompileNgModuleInjectorSummary extends CompileSummary { +export interface CompileNgModuleSummary { isSummary: boolean /* TODO: `true` when we drop TS 1.8 support */; type: CompileTypeMetadata; - entryComponents: CompileIdentifierMetadata[]; - providers: CompileProviderMetadata[]; - importedModules: CompileNgModuleInjectorSummary[]; - exportedModules: CompileNgModuleInjectorSummary[]; -} -// Note: This should only use interfaces as nested data types -// as we need to be able to serialize this from/to JSON! -export interface CompileNgModuleDirectiveSummary extends CompileSummary { - isSummary: boolean /* TODO: `true` when we drop TS 1.8 support */; - type: CompileTypeMetadata; exportedDirectives: CompileIdentifierMetadata[]; exportedPipes: CompileIdentifierMetadata[]; - exportedModules: CompileNgModuleDirectiveSummary[]; - directiveLoaders: (() => Promise)[]; -} + exportedModules: CompileIdentifierMetadata[]; -// Note: This should only use interfaces as nested data types -// as we need to be able to serialize this from/to JSON! -export type CompileNgModuleSummary = - CompileNgModuleInjectorSummary & CompileNgModuleDirectiveSummary; + // Note: This is transitive. + entryComponents: CompileIdentifierMetadata[]; + // Note: This is transitive. + providers: {provider: CompileProviderMetadata, module: CompileIdentifierMetadata}[], + // Note: This is transitive. + modules: CompileTypeMetadata[]; +} /** * Metadata regarding compilation of a module. @@ -532,6 +523,7 @@ export class CompileNgModuleMetadata { declaredDirectives: CompileIdentifierMetadata[]; exportedDirectives: CompileIdentifierMetadata[]; declaredPipes: CompileIdentifierMetadata[]; + exportedPipes: CompileIdentifierMetadata[]; entryComponents: CompileIdentifierMetadata[]; bootstrapComponents: CompileIdentifierMetadata[]; @@ -581,34 +573,12 @@ export class CompileNgModuleMetadata { return { isSummary: true, type: this.type, - entryComponents: this.entryComponents, - providers: this.providers, - importedModules: this.importedModules, - exportedModules: this.exportedModules, + entryComponents: this.transitiveModule.entryComponents, + providers: this.transitiveModule.providers, + modules: this.transitiveModule.modules, exportedDirectives: this.exportedDirectives, exportedPipes: this.exportedPipes, - directiveLoaders: this.transitiveModule.directiveLoaders - }; - } - - toInjectorSummary(): CompileNgModuleInjectorSummary { - return { - isSummary: true, - type: this.type, - entryComponents: this.entryComponents, - providers: this.providers, - importedModules: this.importedModules, - exportedModules: this.exportedModules - }; - } - toDirectiveSummary(): CompileNgModuleDirectiveSummary { - return { - isSummary: true, - type: this.type, - exportedDirectives: this.exportedDirectives, - exportedPipes: this.exportedPipes, - exportedModules: this.exportedModules, - directiveLoaders: this.transitiveModule.directiveLoaders + exportedModules: this.exportedModules.map(m => m.type) }; } } @@ -618,10 +588,10 @@ export class TransitiveCompileNgModuleMetadata { pipesSet = new Set(); constructor( - public modules: CompileNgModuleInjectorSummary[], public providers: CompileProviderMetadata[], + public modules: CompileTypeMetadata[], + public providers: {provider: CompileProviderMetadata, module: CompileIdentifierMetadata}[], public entryComponents: CompileIdentifierMetadata[], - public directives: CompileIdentifierMetadata[], public pipes: CompileIdentifierMetadata[], - public directiveLoaders: (() => Promise)[]) { + public directives: CompileIdentifierMetadata[], public pipes: CompileIdentifierMetadata[]) { directives.forEach(dir => this.directivesSet.add(dir.reference)); pipes.forEach(pipe => this.pipesSet.add(pipe.reference)); } diff --git a/modules/@angular/compiler/src/i18n/extractor.ts b/modules/@angular/compiler/src/i18n/extractor.ts index b1bad2f136..8ac6e4cca7 100644 --- a/modules/@angular/compiler/src/i18n/extractor.ts +++ b/modules/@angular/compiler/src/i18n/extractor.ts @@ -12,7 +12,7 @@ */ import {ViewEncapsulation} from '@angular/core'; -import {analyzeAndValidateNgModules, extractProgramSymbols, loadNgModuleDirectives} from '../aot/compiler'; +import {analyzeAndValidateNgModules, extractProgramSymbols} from '../aot/compiler'; import {StaticAndDynamicReflectionCapabilities} from '../aot/static_reflection_capabilities'; import {StaticReflector, StaticReflectorHost} from '../aot/static_reflector'; import {CompileDirectiveMetadata} from '../compile_metadata'; @@ -58,32 +58,36 @@ export class Extractor { const programSymbols = extractProgramSymbols(this.staticReflector, rootFiles, this.options); const {ngModuleByPipeOrDirective, files, ngModules} = analyzeAndValidateNgModules(programSymbols, this.options, this.metadataResolver); - return loadNgModuleDirectives(ngModules).then(() => { - const errors: ParseError[] = []; + return Promise + .all(ngModules.map( + ngModule => this.metadataResolver.loadNgModuleDirectiveAndPipeMetadata( + ngModule.type.reference, false))) + .then(() => { + const errors: ParseError[] = []; - files.forEach(file => { - const compMetas: CompileDirectiveMetadata[] = []; - file.directives.forEach(directiveType => { - const dirMeta = this.metadataResolver.getDirectiveMetadata(directiveType); - if (dirMeta && dirMeta.isComponent) { - compMetas.push(dirMeta); + files.forEach(file => { + const compMetas: CompileDirectiveMetadata[] = []; + file.directives.forEach(directiveType => { + const dirMeta = this.metadataResolver.getDirectiveMetadata(directiveType); + if (dirMeta && dirMeta.isComponent) { + compMetas.push(dirMeta); + } + }); + compMetas.forEach(compMeta => { + const html = compMeta.template.template; + const interpolationConfig = + InterpolationConfig.fromArray(compMeta.template.interpolation); + errors.push( + ...this.messageBundle.updateFromTemplate(html, file.srcUrl, interpolationConfig)); + }); + }); + + if (errors.length) { + throw new Error(errors.map(e => e.toString()).join('\n')); } - }); - compMetas.forEach(compMeta => { - const html = compMeta.template.template; - const interpolationConfig = - InterpolationConfig.fromArray(compMeta.template.interpolation); - errors.push( - ...this.messageBundle.updateFromTemplate(html, file.srcUrl, interpolationConfig)); - }); - }); - if (errors.length) { - throw new Error(errors.map(e => e.toString()).join('\n')); - } - - return this.messageBundle; - }); + return this.messageBundle; + }); } static create(host: ExtractorHost, options: ExtractorOptions): diff --git a/modules/@angular/compiler/src/jit/compiler.ts b/modules/@angular/compiler/src/jit/compiler.ts index e5cc4520f1..7a9c261990 100644 --- a/modules/@angular/compiler/src/jit/compiler.ts +++ b/modules/@angular/compiler/src/jit/compiler.ts @@ -101,7 +101,8 @@ export class JitCompiler implements Compiler { private _loadModules(mainModule: any, isSync: boolean): Promise { const loadingPromises: Promise[] = []; - const {ngModule, loading} = this._metadataResolver.loadNgModuleMetadata(mainModule, isSync); + const {ngModule, loading} = + this._metadataResolver.loadNgModuleDirectiveAndPipeMetadata(mainModule, isSync); loadingPromises.push(loading); // Note: the loadingPromise for a module only includes the loading of the exported directives // of imported modules. @@ -109,7 +110,8 @@ export class JitCompiler implements Compiler { // so we also need to call loadNgModuleMetadata for all nested modules. ngModule.transitiveModule.modules.forEach((localModuleMeta) => { loadingPromises.push( - this._metadataResolver.loadNgModuleMetadata(localModuleMeta.type.reference, isSync) + this._metadataResolver + .loadNgModuleDirectiveAndPipeMetadata(localModuleMeta.reference, isSync) .loading); }); return Promise.all(loadingPromises); @@ -150,7 +152,7 @@ export class JitCompiler implements Compiler { ngModule.transitiveModule.modules.forEach((localModuleSummary) => { const localModuleMeta = - this._metadataResolver.getNgModuleMetadata(localModuleSummary.type.reference); + this._metadataResolver.getNgModuleMetadata(localModuleSummary.reference); localModuleMeta.declaredDirectives.forEach((dirIdentifier) => { moduleByDirective.set(dirIdentifier.reference, localModuleMeta); const dirMeta = this._metadataResolver.getDirectiveMetadata(dirIdentifier.reference); @@ -168,7 +170,7 @@ export class JitCompiler implements Compiler { }); ngModule.transitiveModule.modules.forEach((localModuleSummary) => { const localModuleMeta = - this._metadataResolver.getNgModuleMetadata(localModuleSummary.type.reference); + this._metadataResolver.getNgModuleMetadata(localModuleSummary.reference); localModuleMeta.declaredDirectives.forEach((dirIdentifier) => { const dirMeta = this._metadataResolver.getDirectiveMetadata(dirIdentifier.reference); if (dirMeta.isComponent) { diff --git a/modules/@angular/compiler/src/metadata_resolver.ts b/modules/@angular/compiler/src/metadata_resolver.ts index faba178acb..bb5c42d6b3 100644 --- a/modules/@angular/compiler/src/metadata_resolver.ts +++ b/modules/@angular/compiler/src/metadata_resolver.ts @@ -300,24 +300,11 @@ export class CompileMetadataResolver { isPipe(type: any) { return this._pipeResolver.isPipe(type); } - /** - * Gets the metadata for the given module. - * This assumes `loadNgModuleMetadata` has been called first. - */ - getNgModuleMetadata(moduleType: any): cpl.CompileNgModuleMetadata { - const modMeta = this._ngModuleCache.get(moduleType); - if (!modMeta) { - throw new Error( - `Illegal state: getNgModuleMetadata can only be called after loadNgModuleMetadata. Module ${stringify(moduleType)}.`); - } - return modMeta; - } - - private _loadNgModuleSummary(moduleType: any, isSync: boolean): cpl.CompileNgModuleSummary { + private _getNgModuleSummary(moduleType: any): cpl.CompileNgModuleSummary { // TODO(tbosch): add logic to read summary files! // - needs to add directive / pipe summaries to this._directiveSummaryCache / // this._pipeSummaryCache as well! - const moduleMeta = this._loadNgModuleMetadata(moduleType, isSync, false); + const moduleMeta = this.getNgModuleMetadata(moduleType, false); return moduleMeta ? moduleMeta.toSummary() : null; } @@ -326,25 +313,23 @@ export class CompileMetadataResolver { * imported modules, * but not private directives of imported modules. */ - loadNgModuleMetadata(moduleType: any, isSync: boolean, throwIfNotFound = true): + loadNgModuleDirectiveAndPipeMetadata(moduleType: any, isSync: boolean, throwIfNotFound = true): {ngModule: cpl.CompileNgModuleMetadata, loading: Promise} { - const ngModule = this._loadNgModuleMetadata(moduleType, isSync, throwIfNotFound); - const loading = ngModule ? - Promise.all(ngModule.transitiveModule.directiveLoaders.map(loader => loader())) : - Promise.resolve(null); + const ngModule = this.getNgModuleMetadata(moduleType, throwIfNotFound); + let loading: Promise; + if (ngModule) { + loading = Promise.all([ + ...ngModule.transitiveModule.directives.map( + (id) => this._loadDirectiveMetadata(id.reference, isSync)), + ...ngModule.transitiveModule.pipes.map((id) => this._loadPipeMetadata(id.reference)), + ]); + } else { + loading = Promise.resolve(null); + } return {ngModule, loading}; } - /** - * Get the NgModule metadata without loading the directives. - */ - getUnloadedNgModuleMetadata(moduleType: any, isSync: boolean, throwIfNotFound = true): - cpl.CompileNgModuleMetadata { - return this._loadNgModuleMetadata(moduleType, isSync, throwIfNotFound); - } - - private _loadNgModuleMetadata(moduleType: any, isSync: boolean, throwIfNotFound = true): - cpl.CompileNgModuleMetadata { + getNgModuleMetadata(moduleType: any, throwIfNotFound = true): cpl.CompileNgModuleMetadata { moduleType = resolveForwardRef(moduleType); let compileMeta = this._ngModuleCache.get(moduleType); if (compileMeta) { @@ -359,7 +344,7 @@ export class CompileMetadataResolver { const declaredPipes: cpl.CompileIdentifierMetadata[] = []; const importedModules: cpl.CompileNgModuleSummary[] = []; const exportedModules: cpl.CompileNgModuleSummary[] = []; - const providers: any[] = []; + const providers: cpl.CompileProviderMetadata[] = []; const entryComponents: cpl.CompileIdentifierMetadata[] = []; const bootstrapComponents: cpl.CompileIdentifierMetadata[] = []; const schemas: SchemaMetadata[] = []; @@ -380,7 +365,7 @@ export class CompileMetadataResolver { } if (importedModuleType) { - const importedModuleSummary = this._loadNgModuleSummary(importedModuleType, isSync); + const importedModuleSummary = this._getNgModuleSummary(importedModuleType); if (!importedModuleSummary) { throw new Error( `Unexpected ${this._getTypeDescriptor(importedType)} '${stringify(importedType)}' imported by the module '${stringify(moduleType)}'`); @@ -399,7 +384,7 @@ export class CompileMetadataResolver { throw new Error( `Unexpected value '${stringify(exportedType)}' exported by the module '${stringify(moduleType)}'`); } - const exportedModuleSummary = this._loadNgModuleSummary(exportedType, isSync); + const exportedModuleSummary = this._getNgModuleSummary(exportedType); if (exportedModuleSummary) { exportedModules.push(exportedModuleSummary); } else { @@ -423,16 +408,11 @@ export class CompileMetadataResolver { transitiveModule.directives.push(declaredIdentifier); declaredDirectives.push(declaredIdentifier); this._addTypeToModule(declaredType, moduleType); - const loader = this._loadDirectiveMetadata(declaredType, isSync); - if (loader) { - transitiveModule.directiveLoaders.push(loader); - } } else if (this._pipeResolver.isPipe(declaredType)) { transitiveModule.pipesSet.add(declaredType); transitiveModule.pipes.push(declaredIdentifier); declaredPipes.push(declaredIdentifier); this._addTypeToModule(declaredType, moduleType); - this._loadPipeMetadata(declaredType); } else { throw new Error( `Unexpected ${this._getTypeDescriptor(declaredType)} '${stringify(declaredType)}' declared by the module '${stringify(moduleType)}'`); @@ -482,9 +462,6 @@ export class CompileMetadataResolver { schemas.push(...flattenAndDedupeArray(meta.schemas)); } - transitiveModule.entryComponents.push(...entryComponents); - transitiveModule.providers.push(...providers); - compileMeta = new cpl.CompileNgModuleMetadata({ type: this._getTypeMetadata(moduleType), providers, @@ -501,7 +478,11 @@ export class CompileMetadataResolver { id: meta.id, }); - transitiveModule.modules.push(compileMeta.toInjectorSummary()); + transitiveModule.entryComponents.push(...entryComponents); + providers.forEach((provider) => { + transitiveModule.providers.push({provider: provider, module: compileMeta.type}); + }); + transitiveModule.modules.push(compileMeta.type); this._ngModuleCache.set(moduleType, compileMeta); return compileMeta; } @@ -542,19 +523,63 @@ export class CompileMetadataResolver { importedModules: cpl.CompileNgModuleSummary[], exportedModules: cpl.CompileNgModuleSummary[]): cpl.TransitiveCompileNgModuleMetadata { // collect `providers` / `entryComponents` from all imported and all exported modules - const transitiveModules = getTransitiveImportedModules(importedModules.concat(exportedModules)); - const providers = flattenArray(transitiveModules.map((ngModule) => ngModule.providers)); - const entryComponents = - flattenArray(transitiveModules.map((ngModule) => ngModule.entryComponents)); + const modulesByToken = new Map>(); + const providers: {provider: cpl.CompileProviderMetadata, + module: cpl.CompileIdentifierMetadata}[] = []; + const entryComponents: cpl.CompileIdentifierMetadata[] = []; + const entryComponentSet = new Set(); + const modules: cpl.CompileTypeMetadata[] = []; + const moduleSet = new Set(); + importedModules.concat(exportedModules).forEach((modSummary) => { + modSummary.modules.forEach((mod) => { + if (!moduleSet.has(mod.reference)) { + moduleSet.add(mod.reference); + modules.push(mod); + } + }); + modSummary.entryComponents.forEach((comp) => { + if (!entryComponentSet.has(comp.reference)) { + entryComponentSet.add(comp.reference); + entryComponents.push(comp); + } + }); + modSummary.providers.forEach((entry) => { + const tokenRef = cpl.tokenReference(entry.provider.token); + let prevModules = modulesByToken.get(tokenRef); + if (!prevModules) { + prevModules = new Set(); + modulesByToken.set(tokenRef, prevModules); + } + const moduleRef = entry.module.reference; + if (!prevModules.has(moduleRef)) { + prevModules.add(moduleRef); + providers.push(entry); + } + }); + }); - const transitiveExportedModules = getTransitiveExportedModules(importedModules); + + const transitiveExportedModules = this._getTransitiveExportedModules(importedModules); const directives = flattenArray(transitiveExportedModules.map((ngModule) => ngModule.exportedDirectives)); const pipes = flattenArray(transitiveExportedModules.map((ngModule) => ngModule.exportedPipes)); - const directiveLoaders = - ListWrapper.flatten(transitiveExportedModules.map(ngModule => ngModule.directiveLoaders)); return new cpl.TransitiveCompileNgModuleMetadata( - transitiveModules, providers, entryComponents, directives, pipes, directiveLoaders); + modules, providers, entryComponents, directives, pipes); + } + + private _getTransitiveExportedModules( + modules: cpl.CompileNgModuleSummary[], targetModules: cpl.CompileNgModuleSummary[] = [], + visitedModules = new Set>()): cpl.CompileNgModuleSummary[] { + modules.forEach((ngModule) => { + if (!visitedModules.has(ngModule.type.reference)) { + visitedModules.add(ngModule.type.reference); + targetModules.push(ngModule); + this._getTransitiveExportedModules( + ngModule.exportedModules.map(id => this._getNgModuleSummary(id.reference)), + targetModules, visitedModules); + } + }); + return targetModules; } private _getIdentifierMetadata(type: Type): cpl.CompileIdentifierMetadata { @@ -826,39 +851,6 @@ export class CompileMetadataResolver { } } -function getTransitiveExportedModules( - modules: cpl.CompileNgModuleDirectiveSummary[], - targetModules: cpl.CompileNgModuleDirectiveSummary[] = [], - visitedModules = new Set>()): cpl.CompileNgModuleDirectiveSummary[] { - modules.forEach((ngModule) => { - if (!visitedModules.has(ngModule.type.reference)) { - visitedModules.add(ngModule.type.reference); - getTransitiveExportedModules(ngModule.exportedModules, targetModules, visitedModules); - // Add after recursing so imported/exported modules are before the module itself. - // This is important for overwriting providers of imported modules! - targetModules.push(ngModule); - } - }); - return targetModules; -} - -function getTransitiveImportedModules( - modules: cpl.CompileNgModuleInjectorSummary[], - targetModules: cpl.CompileNgModuleInjectorSummary[] = [], - visitedModules = new Set>()): cpl.CompileNgModuleInjectorSummary[] { - modules.forEach((ngModule) => { - if (!visitedModules.has(ngModule.type.reference)) { - visitedModules.add(ngModule.type.reference); - const nestedModules = ngModule.importedModules.concat(ngModule.exportedModules); - getTransitiveImportedModules(nestedModules, targetModules, visitedModules); - // Add after recursing so imported/exported modules are before the module itself. - // This is important for overwriting providers of imported modules! - targetModules.push(ngModule); - } - }); - return targetModules; -} - function flattenArray(tree: any[], out: Array = []): Array { if (tree) { for (let i = 0; i < tree.length; i++) { diff --git a/modules/@angular/compiler/src/provider_analyzer.ts b/modules/@angular/compiler/src/provider_analyzer.ts index 27217a57f8..d754f86a22 100644 --- a/modules/@angular/compiler/src/provider_analyzer.ts +++ b/modules/@angular/compiler/src/provider_analyzer.ts @@ -273,16 +273,15 @@ export class NgModuleProviderAnalyzer { ngModule: CompileNgModuleMetadata, extraProviders: CompileProviderMetadata[], sourceSpan: ParseSourceSpan) { this._allProviders = new Map(); - const ngModuleTypes = ngModule.transitiveModule.modules.map((moduleMeta) => moduleMeta.type); - ngModuleTypes.forEach((ngModuleType: CompileTypeMetadata) => { + ngModule.transitiveModule.modules.forEach((ngModuleType: CompileTypeMetadata) => { const ngModuleProvider = {token: {identifier: ngModuleType}, useClass: ngModuleType}; _resolveProviders( [ngModuleProvider], ProviderAstType.PublicService, true, sourceSpan, this._errors, this._allProviders); }); _resolveProviders( - ngModule.transitiveModule.providers.concat(extraProviders), ProviderAstType.PublicService, - false, sourceSpan, this._errors, this._allProviders); + ngModule.transitiveModule.providers.map(entry => entry.provider).concat(extraProviders), + ProviderAstType.PublicService, false, sourceSpan, this._errors, this._allProviders); } parse(): ProviderAst[] { diff --git a/modules/@angular/compiler/test/metadata_resolver_spec.ts b/modules/@angular/compiler/test/metadata_resolver_spec.ts index b23f29946c..087618eb55 100644 --- a/modules/@angular/compiler/test/metadata_resolver_spec.ts +++ b/modules/@angular/compiler/test/metadata_resolver_spec.ts @@ -23,7 +23,7 @@ export function main() { describe('CompileMetadataResolver', () => { beforeEach(() => { TestBed.configureCompiler({providers: TEST_COMPILER_PROVIDERS}); }); - it('should throw on the get... methods if the module has not been loaded yet', + it('should throw on the getDirectiveMetadata/getPipeMetadata methods if the module has not been loaded yet', inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => { @NgModule({}) class SomeModule { @@ -33,7 +33,6 @@ export function main() { class SomePipe { } - expect(() => resolver.getNgModuleMetadata(SomeModule)).toThrowError(/Illegal state/); expect(() => resolver.getDirectiveMetadata(ComponentWithEverythingInline)) .toThrowError(/Illegal state/); expect(() => resolver.getPipeMetadata(SomePipe)).toThrowError(/Illegal state/); @@ -44,7 +43,7 @@ export function main() { @NgModule({declarations: [ComponentWithEverythingInline]}) class SomeModule { } - resolver.loadNgModuleMetadata(SomeModule, true); + resolver.loadNgModuleDirectiveAndPipeMetadata(SomeModule, true); const meta = resolver.getDirectiveMetadata(ComponentWithEverythingInline); expect(meta.selector).toEqual('someSelector'); @@ -71,7 +70,7 @@ export function main() { class SomeModule { } - expect(() => resolver.loadNgModuleMetadata(SomeModule, true)) + expect(() => resolver.loadNgModuleDirectiveAndPipeMetadata(SomeModule, true)) .toThrowError( `Can't compile synchronously as ${stringify(ComponentWithExternalResources)} is still being loaded!`); })); @@ -85,7 +84,7 @@ export function main() { } resourceLoader.when('someTemplateUrl', 'someTemplate'); - resolver.loadNgModuleMetadata(SomeModule, false).loading.then(() => { + resolver.loadNgModuleDirectiveAndPipeMetadata(SomeModule, false).loading.then(() => { const meta = resolver.getDirectiveMetadata(ComponentWithExternalResources); expect(meta.selector).toEqual('someSelector'); expect(meta.template.styleUrls).toEqual(['someStyleUrl']); @@ -99,7 +98,10 @@ export function main() { async(inject( [CompileMetadataResolver, ResourceLoader], (resolver: CompileMetadataResolver, resourceLoader: MockResourceLoader) => { - @NgModule({declarations: [ComponentWithExternalResources]}) + @NgModule({ + declarations: [ComponentWithExternalResources], + exports: [ComponentWithExternalResources] + }) class SomeImportedModule { } @@ -108,7 +110,7 @@ export function main() { } resourceLoader.when('someTemplateUrl', 'someTemplate'); - resolver.loadNgModuleMetadata(SomeModule, false).loading.then(() => { + resolver.loadNgModuleDirectiveAndPipeMetadata(SomeModule, false).loading.then(() => { const meta = resolver.getDirectiveMetadata(ComponentWithExternalResources); expect(meta.selector).toEqual('someSelector'); }); @@ -126,7 +128,7 @@ export function main() { class SomeModule { } - resolver.loadNgModuleMetadata(SomeModule, false).loading.then(() => { + resolver.loadNgModuleDirectiveAndPipeMetadata(SomeModule, false).loading.then(() => { const value: string = resolver.getDirectiveMetadata(ComponentWithoutModuleId).template.templateUrl; const expectedEndValue = './someUrl'; @@ -140,7 +142,7 @@ export function main() { class SomeModule { } - expect(() => resolver.loadNgModuleMetadata(SomeModule, true)) + expect(() => resolver.loadNgModuleDirectiveAndPipeMetadata(SomeModule, true)) .toThrowError( `moduleId should be a string in "ComponentWithInvalidModuleId". See` + ` https://goo.gl/wIDDiL for more information.\n` + @@ -155,7 +157,7 @@ export function main() { class SomeModule { } - expect(() => resolver.loadNgModuleMetadata(SomeModule, true)) + expect(() => resolver.loadNgModuleDirectiveAndPipeMetadata(SomeModule, true)) .toThrowError(`Expected 'styles' to be an array of strings.`); })); @@ -165,7 +167,7 @@ export function main() { class SomeModule { } - expect(() => resolver.loadNgModuleMetadata(SomeModule, true)) + expect(() => resolver.loadNgModuleDirectiveAndPipeMetadata(SomeModule, true)) .toThrowError(`Can't resolve all parameters for MyBrokenComp1: (?).`); })); it('should throw with descriptive error message when a directive is passed to imports', @@ -173,7 +175,8 @@ export function main() { @NgModule({imports: [ComponentWithoutModuleId]}) class ModuleWithImportedComponent { } - expect(() => resolver.loadNgModuleMetadata(ModuleWithImportedComponent, true)) + expect( + () => resolver.loadNgModuleDirectiveAndPipeMetadata(ModuleWithImportedComponent, true)) .toThrowError( `Unexpected directive 'ComponentWithoutModuleId' imported by the module 'ModuleWithImportedComponent'`); })); @@ -186,7 +189,7 @@ export function main() { @NgModule({imports: [SomePipe]}) class ModuleWithImportedPipe { } - expect(() => resolver.loadNgModuleMetadata(ModuleWithImportedPipe, true)) + expect(() => resolver.loadNgModuleDirectiveAndPipeMetadata(ModuleWithImportedPipe, true)) .toThrowError( `Unexpected pipe 'SomePipe' imported by the module 'ModuleWithImportedPipe'`); })); @@ -199,7 +202,7 @@ export function main() { @NgModule({declarations: [SomeModule]}) class ModuleWithDeclaredModule { } - expect(() => resolver.loadNgModuleMetadata(ModuleWithDeclaredModule, true)) + expect(() => resolver.loadNgModuleDirectiveAndPipeMetadata(ModuleWithDeclaredModule, true)) .toThrowError( `Unexpected module 'SomeModule' declared by the module 'ModuleWithDeclaredModule'`); })); @@ -209,7 +212,7 @@ export function main() { @NgModule({declarations: [null]}) class ModuleWithNullDeclared { } - expect(() => resolver.loadNgModuleMetadata(ModuleWithNullDeclared, true)) + expect(() => resolver.loadNgModuleDirectiveAndPipeMetadata(ModuleWithNullDeclared, true)) .toThrowError( `Unexpected value 'null' declared by the module 'ModuleWithNullDeclared'`); })); @@ -219,7 +222,7 @@ export function main() { @NgModule({imports: [null]}) class ModuleWithNullImported { } - expect(() => resolver.loadNgModuleMetadata(ModuleWithNullImported, true)) + expect(() => resolver.loadNgModuleDirectiveAndPipeMetadata(ModuleWithNullImported, true)) .toThrowError( `Unexpected value 'null' imported by the module 'ModuleWithNullImported'`); })); @@ -231,7 +234,7 @@ export function main() { class SomeModule { } - expect(() => resolver.loadNgModuleMetadata(SomeModule, true)) + expect(() => resolver.loadNgModuleDirectiveAndPipeMetadata(SomeModule, true)) .toThrowError(`Can't resolve all parameters for NonAnnotatedService: (?).`); })); @@ -241,7 +244,7 @@ export function main() { class SomeModule { } - expect(() => resolver.loadNgModuleMetadata(SomeModule, true)) + expect(() => resolver.loadNgModuleDirectiveAndPipeMetadata(SomeModule, true)) .toThrowError( `Invalid providers for "MyBrokenComp3" - only instances of Provider and Type are allowed, got: [SimpleService, ?null?, ...]`); })); @@ -252,7 +255,7 @@ export function main() { class SomeModule { } - expect(() => resolver.loadNgModuleMetadata(SomeModule, true)) + expect(() => resolver.loadNgModuleDirectiveAndPipeMetadata(SomeModule, true)) .toThrowError( `Invalid viewProviders for "MyBrokenComp4" - only instances of Provider and Type are allowed, got: [?null?, ...]`); })); @@ -266,10 +269,12 @@ export function main() { class ModuleWithUndefinedBootstrap { } - expect(() => resolver.loadNgModuleMetadata(ModuleWithNullBootstrap, true)) + expect(() => resolver.loadNgModuleDirectiveAndPipeMetadata(ModuleWithNullBootstrap, true)) .toThrowError( `Unexpected value 'null' used in the bootstrap property of module 'ModuleWithNullBootstrap'`); - expect(() => resolver.loadNgModuleMetadata(ModuleWithUndefinedBootstrap, true)) + expect( + () => + resolver.loadNgModuleDirectiveAndPipeMetadata(ModuleWithUndefinedBootstrap, true)) .toThrowError( `Unexpected value 'undefined' used in the bootstrap property of module 'ModuleWithUndefinedBootstrap'`); })); @@ -280,35 +285,35 @@ export function main() { class Module1 { } - expect(() => resolver.loadNgModuleMetadata(Module1, true)) + expect(() => resolver.loadNgModuleDirectiveAndPipeMetadata(Module1, true)) .toThrowError(`[' ', ' '] contains unusable interpolation symbol.`); @NgModule({declarations: [ComponentWithInvalidInterpolation2]}) class Module2 { } - expect(() => resolver.loadNgModuleMetadata(Module2, true)) + expect(() => resolver.loadNgModuleDirectiveAndPipeMetadata(Module2, true)) .toThrowError(`['{', '}'] contains unusable interpolation symbol.`); @NgModule({declarations: [ComponentWithInvalidInterpolation3]}) class Module3 { } - expect(() => resolver.loadNgModuleMetadata(Module3, true)) + expect(() => resolver.loadNgModuleDirectiveAndPipeMetadata(Module3, true)) .toThrowError(`['<%', '%>'] contains unusable interpolation symbol.`); @NgModule({declarations: [ComponentWithInvalidInterpolation4]}) class Module4 { } - expect(() => resolver.loadNgModuleMetadata(Module4, true)) + expect(() => resolver.loadNgModuleDirectiveAndPipeMetadata(Module4, true)) .toThrowError(`['&#', '}}'] contains unusable interpolation symbol.`); @NgModule({declarations: [ComponentWithInvalidInterpolation5]}) class Module5 { } - expect(() => resolver.loadNgModuleMetadata(Module5, true)) + expect(() => resolver.loadNgModuleDirectiveAndPipeMetadata(Module5, true)) .toThrowError(`['{', '}}'] contains unusable interpolation symbol.`); })); }); @@ -324,7 +329,7 @@ export function main() { class MyModule { } - const modMeta = resolver.loadNgModuleMetadata(MyModule, true).ngModule; + const modMeta = resolver.loadNgModuleDirectiveAndPipeMetadata(MyModule, true).ngModule; expect(modMeta.declaredDirectives.length).toBe(1); expect(modMeta.declaredDirectives[0].reference).toBe(MyComp); }));