refactor(compiler): allows synchronous retrieving of metadata (#12908)
Allows non-normalized metadata to be retrieved synchronously. Related to #7482
This commit is contained in:
parent
8b2dfb2eca
commit
481c9b3258
@ -34,34 +34,34 @@ export class Extractor {
|
|||||||
const programSymbols: StaticSymbol[] =
|
const programSymbols: StaticSymbol[] =
|
||||||
extractProgramSymbols(this.program, this.staticReflector, this.reflectorHost, this.options);
|
extractProgramSymbols(this.program, this.staticReflector, this.reflectorHost, this.options);
|
||||||
|
|
||||||
return compiler
|
const {ngModules, files} = compiler.analyzeAndValidateNgModules(
|
||||||
.analyzeNgModules(programSymbols, {transitiveModules: true}, this.metadataResolver)
|
programSymbols, {transitiveModules: true}, this.metadataResolver);
|
||||||
.then(({files}) => {
|
return compiler.loadNgModuleDirectives(ngModules).then(() => {
|
||||||
const errors: compiler.ParseError[] = [];
|
const errors: compiler.ParseError[] = [];
|
||||||
|
|
||||||
files.forEach(file => {
|
files.forEach(file => {
|
||||||
const compMetas: compiler.CompileDirectiveMetadata[] = [];
|
const compMetas: compiler.CompileDirectiveMetadata[] = [];
|
||||||
file.directives.forEach(directiveType => {
|
file.directives.forEach(directiveType => {
|
||||||
const dirMeta = this.metadataResolver.getDirectiveMetadata(directiveType);
|
const dirMeta = this.metadataResolver.getDirectiveMetadata(directiveType);
|
||||||
if (dirMeta && dirMeta.isComponent) {
|
if (dirMeta && dirMeta.isComponent) {
|
||||||
compMetas.push(dirMeta);
|
compMetas.push(dirMeta);
|
||||||
}
|
|
||||||
});
|
|
||||||
compMetas.forEach(compMeta => {
|
|
||||||
const html = compMeta.template.template;
|
|
||||||
const interpolationConfig =
|
|
||||||
compiler.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;
|
|
||||||
});
|
});
|
||||||
|
compMetas.forEach(compMeta => {
|
||||||
|
const html = compMeta.template.template;
|
||||||
|
const interpolationConfig =
|
||||||
|
compiler.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;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static create(
|
static create(
|
||||||
|
@ -589,7 +589,7 @@ export interface CompileNgModuleDirectiveSummary extends CompileSummary {
|
|||||||
exportedDirectives: CompileIdentifierMetadata[];
|
exportedDirectives: CompileIdentifierMetadata[];
|
||||||
exportedPipes: CompileIdentifierMetadata[];
|
exportedPipes: CompileIdentifierMetadata[];
|
||||||
exportedModules: CompileNgModuleDirectiveSummary[];
|
exportedModules: CompileNgModuleDirectiveSummary[];
|
||||||
loadingPromises: Promise<any>[];
|
directiveLoaders: (() => Promise<void>)[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CompileNgModuleSummary =
|
export type CompileNgModuleSummary =
|
||||||
@ -661,7 +661,7 @@ export class CompileNgModuleMetadata implements CompileMetadataWithIdentifier {
|
|||||||
exportedModules: this.exportedModules,
|
exportedModules: this.exportedModules,
|
||||||
exportedDirectives: this.exportedDirectives,
|
exportedDirectives: this.exportedDirectives,
|
||||||
exportedPipes: this.exportedPipes,
|
exportedPipes: this.exportedPipes,
|
||||||
loadingPromises: this.transitiveModule.loadingPromises
|
directiveLoaders: this.transitiveModule.directiveLoaders
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -682,7 +682,7 @@ export class CompileNgModuleMetadata implements CompileMetadataWithIdentifier {
|
|||||||
exportedDirectives: this.exportedDirectives,
|
exportedDirectives: this.exportedDirectives,
|
||||||
exportedPipes: this.exportedPipes,
|
exportedPipes: this.exportedPipes,
|
||||||
exportedModules: this.exportedModules,
|
exportedModules: this.exportedModules,
|
||||||
loadingPromises: this.transitiveModule.loadingPromises
|
directiveLoaders: this.transitiveModule.directiveLoaders
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -695,7 +695,7 @@ export class TransitiveCompileNgModuleMetadata {
|
|||||||
public modules: CompileNgModuleInjectorSummary[], public providers: CompileProviderMetadata[],
|
public modules: CompileNgModuleInjectorSummary[], public providers: CompileProviderMetadata[],
|
||||||
public entryComponents: CompileIdentifierMetadata[],
|
public entryComponents: CompileIdentifierMetadata[],
|
||||||
public directives: CompileIdentifierMetadata[], public pipes: CompileIdentifierMetadata[],
|
public directives: CompileIdentifierMetadata[], public pipes: CompileIdentifierMetadata[],
|
||||||
public loadingPromises: Promise<any>[]) {
|
public directiveLoaders: (() => Promise<void>)[]) {
|
||||||
directives.forEach(dir => this.directivesSet.add(dir.reference));
|
directives.forEach(dir => this.directivesSet.add(dir.reference));
|
||||||
pipes.forEach(pipe => this.pipesSet.add(pipe.reference));
|
pipes.forEach(pipe => this.pipesSet.add(pipe.reference));
|
||||||
}
|
}
|
||||||
|
@ -146,97 +146,43 @@ export class CompileMetadataResolver {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
directiveType = resolveForwardRef(directiveType);
|
directiveType = resolveForwardRef(directiveType);
|
||||||
const dirMeta = this._directiveResolver.resolve(directiveType);
|
const nonNormalizedMetadata = this.getNonNormalizedDirectiveMetadata(directiveType);
|
||||||
if (!dirMeta) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
let moduleUrl = staticTypeModuleUrl(directiveType);
|
|
||||||
|
|
||||||
const createDirectiveMetadata = (templateMeta: cpl.CompileTemplateMetadata) => {
|
const createDirectiveMetadata = (templateMetadata: cpl.CompileTemplateMetadata) => {
|
||||||
let changeDetectionStrategy: ChangeDetectionStrategy = null;
|
const normalizedDirMeta = new cpl.CompileDirectiveMetadata({
|
||||||
let viewProviders: Array<cpl.CompileProviderMetadata|cpl.CompileTypeMetadata|any[]> = [];
|
type: nonNormalizedMetadata.type,
|
||||||
let entryComponentMetadata: cpl.CompileIdentifierMetadata[] = [];
|
isComponent: nonNormalizedMetadata.isComponent,
|
||||||
let selector = dirMeta.selector;
|
selector: nonNormalizedMetadata.selector,
|
||||||
|
exportAs: nonNormalizedMetadata.exportAs,
|
||||||
if (dirMeta instanceof Component) {
|
changeDetection: nonNormalizedMetadata.changeDetection,
|
||||||
// Component
|
inputs: nonNormalizedMetadata.inputs,
|
||||||
changeDetectionStrategy = dirMeta.changeDetection;
|
outputs: nonNormalizedMetadata.outputs,
|
||||||
if (dirMeta.viewProviders) {
|
hostListeners: nonNormalizedMetadata.hostListeners,
|
||||||
viewProviders = this._getProvidersMetadata(
|
hostProperties: nonNormalizedMetadata.hostProperties,
|
||||||
dirMeta.viewProviders, entryComponentMetadata,
|
hostAttributes: nonNormalizedMetadata.hostAttributes,
|
||||||
`viewProviders for "${stringify(directiveType)}"`);
|
providers: nonNormalizedMetadata.providers,
|
||||||
}
|
viewProviders: nonNormalizedMetadata.viewProviders,
|
||||||
if (dirMeta.entryComponents) {
|
queries: nonNormalizedMetadata.queries,
|
||||||
entryComponentMetadata =
|
viewQueries: nonNormalizedMetadata.viewQueries,
|
||||||
flattenAndDedupeArray(dirMeta.entryComponents)
|
entryComponents: nonNormalizedMetadata.entryComponents,
|
||||||
.map((type) => this._getIdentifierMetadata(type, staticTypeModuleUrl(type)))
|
template: templateMetadata
|
||||||
.concat(entryComponentMetadata);
|
|
||||||
}
|
|
||||||
if (!selector) {
|
|
||||||
selector = this._schemaRegistry.getDefaultComponentElementName();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Directive
|
|
||||||
if (!selector) {
|
|
||||||
throw new Error(`Directive ${stringify(directiveType)} has no selector, please add it!`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let providers: Array<cpl.CompileProviderMetadata|cpl.CompileTypeMetadata|any[]> = [];
|
|
||||||
if (isPresent(dirMeta.providers)) {
|
|
||||||
providers = this._getProvidersMetadata(
|
|
||||||
dirMeta.providers, entryComponentMetadata,
|
|
||||||
`providers for "${stringify(directiveType)}"`);
|
|
||||||
}
|
|
||||||
let queries: cpl.CompileQueryMetadata[] = [];
|
|
||||||
let viewQueries: cpl.CompileQueryMetadata[] = [];
|
|
||||||
if (isPresent(dirMeta.queries)) {
|
|
||||||
queries = this._getQueriesMetadata(dirMeta.queries, false, directiveType);
|
|
||||||
viewQueries = this._getQueriesMetadata(dirMeta.queries, true, directiveType);
|
|
||||||
}
|
|
||||||
|
|
||||||
const meta = cpl.CompileDirectiveMetadata.create({
|
|
||||||
selector: selector,
|
|
||||||
exportAs: dirMeta.exportAs,
|
|
||||||
isComponent: !!templateMeta,
|
|
||||||
type: this._getTypeMetadata(directiveType, moduleUrl),
|
|
||||||
template: templateMeta,
|
|
||||||
changeDetection: changeDetectionStrategy,
|
|
||||||
inputs: dirMeta.inputs,
|
|
||||||
outputs: dirMeta.outputs,
|
|
||||||
host: dirMeta.host,
|
|
||||||
providers: providers,
|
|
||||||
viewProviders: viewProviders,
|
|
||||||
queries: queries,
|
|
||||||
viewQueries: viewQueries,
|
|
||||||
entryComponents: entryComponentMetadata
|
|
||||||
});
|
});
|
||||||
this._directiveCache.set(directiveType, meta);
|
this._directiveCache.set(directiveType, normalizedDirMeta);
|
||||||
this._directiveSummaryCache.set(directiveType, meta.toSummary());
|
this._directiveSummaryCache.set(directiveType, normalizedDirMeta.toSummary());
|
||||||
return meta;
|
return normalizedDirMeta;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (dirMeta instanceof Component) {
|
if (nonNormalizedMetadata.isComponent) {
|
||||||
// component
|
|
||||||
moduleUrl = componentModuleUrl(this._reflector, directiveType, dirMeta);
|
|
||||||
assertArrayOfStrings('styles', dirMeta.styles);
|
|
||||||
assertArrayOfStrings('styleUrls', dirMeta.styleUrls);
|
|
||||||
assertInterpolationSymbols('interpolation', dirMeta.interpolation);
|
|
||||||
|
|
||||||
const animations = dirMeta.animations ?
|
|
||||||
dirMeta.animations.map(e => this.getAnimationEntryMetadata(e)) :
|
|
||||||
null;
|
|
||||||
|
|
||||||
const templateMeta = this._directiveNormalizer.normalizeTemplate({
|
const templateMeta = this._directiveNormalizer.normalizeTemplate({
|
||||||
componentType: directiveType,
|
componentType: directiveType,
|
||||||
moduleUrl: moduleUrl,
|
moduleUrl: nonNormalizedMetadata.type.moduleUrl,
|
||||||
encapsulation: dirMeta.encapsulation,
|
encapsulation: nonNormalizedMetadata.template.encapsulation,
|
||||||
template: dirMeta.template,
|
template: nonNormalizedMetadata.template.template,
|
||||||
templateUrl: dirMeta.templateUrl,
|
templateUrl: nonNormalizedMetadata.template.templateUrl,
|
||||||
styles: dirMeta.styles,
|
styles: nonNormalizedMetadata.template.styles,
|
||||||
styleUrls: dirMeta.styleUrls,
|
styleUrls: nonNormalizedMetadata.template.styleUrls,
|
||||||
animations: animations,
|
animations: nonNormalizedMetadata.template.animations,
|
||||||
interpolation: dirMeta.interpolation
|
interpolation: nonNormalizedMetadata.template.interpolation
|
||||||
});
|
});
|
||||||
if (templateMeta.syncResult) {
|
if (templateMeta.syncResult) {
|
||||||
createDirectiveMetadata(templateMeta.syncResult);
|
createDirectiveMetadata(templateMeta.syncResult);
|
||||||
@ -254,6 +200,96 @@ export class CompileMetadataResolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getNonNormalizedDirectiveMetadata(directiveType: any): cpl.CompileDirectiveMetadata {
|
||||||
|
directiveType = resolveForwardRef(directiveType);
|
||||||
|
const dirMeta = this._directiveResolver.resolve(directiveType);
|
||||||
|
if (!dirMeta) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
let moduleUrl = staticTypeModuleUrl(directiveType);
|
||||||
|
let nonNormalizedTemplateMetadata: cpl.CompileTemplateMetadata;
|
||||||
|
|
||||||
|
if (dirMeta instanceof Component) {
|
||||||
|
// component
|
||||||
|
moduleUrl = componentModuleUrl(this._reflector, directiveType, dirMeta);
|
||||||
|
assertArrayOfStrings('styles', dirMeta.styles);
|
||||||
|
assertArrayOfStrings('styleUrls', dirMeta.styleUrls);
|
||||||
|
assertInterpolationSymbols('interpolation', dirMeta.interpolation);
|
||||||
|
|
||||||
|
const animations = dirMeta.animations ?
|
||||||
|
dirMeta.animations.map(e => this.getAnimationEntryMetadata(e)) :
|
||||||
|
null;
|
||||||
|
|
||||||
|
nonNormalizedTemplateMetadata = new cpl.CompileTemplateMetadata({
|
||||||
|
encapsulation: dirMeta.encapsulation,
|
||||||
|
template: dirMeta.template,
|
||||||
|
templateUrl: dirMeta.templateUrl,
|
||||||
|
styles: dirMeta.styles,
|
||||||
|
styleUrls: dirMeta.styleUrls,
|
||||||
|
animations: animations,
|
||||||
|
interpolation: dirMeta.interpolation
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let changeDetectionStrategy: ChangeDetectionStrategy = null;
|
||||||
|
let viewProviders: Array<cpl.CompileProviderMetadata|cpl.CompileTypeMetadata|any[]> = [];
|
||||||
|
let entryComponentMetadata: cpl.CompileIdentifierMetadata[] = [];
|
||||||
|
let selector = dirMeta.selector;
|
||||||
|
|
||||||
|
if (dirMeta instanceof Component) {
|
||||||
|
// Component
|
||||||
|
changeDetectionStrategy = dirMeta.changeDetection;
|
||||||
|
if (dirMeta.viewProviders) {
|
||||||
|
viewProviders = this._getProvidersMetadata(
|
||||||
|
dirMeta.viewProviders, entryComponentMetadata,
|
||||||
|
`viewProviders for "${stringify(directiveType)}"`);
|
||||||
|
}
|
||||||
|
if (dirMeta.entryComponents) {
|
||||||
|
entryComponentMetadata =
|
||||||
|
flattenAndDedupeArray(dirMeta.entryComponents)
|
||||||
|
.map((type) => this._getIdentifierMetadata(type, staticTypeModuleUrl(type)))
|
||||||
|
.concat(entryComponentMetadata);
|
||||||
|
}
|
||||||
|
if (!selector) {
|
||||||
|
selector = this._schemaRegistry.getDefaultComponentElementName();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Directive
|
||||||
|
if (!selector) {
|
||||||
|
throw new Error(`Directive ${stringify(directiveType)} has no selector, please add it!`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let providers: Array<cpl.CompileProviderMetadata|cpl.CompileTypeMetadata|any[]> = [];
|
||||||
|
if (isPresent(dirMeta.providers)) {
|
||||||
|
providers = this._getProvidersMetadata(
|
||||||
|
dirMeta.providers, entryComponentMetadata, `providers for "${stringify(directiveType)}"`);
|
||||||
|
}
|
||||||
|
let queries: cpl.CompileQueryMetadata[] = [];
|
||||||
|
let viewQueries: cpl.CompileQueryMetadata[] = [];
|
||||||
|
if (isPresent(dirMeta.queries)) {
|
||||||
|
queries = this._getQueriesMetadata(dirMeta.queries, false, directiveType);
|
||||||
|
viewQueries = this._getQueriesMetadata(dirMeta.queries, true, directiveType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cpl.CompileDirectiveMetadata.create({
|
||||||
|
selector: selector,
|
||||||
|
exportAs: dirMeta.exportAs,
|
||||||
|
isComponent: !!nonNormalizedTemplateMetadata,
|
||||||
|
type: this._getTypeMetadata(directiveType, moduleUrl),
|
||||||
|
template: nonNormalizedTemplateMetadata,
|
||||||
|
changeDetection: changeDetectionStrategy,
|
||||||
|
inputs: dirMeta.inputs,
|
||||||
|
outputs: dirMeta.outputs,
|
||||||
|
host: dirMeta.host,
|
||||||
|
providers: providers,
|
||||||
|
viewProviders: viewProviders,
|
||||||
|
queries: queries,
|
||||||
|
viewQueries: viewQueries,
|
||||||
|
entryComponents: entryComponentMetadata
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the metadata for the given directive.
|
* Gets the metadata for the given directive.
|
||||||
* This assumes `loadNgModuleMetadata` has been called first.
|
* This assumes `loadNgModuleMetadata` has been called first.
|
||||||
@ -309,11 +345,20 @@ export class CompileMetadataResolver {
|
|||||||
loadNgModuleMetadata(moduleType: any, isSync: boolean, throwIfNotFound = true):
|
loadNgModuleMetadata(moduleType: any, isSync: boolean, throwIfNotFound = true):
|
||||||
{ngModule: cpl.CompileNgModuleMetadata, loading: Promise<any>} {
|
{ngModule: cpl.CompileNgModuleMetadata, loading: Promise<any>} {
|
||||||
const ngModule = this._loadNgModuleMetadata(moduleType, isSync, throwIfNotFound);
|
const ngModule = this._loadNgModuleMetadata(moduleType, isSync, throwIfNotFound);
|
||||||
const loading =
|
const loading = ngModule ?
|
||||||
ngModule ? Promise.all(ngModule.transitiveModule.loadingPromises) : Promise.resolve(null);
|
Promise.all(ngModule.transitiveModule.directiveLoaders.map(loader => loader())) :
|
||||||
|
Promise.resolve(null);
|
||||||
return {ngModule, loading};
|
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):
|
private _loadNgModuleMetadata(moduleType: any, isSync: boolean, throwIfNotFound = true):
|
||||||
cpl.CompileNgModuleMetadata {
|
cpl.CompileNgModuleMetadata {
|
||||||
moduleType = resolveForwardRef(moduleType);
|
moduleType = resolveForwardRef(moduleType);
|
||||||
@ -396,10 +441,8 @@ export class CompileMetadataResolver {
|
|||||||
transitiveModule.directives.push(declaredIdentifier);
|
transitiveModule.directives.push(declaredIdentifier);
|
||||||
declaredDirectives.push(declaredIdentifier);
|
declaredDirectives.push(declaredIdentifier);
|
||||||
this._addTypeToModule(declaredType, moduleType);
|
this._addTypeToModule(declaredType, moduleType);
|
||||||
const loadingPromise = this._loadDirectiveMetadata(declaredType, isSync);
|
transitiveModule.directiveLoaders.push(
|
||||||
if (loadingPromise) {
|
() => this._loadDirectiveMetadata(declaredType, isSync));
|
||||||
transitiveModule.loadingPromises.push(loadingPromise);
|
|
||||||
}
|
|
||||||
} else if (this._pipeResolver.isPipe(declaredType)) {
|
} else if (this._pipeResolver.isPipe(declaredType)) {
|
||||||
transitiveModule.pipesSet.add(declaredType);
|
transitiveModule.pipesSet.add(declaredType);
|
||||||
transitiveModule.pipes.push(declaredIdentifier);
|
transitiveModule.pipes.push(declaredIdentifier);
|
||||||
@ -525,10 +568,10 @@ export class CompileMetadataResolver {
|
|||||||
const directives =
|
const directives =
|
||||||
flattenArray(transitiveExportedModules.map((ngModule) => ngModule.exportedDirectives));
|
flattenArray(transitiveExportedModules.map((ngModule) => ngModule.exportedDirectives));
|
||||||
const pipes = flattenArray(transitiveExportedModules.map((ngModule) => ngModule.exportedPipes));
|
const pipes = flattenArray(transitiveExportedModules.map((ngModule) => ngModule.exportedPipes));
|
||||||
const loadingPromises =
|
const directiveLoaders =
|
||||||
ListWrapper.flatten(transitiveExportedModules.map(ngModule => ngModule.loadingPromises));
|
ListWrapper.flatten(transitiveExportedModules.map(ngModule => ngModule.directiveLoaders));
|
||||||
return new cpl.TransitiveCompileNgModuleMetadata(
|
return new cpl.TransitiveCompileNgModuleMetadata(
|
||||||
transitiveModules, providers, entryComponents, directives, pipes, loadingPromises);
|
transitiveModules, providers, entryComponents, directives, pipes, directiveLoaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getIdentifierMetadata(type: Type<any>, moduleUrl: string):
|
private _getIdentifierMetadata(type: Type<any>, moduleUrl: string):
|
||||||
@ -584,20 +627,26 @@ export class CompileMetadataResolver {
|
|||||||
return pipeSummary;
|
return pipeSummary;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _loadPipeMetadata(pipeType: Type<any>): void {
|
getOrLoadPipeMetadata(pipeType: any): cpl.CompilePipeMetadata {
|
||||||
pipeType = resolveForwardRef(pipeType);
|
let pipeMeta = this._pipeCache.get(pipeType);
|
||||||
const pipeMeta = this._pipeResolver.resolve(pipeType);
|
|
||||||
if (!pipeMeta) {
|
if (!pipeMeta) {
|
||||||
return null;
|
pipeMeta = this._loadPipeMetadata(pipeType);
|
||||||
}
|
}
|
||||||
|
return pipeMeta;
|
||||||
|
}
|
||||||
|
|
||||||
const meta = new cpl.CompilePipeMetadata({
|
private _loadPipeMetadata(pipeType: any): cpl.CompilePipeMetadata {
|
||||||
|
pipeType = resolveForwardRef(pipeType);
|
||||||
|
const pipeAnnotation = this._pipeResolver.resolve(pipeType);
|
||||||
|
|
||||||
|
const pipeMeta = new cpl.CompilePipeMetadata({
|
||||||
type: this._getTypeMetadata(pipeType, staticTypeModuleUrl(pipeType)),
|
type: this._getTypeMetadata(pipeType, staticTypeModuleUrl(pipeType)),
|
||||||
name: pipeMeta.name,
|
name: pipeAnnotation.name,
|
||||||
pure: pipeMeta.pure
|
pure: pipeAnnotation.pure
|
||||||
});
|
});
|
||||||
this._pipeCache.set(pipeType, meta);
|
this._pipeCache.set(pipeType, pipeMeta);
|
||||||
this._pipeSummaryCache.set(pipeType, meta.toSummary());
|
this._pipeSummaryCache.set(pipeType, pipeMeta.toSummary());
|
||||||
|
return pipeMeta;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getDependenciesMetadata(typeOrFunc: Type<any>|Function, dependencies: any[]):
|
private _getDependenciesMetadata(typeOrFunc: Type<any>|Function, dependencies: any[]):
|
||||||
|
@ -27,17 +27,46 @@ export class SourceModule {
|
|||||||
constructor(public fileUrl: string, public moduleUrl: string, public source: string) {}
|
constructor(public fileUrl: string, public moduleUrl: string, public source: string) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface NgAnalyzedModules {
|
||||||
|
ngModules: CompileNgModuleMetadata[];
|
||||||
|
ngModuleByPipeOrDirective: Map<StaticSymbol, CompileNgModuleMetadata>;
|
||||||
|
files: Array<{srcUrl: string, directives: StaticSymbol[], ngModules: StaticSymbol[]}>;
|
||||||
|
symbolsMissingModule?: StaticSymbol[];
|
||||||
|
}
|
||||||
|
|
||||||
// Returns all the source files and a mapping from modules to directives
|
// Returns all the source files and a mapping from modules to directives
|
||||||
export function analyzeNgModules(
|
export function analyzeNgModules(
|
||||||
programStaticSymbols: StaticSymbol[], options: {transitiveModules: boolean},
|
programStaticSymbols: StaticSymbol[], options: {transitiveModules: boolean},
|
||||||
metadataResolver: CompileMetadataResolver): Promise<{
|
metadataResolver: CompileMetadataResolver): NgAnalyzedModules {
|
||||||
ngModuleByPipeOrDirective: Map<StaticSymbol, CompileNgModuleMetadata>,
|
const {ngModules, symbolsMissingModule} =
|
||||||
files: Array<{srcUrl: string, directives: StaticSymbol[], ngModules: StaticSymbol[]}>
|
_createNgModules(programStaticSymbols, options, metadataResolver);
|
||||||
}> {
|
return _analyzeNgModules(ngModules, symbolsMissingModule);
|
||||||
return _loadNgModules(programStaticSymbols, options, metadataResolver).then(_analyzeNgModules);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function _analyzeNgModules(ngModuleMetas: CompileNgModuleMetadata[]) {
|
|
||||||
|
export function analyzeAndValidateNgModules(
|
||||||
|
programStaticSymbols: StaticSymbol[], options: {transitiveModules: boolean},
|
||||||
|
metadataResolver: CompileMetadataResolver): NgAnalyzedModules {
|
||||||
|
const result = analyzeNgModules(programStaticSymbols, options, metadataResolver);
|
||||||
|
if (result.symbolsMissingModule && result.symbolsMissingModule.length) {
|
||||||
|
const messages = result.symbolsMissingModule.map(
|
||||||
|
s => `Cannot determine the module for class ${s.name} in ${s.filePath}!`);
|
||||||
|
throw new Error(messages.join('\n'));
|
||||||
|
}
|
||||||
|
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 {
|
||||||
const moduleMetasByRef = new Map<any, CompileNgModuleMetadata>();
|
const moduleMetasByRef = new Map<any, CompileNgModuleMetadata>();
|
||||||
ngModuleMetas.forEach((ngModule) => moduleMetasByRef.set(ngModule.type.reference, ngModule));
|
ngModuleMetas.forEach((ngModule) => moduleMetasByRef.set(ngModule.type.reference, ngModule));
|
||||||
const ngModuleByPipeOrDirective = new Map<StaticSymbol, CompileNgModuleMetadata>();
|
const ngModuleByPipeOrDirective = new Map<StaticSymbol, CompileNgModuleMetadata>();
|
||||||
@ -78,10 +107,11 @@ function _analyzeNgModules(ngModuleMetas: CompileNgModuleMetadata[]) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// map directive/pipe to module
|
// map directive/pipe to module
|
||||||
ngModuleByPipeOrDirective,
|
ngModuleByPipeOrDirective,
|
||||||
// list modules and directives for every source file
|
// list modules and directives for every source file
|
||||||
files,
|
files,
|
||||||
|
ngModules: ngModuleMetas, symbolsMissingModule
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,13 +130,14 @@ export class OfflineCompiler {
|
|||||||
|
|
||||||
compileModules(staticSymbols: StaticSymbol[], options: {transitiveModules: boolean}):
|
compileModules(staticSymbols: StaticSymbol[], options: {transitiveModules: boolean}):
|
||||||
Promise<SourceModule[]> {
|
Promise<SourceModule[]> {
|
||||||
return analyzeNgModules(staticSymbols, options, this._metadataResolver)
|
const {ngModuleByPipeOrDirective, files, ngModules} =
|
||||||
.then(({ngModuleByPipeOrDirective, files}) => {
|
analyzeAndValidateNgModules(staticSymbols, options, this._metadataResolver);
|
||||||
const sourceModules = files.map(
|
return loadNgModuleDirectives(ngModules).then(() => {
|
||||||
file => this._compileSrcFile(
|
const sourceModules = files.map(
|
||||||
file.srcUrl, ngModuleByPipeOrDirective, file.directives, file.ngModules));
|
file => this._compileSrcFile(
|
||||||
return ListWrapper.flatten(sourceModules);
|
file.srcUrl, ngModuleByPipeOrDirective, file.directives, file.ngModules));
|
||||||
});
|
return ListWrapper.flatten(sourceModules);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _compileSrcFile(
|
private _compileSrcFile(
|
||||||
@ -328,22 +359,21 @@ function _splitTypescriptSuffix(path: string): string[] {
|
|||||||
// Load the NgModules and check
|
// Load the NgModules and check
|
||||||
// that all directives / pipes that are present in the program
|
// that all directives / pipes that are present in the program
|
||||||
// are also declared by a module.
|
// are also declared by a module.
|
||||||
function _loadNgModules(
|
function _createNgModules(
|
||||||
programStaticSymbols: StaticSymbol[], options: {transitiveModules: boolean},
|
programStaticSymbols: StaticSymbol[], options: {transitiveModules: boolean},
|
||||||
metadataResolver: CompileMetadataResolver): Promise<CompileNgModuleMetadata[]> {
|
metadataResolver: CompileMetadataResolver):
|
||||||
|
{ngModules: CompileNgModuleMetadata[], symbolsMissingModule: StaticSymbol[]} {
|
||||||
const ngModules = new Map<any, CompileNgModuleMetadata>();
|
const ngModules = new Map<any, CompileNgModuleMetadata>();
|
||||||
const programPipesAndDirectives: StaticSymbol[] = [];
|
const programPipesAndDirectives: StaticSymbol[] = [];
|
||||||
const ngModulePipesAndDirective = new Set<StaticSymbol>();
|
const ngModulePipesAndDirective = new Set<StaticSymbol>();
|
||||||
const loadingPromises: Promise<any>[] = [];
|
|
||||||
|
|
||||||
const addNgModule = (staticSymbol: any) => {
|
const addNgModule = (staticSymbol: any) => {
|
||||||
if (ngModules.has(staticSymbol)) {
|
if (ngModules.has(staticSymbol)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const {ngModule, loading} = metadataResolver.loadNgModuleMetadata(staticSymbol, false, false);
|
const ngModule = metadataResolver.getUnloadedNgModuleMetadata(staticSymbol, false, false);
|
||||||
if (ngModule) {
|
if (ngModule) {
|
||||||
ngModules.set(ngModule.type.reference, ngModule);
|
ngModules.set(ngModule.type.reference, ngModule);
|
||||||
loadingPromises.push(loading);
|
|
||||||
ngModule.declaredDirectives.forEach((dir) => ngModulePipesAndDirective.add(dir.reference));
|
ngModule.declaredDirectives.forEach((dir) => ngModulePipesAndDirective.add(dir.reference));
|
||||||
ngModule.declaredPipes.forEach((pipe) => ngModulePipesAndDirective.add(pipe.reference));
|
ngModule.declaredPipes.forEach((pipe) => ngModulePipesAndDirective.add(pipe.reference));
|
||||||
if (options.transitiveModules) {
|
if (options.transitiveModules) {
|
||||||
@ -364,11 +394,5 @@ function _loadNgModules(
|
|||||||
const symbolsMissingModule =
|
const symbolsMissingModule =
|
||||||
programPipesAndDirectives.filter(s => !ngModulePipesAndDirective.has(s));
|
programPipesAndDirectives.filter(s => !ngModulePipesAndDirective.has(s));
|
||||||
|
|
||||||
if (symbolsMissingModule.length) {
|
return {ngModules: Array.from(ngModules.values()), symbolsMissingModule};
|
||||||
const messages = symbolsMissingModule.map(
|
|
||||||
s => `Cannot determine the module for class ${s.name} in ${s.filePath}!`);
|
|
||||||
throw new Error(messages.join('\n'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.all(loadingPromises).then(() => Array.from(ngModules.values()));
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user