refactor(compiler): introduce summaries for metadata (#12799)
This does not yet introduce loading / serialization of summaries. Part of #12787
This commit is contained in:
parent
ef881475e9
commit
fcb4e66493
|
@ -98,6 +98,15 @@ export class CompileIdentifierMetadata implements CompileMetadataWithIdentifier
|
|||
get identifier(): CompileIdentifierMetadata { return this; }
|
||||
}
|
||||
|
||||
/**
|
||||
* A CompileSummary is the data needed to use a directive / pipe / module
|
||||
* in other modules / components. However, this data is not enough to compile
|
||||
* the directive / module itself.
|
||||
*/
|
||||
export interface CompileSummary {
|
||||
isSummary: boolean /* TODO: `true` when we drop TS 1.8 support */;
|
||||
}
|
||||
|
||||
export class CompileDiDependencyMetadata {
|
||||
isAttribute: boolean;
|
||||
isSelf: boolean;
|
||||
|
@ -264,6 +273,16 @@ export class CompileStylesheetMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Summary Metadata regarding compilation of a template.
|
||||
*/
|
||||
export interface CompileTemplateSummary extends CompileSummary {
|
||||
isSummary: boolean /* TODO: `true` when we drop TS 1.8 support */;
|
||||
animations: string[];
|
||||
ngContentSelectors: string[];
|
||||
encapsulation: ViewEncapsulation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Metadata regarding compilation of a template.
|
||||
*/
|
||||
|
@ -303,6 +322,34 @@ export class CompileTemplateMetadata {
|
|||
}
|
||||
this.interpolation = interpolation;
|
||||
}
|
||||
|
||||
toSummary(): CompileTemplateSummary {
|
||||
return {
|
||||
isSummary: true,
|
||||
animations: this.animations.map(anim => anim.name),
|
||||
ngContentSelectors: this.ngContentSelectors,
|
||||
encapsulation: this.encapsulation
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export interface CompileDirectiveSummary extends CompileSummary {
|
||||
isSummary: boolean /* TODO: `true` when we drop TS 1.8 support */;
|
||||
type: CompileTypeMetadata;
|
||||
isComponent: boolean;
|
||||
selector: string;
|
||||
exportAs: string;
|
||||
inputs: {[key: string]: string};
|
||||
outputs: {[key: string]: string};
|
||||
hostListeners: {[key: string]: string};
|
||||
hostProperties: {[key: string]: string};
|
||||
hostAttributes: {[key: string]: string};
|
||||
providers: CompileProviderMetadata[];
|
||||
viewProviders: CompileProviderMetadata[];
|
||||
queries: CompileQueryMetadata[];
|
||||
entryComponents: CompileIdentifierMetadata[];
|
||||
changeDetection: ChangeDetectionStrategy;
|
||||
template: CompileTemplateSummary;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -394,7 +441,6 @@ export class CompileDirectiveMetadata implements CompileMetadataWithIdentifier {
|
|||
viewProviders: CompileProviderMetadata[];
|
||||
queries: CompileQueryMetadata[];
|
||||
viewQueries: CompileQueryMetadata[];
|
||||
// Note: Need to keep types here to prevent cycles!
|
||||
entryComponents: CompileIdentifierMetadata[];
|
||||
|
||||
template: CompileTemplateMetadata;
|
||||
|
@ -442,6 +488,27 @@ export class CompileDirectiveMetadata implements CompileMetadataWithIdentifier {
|
|||
}
|
||||
|
||||
get identifier(): CompileIdentifierMetadata { return this.type; }
|
||||
|
||||
toSummary(): CompileDirectiveSummary {
|
||||
return {
|
||||
isSummary: true,
|
||||
type: this.type,
|
||||
isComponent: this.isComponent,
|
||||
selector: this.selector,
|
||||
exportAs: this.exportAs,
|
||||
inputs: this.inputs,
|
||||
outputs: this.outputs,
|
||||
hostListeners: this.hostListeners,
|
||||
hostProperties: this.hostProperties,
|
||||
hostAttributes: this.hostAttributes,
|
||||
providers: this.providers,
|
||||
viewProviders: this.viewProviders,
|
||||
queries: this.queries,
|
||||
entryComponents: this.entryComponents,
|
||||
changeDetection: this.changeDetection,
|
||||
template: this.template && this.template.toSummary()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -479,6 +546,12 @@ export function createHostComponentMeta(compMeta: CompileDirectiveMetadata):
|
|||
});
|
||||
}
|
||||
|
||||
export interface CompilePipeSummary extends CompileSummary {
|
||||
isSummary: boolean /* TODO: `true` when we drop TS 1.8 support */;
|
||||
type: CompileTypeMetadata;
|
||||
name: string;
|
||||
pure: boolean;
|
||||
}
|
||||
|
||||
export class CompilePipeMetadata implements CompileMetadataWithIdentifier {
|
||||
type: CompileTypeMetadata;
|
||||
|
@ -495,8 +568,33 @@ export class CompilePipeMetadata implements CompileMetadataWithIdentifier {
|
|||
this.pure = !!pure;
|
||||
}
|
||||
get identifier(): CompileIdentifierMetadata { return this.type; }
|
||||
|
||||
toSummary(): CompilePipeSummary {
|
||||
return {isSummary: true, type: this.type, name: this.name, pure: this.pure};
|
||||
}
|
||||
}
|
||||
|
||||
export interface CompileNgModuleInjectorSummary extends CompileSummary {
|
||||
isSummary: boolean /* TODO: `true` when we drop TS 1.8 support */;
|
||||
type: CompileTypeMetadata;
|
||||
entryComponents: CompileIdentifierMetadata[];
|
||||
providers: CompileProviderMetadata[];
|
||||
importedModules: CompileNgModuleInjectorSummary[];
|
||||
exportedModules: CompileNgModuleInjectorSummary[];
|
||||
}
|
||||
|
||||
export interface CompileNgModuleDirectiveSummary extends CompileSummary {
|
||||
isSummary: boolean /* TODO: `true` when we drop TS 1.8 support */;
|
||||
type: CompileTypeMetadata;
|
||||
exportedDirectives: CompileIdentifierMetadata[];
|
||||
exportedPipes: CompileIdentifierMetadata[];
|
||||
exportedModules: CompileNgModuleDirectiveSummary[];
|
||||
loadingPromises: Promise<any>[];
|
||||
}
|
||||
|
||||
export type CompileNgModuleSummary =
|
||||
CompileNgModuleInjectorSummary & CompileNgModuleDirectiveSummary;
|
||||
|
||||
/**
|
||||
* Metadata regarding compilation of a module.
|
||||
*/
|
||||
|
@ -506,13 +604,12 @@ export class CompileNgModuleMetadata implements CompileMetadataWithIdentifier {
|
|||
exportedDirectives: CompileIdentifierMetadata[];
|
||||
declaredPipes: CompileIdentifierMetadata[];
|
||||
exportedPipes: CompileIdentifierMetadata[];
|
||||
// Note: See CompileDirectiveMetadata.entryComponents why this has to be a type.
|
||||
entryComponents: CompileIdentifierMetadata[];
|
||||
bootstrapComponents: CompileIdentifierMetadata[];
|
||||
providers: CompileProviderMetadata[];
|
||||
|
||||
importedModules: CompileNgModuleMetadata[];
|
||||
exportedModules: CompileNgModuleMetadata[];
|
||||
importedModules: CompileNgModuleSummary[];
|
||||
exportedModules: CompileNgModuleSummary[];
|
||||
schemas: SchemaMetadata[];
|
||||
id: string;
|
||||
|
||||
|
@ -531,8 +628,8 @@ export class CompileNgModuleMetadata implements CompileMetadataWithIdentifier {
|
|||
exportedPipes?: CompileIdentifierMetadata[],
|
||||
entryComponents?: CompileIdentifierMetadata[],
|
||||
bootstrapComponents?: CompileIdentifierMetadata[],
|
||||
importedModules?: CompileNgModuleMetadata[],
|
||||
exportedModules?: CompileNgModuleMetadata[],
|
||||
importedModules?: CompileNgModuleSummary[],
|
||||
exportedModules?: CompileNgModuleSummary[],
|
||||
transitiveModule?: TransitiveCompileNgModuleMetadata,
|
||||
schemas?: SchemaMetadata[],
|
||||
id?: string
|
||||
|
@ -553,6 +650,41 @@ export class CompileNgModuleMetadata implements CompileMetadataWithIdentifier {
|
|||
}
|
||||
|
||||
get identifier(): CompileIdentifierMetadata { return this.type; }
|
||||
|
||||
toSummary(): CompileNgModuleSummary {
|
||||
return {
|
||||
isSummary: true,
|
||||
type: this.type,
|
||||
entryComponents: this.entryComponents,
|
||||
providers: this.providers,
|
||||
importedModules: this.importedModules,
|
||||
exportedModules: this.exportedModules,
|
||||
exportedDirectives: this.exportedDirectives,
|
||||
exportedPipes: this.exportedPipes,
|
||||
loadingPromises: this.transitiveModule.loadingPromises
|
||||
};
|
||||
}
|
||||
|
||||
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,
|
||||
loadingPromises: this.transitiveModule.loadingPromises
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class TransitiveCompileNgModuleMetadata {
|
||||
|
@ -560,7 +692,7 @@ export class TransitiveCompileNgModuleMetadata {
|
|||
pipesSet = new Set<any>();
|
||||
|
||||
constructor(
|
||||
public modules: CompileNgModuleMetadata[], public providers: CompileProviderMetadata[],
|
||||
public modules: CompileNgModuleInjectorSummary[], public providers: CompileProviderMetadata[],
|
||||
public entryComponents: CompileIdentifierMetadata[],
|
||||
public directives: CompileIdentifierMetadata[], public pipes: CompileIdentifierMetadata[],
|
||||
public loadingPromises: Promise<any>[]) {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
import {Injectable} from '@angular/core';
|
||||
|
||||
import {CompileDirectiveMetadata, CompileIdentifierMetadata} from './compile_metadata';
|
||||
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompileIdentifierMetadata} from './compile_metadata';
|
||||
import {createCheckBindingField, createCheckBindingStmt} from './compiler_util/binding_util';
|
||||
import {EventHandlerVars, convertActionBinding, convertPropertyBinding} from './compiler_util/expression_converter';
|
||||
import {triggerAnimation, writeToRenderer} from './compiler_util/render_util';
|
||||
|
@ -355,8 +355,8 @@ function parseHostBindings(
|
|||
const sourceSpan = new ParseSourceSpan(
|
||||
new ParseLocation(sourceFile, null, null, null),
|
||||
new ParseLocation(sourceFile, null, null, null));
|
||||
const parsedHostProps = parser.createDirectiveHostPropertyAsts(dirMeta, sourceSpan);
|
||||
const parsedHostListeners = parser.createDirectiveHostEventAsts(dirMeta, sourceSpan);
|
||||
const parsedHostProps = parser.createDirectiveHostPropertyAsts(dirMeta.toSummary(), sourceSpan);
|
||||
const parsedHostListeners = parser.createDirectiveHostEventAsts(dirMeta.toSummary(), sourceSpan);
|
||||
|
||||
return new ParseResult(parsedHostProps, parsedHostListeners, errors);
|
||||
}
|
||||
|
@ -418,7 +418,7 @@ export class DirectiveWrapperExpressions {
|
|||
return [];
|
||||
}
|
||||
}
|
||||
static ngOnDestroy(dir: CompileDirectiveMetadata, dirWrapper: o.Expression): o.Statement[] {
|
||||
static ngOnDestroy(dir: CompileDirectiveSummary, dirWrapper: o.Expression): o.Statement[] {
|
||||
if (dir.type.lifecycleHooks.indexOf(LifecycleHooks.OnDestroy) !== -1 ||
|
||||
Object.keys(dir.outputs).length > 0) {
|
||||
return [dirWrapper.callMethod('ngOnDestroy', []).toStmt()];
|
||||
|
@ -427,7 +427,7 @@ export class DirectiveWrapperExpressions {
|
|||
}
|
||||
}
|
||||
static subscribe(
|
||||
dirMeta: CompileDirectiveMetadata, hostProps: BoundElementPropertyAst[], usedEvents: string[],
|
||||
dirMeta: CompileDirectiveSummary, hostProps: BoundElementPropertyAst[], usedEvents: string[],
|
||||
dirWrapper: o.Expression, view: o.Expression, eventListener: o.Expression): o.Statement[] {
|
||||
let needsSubscribe = false;
|
||||
let eventFlags: o.Expression[] = [];
|
||||
|
|
|
@ -12,7 +12,7 @@ import {assertArrayOfStrings, assertInterpolationSymbols} from './assertions';
|
|||
import * as cpl from './compile_metadata';
|
||||
import {DirectiveNormalizer} from './directive_normalizer';
|
||||
import {DirectiveResolver} from './directive_resolver';
|
||||
import {ListWrapper} from './facade/collection';
|
||||
import {ListWrapper, StringMapWrapper} from './facade/collection';
|
||||
import {isBlank, isPresent, stringify} from './facade/lang';
|
||||
import {Identifiers, resolveIdentifierToken} from './identifiers';
|
||||
import {hasLifecycleHook} from './lifecycle_reflector';
|
||||
|
@ -24,6 +24,7 @@ import {getUrlScheme} from './url_resolver';
|
|||
import {MODULE_SUFFIX, SyncAsyncResult, ValueTransformer, sanitizeIdentifier, visitValue} from './util';
|
||||
|
||||
|
||||
|
||||
// Design notes:
|
||||
// - don't lazily create metadata:
|
||||
// For some metadata, we need to do async work sometimes,
|
||||
|
@ -34,7 +35,9 @@ import {MODULE_SUFFIX, SyncAsyncResult, ValueTransformer, sanitizeIdentifier, vi
|
|||
@Injectable()
|
||||
export class CompileMetadataResolver {
|
||||
private _directiveCache = new Map<Type<any>, cpl.CompileDirectiveMetadata>();
|
||||
private _directiveSummaryCache = new Map<Type<any>, cpl.CompileDirectiveSummary>();
|
||||
private _pipeCache = new Map<Type<any>, cpl.CompilePipeMetadata>();
|
||||
private _pipeSummaryCache = new Map<Type<any>, cpl.CompilePipeSummary>();
|
||||
private _ngModuleCache = new Map<Type<any>, cpl.CompileNgModuleMetadata>();
|
||||
private _ngModuleOfTypes = new Map<Type<any>, Type<any>>();
|
||||
private _anonymousTypes = new Map<Object, number>();
|
||||
|
@ -63,7 +66,9 @@ export class CompileMetadataResolver {
|
|||
clearCacheFor(type: Type<any>) {
|
||||
const dirMeta = this._directiveCache.get(type);
|
||||
this._directiveCache.delete(type);
|
||||
this._directiveSummaryCache.delete(type);
|
||||
this._pipeCache.delete(type);
|
||||
this._pipeSummaryCache.delete(type);
|
||||
this._ngModuleOfTypes.delete(type);
|
||||
// Clear all of the NgModule as they contain transitive information!
|
||||
this._ngModuleCache.clear();
|
||||
|
@ -74,7 +79,9 @@ export class CompileMetadataResolver {
|
|||
|
||||
clearCache() {
|
||||
this._directiveCache.clear();
|
||||
this._directiveSummaryCache.clear();
|
||||
this._pipeCache.clear();
|
||||
this._pipeSummaryCache.clear();
|
||||
this._ngModuleCache.clear();
|
||||
this._ngModuleOfTypes.clear();
|
||||
this._directiveNormalizer.clearCache();
|
||||
|
@ -205,6 +212,7 @@ export class CompileMetadataResolver {
|
|||
entryComponents: entryComponentMetadata
|
||||
});
|
||||
this._directiveCache.set(directiveType, meta);
|
||||
this._directiveSummaryCache.set(directiveType, meta.toSummary());
|
||||
return meta;
|
||||
};
|
||||
|
||||
|
@ -259,6 +267,15 @@ export class CompileMetadataResolver {
|
|||
return dirMeta;
|
||||
}
|
||||
|
||||
getDirectiveSummary(dirType: any): cpl.CompileDirectiveSummary {
|
||||
const dirSummary = this._directiveSummaryCache.get(dirType);
|
||||
if (!dirSummary) {
|
||||
throw new Error(
|
||||
`Illegal state: getDirectiveSummary can only be called after loadNgModuleMetadata for a module that imports it. Directive ${stringify(dirType)}.`);
|
||||
}
|
||||
return dirSummary;
|
||||
}
|
||||
|
||||
isDirective(type: any) { return this._directiveResolver.isDirective(type); }
|
||||
|
||||
isPipe(type: any) { return this._pipeResolver.isPipe(type); }
|
||||
|
@ -276,6 +293,14 @@ export class CompileMetadataResolver {
|
|||
return modMeta;
|
||||
}
|
||||
|
||||
private _loadNgModuleSummary(moduleType: any, isSync: boolean): 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);
|
||||
return moduleMeta ? moduleMeta.toSummary() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an NgModule and all of its directives. This includes loading the exported directives of
|
||||
* imported modules,
|
||||
|
@ -301,11 +326,10 @@ export class CompileMetadataResolver {
|
|||
return null;
|
||||
}
|
||||
const declaredDirectives: cpl.CompileIdentifierMetadata[] = [];
|
||||
const exportedDirectives: cpl.CompileIdentifierMetadata[] = [];
|
||||
const exportedNonModuleIdentifiers: cpl.CompileIdentifierMetadata[] = [];
|
||||
const declaredPipes: cpl.CompileIdentifierMetadata[] = [];
|
||||
const exportedPipes: cpl.CompileIdentifierMetadata[] = [];
|
||||
const importedModules: cpl.CompileNgModuleMetadata[] = [];
|
||||
const exportedModules: cpl.CompileNgModuleMetadata[] = [];
|
||||
const importedModules: cpl.CompileNgModuleSummary[] = [];
|
||||
const exportedModules: cpl.CompileNgModuleSummary[] = [];
|
||||
const providers: any[] = [];
|
||||
const entryComponents: cpl.CompileIdentifierMetadata[] = [];
|
||||
const bootstrapComponents: cpl.CompileIdentifierMetadata[] = [];
|
||||
|
@ -327,12 +351,12 @@ export class CompileMetadataResolver {
|
|||
}
|
||||
|
||||
if (importedModuleType) {
|
||||
const importedMeta = this._loadNgModuleMetadata(importedModuleType, isSync, false);
|
||||
if (importedMeta === null) {
|
||||
const importedModuleSummary = this._loadNgModuleSummary(importedModuleType, isSync);
|
||||
if (!importedModuleSummary) {
|
||||
throw new Error(
|
||||
`Unexpected ${this._getTypeDescriptor(importedType)} '${stringify(importedType)}' imported by the module '${stringify(moduleType)}'`);
|
||||
}
|
||||
importedModules.push(importedMeta);
|
||||
importedModules.push(importedModuleSummary);
|
||||
} else {
|
||||
throw new Error(
|
||||
`Unexpected value '${stringify(importedType)}' imported by the module '${stringify(moduleType)}'`);
|
||||
|
@ -346,18 +370,12 @@ export class CompileMetadataResolver {
|
|||
throw new Error(
|
||||
`Unexpected value '${stringify(exportedType)}' exported by the module '${stringify(moduleType)}'`);
|
||||
}
|
||||
let identifier =
|
||||
this._getIdentifierMetadata(exportedType, staticTypeModuleUrl(exportedType));
|
||||
let exportedModuleMeta: cpl.CompileNgModuleMetadata;
|
||||
if (this._directiveResolver.isDirective(exportedType)) {
|
||||
exportedDirectives.push(identifier);
|
||||
} else if (this._pipeResolver.isPipe(exportedType)) {
|
||||
exportedPipes.push(identifier);
|
||||
} else if (exportedModuleMeta = this._loadNgModuleMetadata(exportedType, isSync, false)) {
|
||||
exportedModules.push(exportedModuleMeta);
|
||||
const exportedModuleSummary = this._loadNgModuleSummary(exportedType, isSync);
|
||||
if (exportedModuleSummary) {
|
||||
exportedModules.push(exportedModuleSummary);
|
||||
} else {
|
||||
throw new Error(
|
||||
`Unexpected ${this._getTypeDescriptor(exportedType)} '${stringify(exportedType)}' exported by the module '${stringify(moduleType)}'`);
|
||||
exportedNonModuleIdentifiers.push(
|
||||
this._getIdentifierMetadata(exportedType, staticTypeModuleUrl(exportedType)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -395,6 +413,19 @@ export class CompileMetadataResolver {
|
|||
});
|
||||
}
|
||||
|
||||
const exportedDirectives: cpl.CompileIdentifierMetadata[] = [];
|
||||
const exportedPipes: cpl.CompileIdentifierMetadata[] = [];
|
||||
exportedNonModuleIdentifiers.forEach((exportedId) => {
|
||||
if (transitiveModule.directivesSet.has(exportedId.reference)) {
|
||||
exportedDirectives.push(exportedId);
|
||||
} else if (transitiveModule.pipesSet.has(exportedId.reference)) {
|
||||
exportedPipes.push(exportedId);
|
||||
} else {
|
||||
throw new Error(
|
||||
`Can't export ${this._getTypeDescriptor(exportedId.reference)} ${stringify(exportedId.reference)} from ${stringify(moduleType)} as it was neither declared nor imported!`);
|
||||
}
|
||||
});
|
||||
|
||||
// The providers of the module have to go last
|
||||
// so that they overwrite any other provider we already added.
|
||||
if (meta.providers) {
|
||||
|
@ -444,29 +475,11 @@ export class CompileMetadataResolver {
|
|||
id: meta.id,
|
||||
});
|
||||
|
||||
transitiveModule.modules.push(compileMeta);
|
||||
this._verifyModule(compileMeta);
|
||||
transitiveModule.modules.push(compileMeta.toInjectorSummary());
|
||||
this._ngModuleCache.set(moduleType, compileMeta);
|
||||
return compileMeta;
|
||||
}
|
||||
|
||||
|
||||
private _verifyModule(moduleMeta: cpl.CompileNgModuleMetadata) {
|
||||
moduleMeta.exportedDirectives.forEach((dirIdentifier) => {
|
||||
if (!moduleMeta.transitiveModule.directivesSet.has(dirIdentifier.reference)) {
|
||||
throw new Error(
|
||||
`Can't export directive ${stringify(dirIdentifier.reference)} from ${stringify(moduleMeta.type.reference)} as it was neither declared nor imported!`);
|
||||
}
|
||||
});
|
||||
|
||||
moduleMeta.exportedPipes.forEach((pipeIdentifier) => {
|
||||
if (!moduleMeta.transitiveModule.pipesSet.has(pipeIdentifier.reference)) {
|
||||
throw new Error(
|
||||
`Can't export pipe ${stringify(pipeIdentifier.reference)} from ${stringify(moduleMeta.type.reference)} as it was neither declared nor imported!`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private _getTypeDescriptor(type: Type<any>): string {
|
||||
if (this._directiveResolver.isDirective(type)) {
|
||||
return 'directive';
|
||||
|
@ -500,20 +513,20 @@ export class CompileMetadataResolver {
|
|||
}
|
||||
|
||||
private _getTransitiveNgModuleMetadata(
|
||||
importedModules: cpl.CompileNgModuleMetadata[],
|
||||
exportedModules: cpl.CompileNgModuleMetadata[]): cpl.TransitiveCompileNgModuleMetadata {
|
||||
importedModules: cpl.CompileNgModuleSummary[],
|
||||
exportedModules: cpl.CompileNgModuleSummary[]): cpl.TransitiveCompileNgModuleMetadata {
|
||||
// collect `providers` / `entryComponents` from all imported and all exported modules
|
||||
const transitiveModules = getTransitiveModules(importedModules.concat(exportedModules), true);
|
||||
const transitiveModules = getTransitiveImportedModules(importedModules.concat(exportedModules));
|
||||
const providers = flattenArray(transitiveModules.map((ngModule) => ngModule.providers));
|
||||
const entryComponents =
|
||||
flattenArray(transitiveModules.map((ngModule) => ngModule.entryComponents));
|
||||
|
||||
const transitiveExportedModules = getTransitiveModules(importedModules, false);
|
||||
const transitiveExportedModules = getTransitiveExportedModules(importedModules);
|
||||
const directives =
|
||||
flattenArray(transitiveExportedModules.map((ngModule) => ngModule.exportedDirectives));
|
||||
const pipes = flattenArray(transitiveExportedModules.map((ngModule) => ngModule.exportedPipes));
|
||||
const loadingPromises = ListWrapper.flatten(
|
||||
transitiveExportedModules.map(ngModule => ngModule.transitiveModule.loadingPromises));
|
||||
const loadingPromises =
|
||||
ListWrapper.flatten(transitiveExportedModules.map(ngModule => ngModule.loadingPromises));
|
||||
return new cpl.TransitiveCompileNgModuleMetadata(
|
||||
transitiveModules, providers, entryComponents, directives, pipes, loadingPromises);
|
||||
}
|
||||
|
@ -562,6 +575,15 @@ export class CompileMetadataResolver {
|
|||
return pipeMeta;
|
||||
}
|
||||
|
||||
getPipeSummary(pipeType: any): cpl.CompilePipeSummary {
|
||||
const pipeSummary = this._pipeSummaryCache.get(pipeType);
|
||||
if (!pipeSummary) {
|
||||
throw new Error(
|
||||
`Illegal state: getPipeSummary can only be called after loadNgModuleMetadata for a module that imports it. Pipe ${stringify(pipeType)}.`);
|
||||
}
|
||||
return pipeSummary;
|
||||
}
|
||||
|
||||
private _loadPipeMetadata(pipeType: Type<any>): void {
|
||||
pipeType = resolveForwardRef(pipeType);
|
||||
const pipeMeta = this._pipeResolver.resolve(pipeType);
|
||||
|
@ -575,6 +597,7 @@ export class CompileMetadataResolver {
|
|||
pure: pipeMeta.pure
|
||||
});
|
||||
this._pipeCache.set(pipeType, meta);
|
||||
this._pipeSummaryCache.set(pipeType, meta.toSummary());
|
||||
}
|
||||
|
||||
private _getDependenciesMetadata(typeOrFunc: Type<any>|Function, dependencies: any[]):
|
||||
|
@ -790,17 +813,31 @@ export class CompileMetadataResolver {
|
|||
}
|
||||
}
|
||||
|
||||
function getTransitiveModules(
|
||||
modules: cpl.CompileNgModuleMetadata[], includeImports: boolean,
|
||||
targetModules: cpl.CompileNgModuleMetadata[] = [],
|
||||
visitedModules = new Set<Type<any>>()): cpl.CompileNgModuleMetadata[] {
|
||||
function getTransitiveExportedModules(
|
||||
modules: cpl.CompileNgModuleDirectiveSummary[],
|
||||
targetModules: cpl.CompileNgModuleDirectiveSummary[] = [],
|
||||
visitedModules = new Set<Type<any>>()): cpl.CompileNgModuleDirectiveSummary[] {
|
||||
modules.forEach((ngModule) => {
|
||||
if (!visitedModules.has(ngModule.type.reference)) {
|
||||
visitedModules.add(ngModule.type.reference);
|
||||
const nestedModules = includeImports ?
|
||||
ngModule.importedModules.concat(ngModule.exportedModules) :
|
||||
ngModule.exportedModules;
|
||||
getTransitiveModules(nestedModules, includeImports, targetModules, visitedModules);
|
||||
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<Type<any>>()): 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);
|
||||
|
|
|
@ -228,9 +228,9 @@ export class OfflineCompiler {
|
|||
fileSuffix: string, targetStatements: o.Statement[]): string {
|
||||
const parsedAnimations = this._animationParser.parseComponent(compMeta);
|
||||
const directives =
|
||||
directiveIdentifiers.map(dir => this._metadataResolver.getDirectiveMetadata(dir.reference));
|
||||
directiveIdentifiers.map(dir => this._metadataResolver.getDirectiveSummary(dir.reference));
|
||||
const pipes = ngModule.transitiveModule.pipes.map(
|
||||
pipe => this._metadataResolver.getPipeMetadata(pipe.reference));
|
||||
pipe => this._metadataResolver.getPipeSummary(pipe.reference));
|
||||
|
||||
const parsedTemplate = this._templateParser.parse(
|
||||
compMeta, compMeta.template.template, directives, pipes, ngModule.schemas,
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
|
||||
import {CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileNgModuleMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTokenMetadata, CompileTypeMetadata} from './compile_metadata';
|
||||
import {CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileDirectiveSummary, CompileNgModuleMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTokenMetadata, CompileTypeMetadata} from './compile_metadata';
|
||||
import {isBlank, isPresent} from './facade/lang';
|
||||
import {Identifiers, resolveIdentifierToken} from './identifiers';
|
||||
import {ParseError, ParseSourceSpan} from './parse_util';
|
||||
|
@ -440,7 +440,7 @@ function _normalizeProviders(
|
|||
|
||||
|
||||
function _resolveProvidersFromDirectives(
|
||||
directives: CompileDirectiveMetadata[], sourceSpan: ParseSourceSpan,
|
||||
directives: CompileDirectiveSummary[], sourceSpan: ParseSourceSpan,
|
||||
targetErrors: ParseError[]): Map<any, ProviderAst> {
|
||||
var providersByToken = new Map<any, ProviderAst>();
|
||||
directives.forEach((directive) => {
|
||||
|
@ -504,7 +504,7 @@ function _getViewQueries(component: CompileDirectiveMetadata): Map<any, CompileQ
|
|||
return viewQueries;
|
||||
}
|
||||
|
||||
function _getContentQueries(directives: CompileDirectiveMetadata[]):
|
||||
function _getContentQueries(directives: CompileDirectiveSummary[]):
|
||||
Map<any, CompileQueryMetadata[]> {
|
||||
var contentQueries = new Map<any, CompileQueryMetadata[]>();
|
||||
directives.forEach(directive => {
|
||||
|
|
|
@ -149,7 +149,9 @@ export class RuntimeCompiler implements Compiler {
|
|||
const moduleByDirective = new Map<any, CompileNgModuleMetadata>();
|
||||
const templates = new Set<CompiledTemplate>();
|
||||
|
||||
ngModule.transitiveModule.modules.forEach((localModuleMeta) => {
|
||||
ngModule.transitiveModule.modules.forEach((localModuleSummary) => {
|
||||
const localModuleMeta =
|
||||
this._metadataResolver.getNgModuleMetadata(localModuleSummary.type.reference);
|
||||
localModuleMeta.declaredDirectives.forEach((dirIdentifier) => {
|
||||
moduleByDirective.set(dirIdentifier.reference, localModuleMeta);
|
||||
const dirMeta = this._metadataResolver.getDirectiveMetadata(dirIdentifier.reference);
|
||||
|
@ -165,7 +167,9 @@ export class RuntimeCompiler implements Compiler {
|
|||
}
|
||||
});
|
||||
});
|
||||
ngModule.transitiveModule.modules.forEach((localModuleMeta) => {
|
||||
ngModule.transitiveModule.modules.forEach((localModuleSummary) => {
|
||||
const localModuleMeta =
|
||||
this._metadataResolver.getNgModuleMetadata(localModuleSummary.type.reference);
|
||||
localModuleMeta.declaredDirectives.forEach((dirIdentifier) => {
|
||||
const dirMeta = this._metadataResolver.getDirectiveMetadata(dirIdentifier.reference);
|
||||
if (dirMeta.isComponent) {
|
||||
|
@ -279,9 +283,9 @@ export class RuntimeCompiler implements Compiler {
|
|||
stylesCompileResult.componentStylesheet, externalStylesheetsByModuleUrl);
|
||||
const parsedAnimations = this._animationParser.parseComponent(compMeta);
|
||||
const directives =
|
||||
template.directives.map(dir => this._metadataResolver.getDirectiveMetadata(dir.reference));
|
||||
template.directives.map(dir => this._metadataResolver.getDirectiveSummary(dir.reference));
|
||||
const pipes = template.ngModule.transitiveModule.pipes.map(
|
||||
pipe => this._metadataResolver.getPipeMetadata(pipe.reference));
|
||||
pipe => this._metadataResolver.getPipeSummary(pipe.reference));
|
||||
const parsedTemplate = this._templateParser.parse(
|
||||
compMeta, compMeta.template.template, directives, pipes, template.ngModule.schemas,
|
||||
compMeta.type.name);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
import {SecurityContext} from '@angular/core';
|
||||
|
||||
import {CompileDirectiveMetadata, CompilePipeMetadata} from '../compile_metadata';
|
||||
import {CompileDirectiveSummary, CompilePipeSummary} from '../compile_metadata';
|
||||
import {AST, ASTWithSource, BindingPipe, EmptyExpr, Interpolation, LiteralPrimitive, ParserError, RecursiveAstVisitor, TemplateBinding} from '../expression_parser/ast';
|
||||
import {Parser} from '../expression_parser/parser';
|
||||
import {isPresent} from '../facade/lang';
|
||||
|
@ -52,16 +52,16 @@ export class BoundProperty {
|
|||
* Parses bindings in templates and in the directive host area.
|
||||
*/
|
||||
export class BindingParser {
|
||||
pipesByName: Map<string, CompilePipeMetadata> = new Map();
|
||||
pipesByName: Map<string, CompilePipeSummary> = new Map();
|
||||
|
||||
constructor(
|
||||
private _exprParser: Parser, private _interpolationConfig: InterpolationConfig,
|
||||
private _schemaRegistry: ElementSchemaRegistry, pipes: CompilePipeMetadata[],
|
||||
private _schemaRegistry: ElementSchemaRegistry, pipes: CompilePipeSummary[],
|
||||
private _targetErrors: ParseError[]) {
|
||||
pipes.forEach(pipe => this.pipesByName.set(pipe.name, pipe));
|
||||
}
|
||||
|
||||
createDirectiveHostPropertyAsts(dirMeta: CompileDirectiveMetadata, sourceSpan: ParseSourceSpan):
|
||||
createDirectiveHostPropertyAsts(dirMeta: CompileDirectiveSummary, sourceSpan: ParseSourceSpan):
|
||||
BoundElementPropertyAst[] {
|
||||
if (dirMeta.hostProperties) {
|
||||
const boundProps: BoundProperty[] = [];
|
||||
|
@ -79,7 +79,7 @@ export class BindingParser {
|
|||
}
|
||||
}
|
||||
|
||||
createDirectiveHostEventAsts(dirMeta: CompileDirectiveMetadata, sourceSpan: ParseSourceSpan):
|
||||
createDirectiveHostEventAsts(dirMeta: CompileDirectiveSummary, sourceSpan: ParseSourceSpan):
|
||||
BoundEventAst[] {
|
||||
if (dirMeta.hostListeners) {
|
||||
const targetEventAsts: BoundEventAst[] = [];
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
import {SecurityContext} from '@angular/core';
|
||||
|
||||
import {CompileDirectiveMetadata, CompileProviderMetadata, CompileTokenMetadata} from '../compile_metadata';
|
||||
import {CompileDirectiveSummary, CompileProviderMetadata, CompileTokenMetadata} from '../compile_metadata';
|
||||
import {AST} from '../expression_parser/ast';
|
||||
import {ParseSourceSpan} from '../parse_util';
|
||||
import {LifecycleHooks} from '../private_import_core';
|
||||
|
@ -168,7 +168,7 @@ export class BoundDirectivePropertyAst implements TemplateAst {
|
|||
*/
|
||||
export class DirectiveAst implements TemplateAst {
|
||||
constructor(
|
||||
public directive: CompileDirectiveMetadata, public inputs: BoundDirectivePropertyAst[],
|
||||
public directive: CompileDirectiveSummary, public inputs: BoundDirectivePropertyAst[],
|
||||
public hostProperties: BoundElementPropertyAst[], public hostEvents: BoundEventAst[],
|
||||
public sourceSpan: ParseSourceSpan) {}
|
||||
visit(visitor: TemplateAstVisitor, context: any): any {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
import {Inject, Injectable, OpaqueToken, Optional, SchemaMetadata, SecurityContext} from '@angular/core';
|
||||
|
||||
import {CompileDirectiveMetadata, CompilePipeMetadata, CompileTemplateMetadata, CompileTokenMetadata, removeIdentifierDuplicates} from '../compile_metadata';
|
||||
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompilePipeSummary, CompileTemplateMetadata, CompileTemplateSummary, CompileTokenMetadata, CompileTypeMetadata, removeIdentifierDuplicates} from '../compile_metadata';
|
||||
import {AST, ASTWithSource, BindingPipe, EmptyExpr, Interpolation, ParserError, RecursiveAstVisitor, TemplateBinding} from '../expression_parser/ast';
|
||||
import {Parser} from '../expression_parser/parser';
|
||||
import {isPresent} from '../facade/lang';
|
||||
|
@ -90,8 +90,8 @@ export class TemplateParser {
|
|||
@Optional() @Inject(TEMPLATE_TRANSFORMS) public transforms: TemplateAstVisitor[]) {}
|
||||
|
||||
parse(
|
||||
component: CompileDirectiveMetadata, template: string, directives: CompileDirectiveMetadata[],
|
||||
pipes: CompilePipeMetadata[], schemas: SchemaMetadata[], templateUrl: string): TemplateAst[] {
|
||||
component: CompileDirectiveMetadata, template: string, directives: CompileDirectiveSummary[],
|
||||
pipes: CompilePipeSummary[], schemas: SchemaMetadata[], templateUrl: string): TemplateAst[] {
|
||||
const result = this.tryParse(component, template, directives, pipes, schemas, templateUrl);
|
||||
const warnings = result.errors.filter(error => error.level === ParseErrorLevel.WARNING);
|
||||
const errors = result.errors.filter(error => error.level === ParseErrorLevel.FATAL);
|
||||
|
@ -109,8 +109,8 @@ export class TemplateParser {
|
|||
}
|
||||
|
||||
tryParse(
|
||||
component: CompileDirectiveMetadata, template: string, directives: CompileDirectiveMetadata[],
|
||||
pipes: CompilePipeMetadata[], schemas: SchemaMetadata[],
|
||||
component: CompileDirectiveMetadata, template: string, directives: CompileDirectiveSummary[],
|
||||
pipes: CompilePipeSummary[], schemas: SchemaMetadata[],
|
||||
templateUrl: string): TemplateParseResult {
|
||||
return this.tryParseHtml(
|
||||
this.expandHtml(this._htmlParser.parse(
|
||||
|
@ -120,13 +120,13 @@ export class TemplateParser {
|
|||
|
||||
tryParseHtml(
|
||||
htmlAstWithErrors: ParseTreeResult, component: CompileDirectiveMetadata, template: string,
|
||||
directives: CompileDirectiveMetadata[], pipes: CompilePipeMetadata[],
|
||||
schemas: SchemaMetadata[], templateUrl: string): TemplateParseResult {
|
||||
directives: CompileDirectiveSummary[], pipes: CompilePipeSummary[], schemas: SchemaMetadata[],
|
||||
templateUrl: string): TemplateParseResult {
|
||||
var result: TemplateAst[];
|
||||
var errors = htmlAstWithErrors.errors;
|
||||
if (htmlAstWithErrors.rootNodes.length > 0) {
|
||||
const uniqDirectives = removeIdentifierDuplicates(directives);
|
||||
const uniqPipes = removeIdentifierDuplicates(pipes);
|
||||
const uniqDirectives = removeSummaryDuplicates(directives);
|
||||
const uniqPipes = removeSummaryDuplicates(pipes);
|
||||
const providerViewContext =
|
||||
new ProviderViewContext(component, htmlAstWithErrors.rootNodes[0].sourceSpan);
|
||||
let interpolationConfig: InterpolationConfig;
|
||||
|
@ -200,14 +200,14 @@ export class TemplateParser {
|
|||
|
||||
class TemplateParseVisitor implements html.Visitor {
|
||||
selectorMatcher = new SelectorMatcher();
|
||||
directivesIndex = new Map<CompileDirectiveMetadata, number>();
|
||||
directivesIndex = new Map<CompileDirectiveSummary, number>();
|
||||
ngContentCount: number = 0;
|
||||
|
||||
constructor(
|
||||
public providerViewContext: ProviderViewContext, directives: CompileDirectiveMetadata[],
|
||||
public providerViewContext: ProviderViewContext, directives: CompileDirectiveSummary[],
|
||||
private _bindingParser: BindingParser, private _schemaRegistry: ElementSchemaRegistry,
|
||||
private _schemas: SchemaMetadata[], private _targetErrors: TemplateParseError[]) {
|
||||
directives.forEach((directive: CompileDirectiveMetadata, index: number) => {
|
||||
directives.forEach((directive, index) => {
|
||||
const selector = CssSelector.parse(directive.selector);
|
||||
this.selectorMatcher.addSelectables(selector, directive);
|
||||
this.directivesIndex.set(directive, index);
|
||||
|
@ -360,7 +360,8 @@ class TemplateParseVisitor implements html.Visitor {
|
|||
componentDirectiveAst.directive.template));
|
||||
|
||||
const componentTemplate = providerContext.viewContext.component.template;
|
||||
this._validateElementAnimationInputOutputs(elementProps, events, componentTemplate);
|
||||
this._validateElementAnimationInputOutputs(
|
||||
elementProps, events, componentTemplate.toSummary());
|
||||
}
|
||||
|
||||
if (hasInlineTemplates) {
|
||||
|
@ -392,9 +393,9 @@ class TemplateParseVisitor implements html.Visitor {
|
|||
|
||||
private _validateElementAnimationInputOutputs(
|
||||
inputs: BoundElementPropertyAst[], outputs: BoundEventAst[],
|
||||
template: CompileTemplateMetadata) {
|
||||
template: CompileTemplateSummary) {
|
||||
const triggerLookup = new Set<string>();
|
||||
template.animations.forEach(entry => { triggerLookup.add(entry.name); });
|
||||
template.animations.forEach(entry => { triggerLookup.add(entry); });
|
||||
|
||||
const animationInputs = inputs.filter(input => input.isAnimation);
|
||||
animationInputs.forEach(input => {
|
||||
|
@ -518,7 +519,7 @@ class TemplateParseVisitor implements html.Visitor {
|
|||
}
|
||||
|
||||
private _parseDirectives(selectorMatcher: SelectorMatcher, elementCssSelector: CssSelector):
|
||||
{directives: CompileDirectiveMetadata[], matchElement: boolean} {
|
||||
{directives: CompileDirectiveSummary[], matchElement: boolean} {
|
||||
// Need to sort the directives so that we get consistent results throughout,
|
||||
// as selectorMatcher uses Maps inside.
|
||||
// Also deduplicate directives as they might match more than one time!
|
||||
|
@ -538,12 +539,12 @@ class TemplateParseVisitor implements html.Visitor {
|
|||
}
|
||||
|
||||
private _createDirectiveAsts(
|
||||
isTemplateElement: boolean, elementName: string, directives: CompileDirectiveMetadata[],
|
||||
isTemplateElement: boolean, elementName: string, directives: CompileDirectiveSummary[],
|
||||
props: BoundProperty[], elementOrDirectiveRefs: ElementOrDirectiveRef[],
|
||||
elementSourceSpan: ParseSourceSpan, targetReferences: ReferenceAst[]): DirectiveAst[] {
|
||||
const matchedReferences = new Set<string>();
|
||||
let component: CompileDirectiveMetadata = null;
|
||||
const directiveAsts = directives.map((directive: CompileDirectiveMetadata) => {
|
||||
let component: CompileDirectiveSummary = null;
|
||||
const directiveAsts = directives.map((directive) => {
|
||||
const sourceSpan = new ParseSourceSpan(
|
||||
elementSourceSpan.start, elementSourceSpan.end, `Directive ${directive.type.name}`);
|
||||
if (directive.isComponent) {
|
||||
|
@ -837,3 +838,15 @@ const NON_BINDABLE_VISITOR = new NonBindableVisitor();
|
|||
function _isEmptyTextNode(node: html.Node): boolean {
|
||||
return node instanceof html.Text && node.value.trim().length == 0;
|
||||
}
|
||||
|
||||
export function removeSummaryDuplicates<T extends{type: CompileTypeMetadata}>(items: T[]): T[] {
|
||||
const map = new Map<any, T>();
|
||||
|
||||
items.forEach((item) => {
|
||||
if (!map.get(item.type.reference)) {
|
||||
map.set(item.type.reference, item);
|
||||
}
|
||||
});
|
||||
|
||||
return Array.from(map.values());
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
|
||||
import {CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileIdentifierMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTokenMetadata} from '../compile_metadata';
|
||||
import {CompileDiDependencyMetadata, CompileDirectiveSummary, CompileIdentifierMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTokenMetadata} from '../compile_metadata';
|
||||
import {createDiTokenExpression} from '../compiler_util/identifier_util';
|
||||
import {DirectiveWrapperCompiler, DirectiveWrapperExpressions} from '../directive_wrapper_compiler';
|
||||
import {isPresent} from '../facade/lang';
|
||||
|
@ -54,8 +54,8 @@ export class CompileElement extends CompileNode {
|
|||
|
||||
constructor(
|
||||
parent: CompileElement, view: CompileView, nodeIndex: number, renderNode: o.Expression,
|
||||
sourceAst: TemplateAst, public component: CompileDirectiveMetadata,
|
||||
private _directives: CompileDirectiveMetadata[],
|
||||
sourceAst: TemplateAst, public component: CompileDirectiveSummary,
|
||||
private _directives: CompileDirectiveSummary[],
|
||||
private _resolvedProvidersArray: ProviderAst[], public hasViewContainer: boolean,
|
||||
public hasEmbeddedView: boolean, references: ReferenceAst[],
|
||||
private _targetDependencies:
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
|
||||
import {CompilePipeMetadata} from '../compile_metadata';
|
||||
import {CompilePipeSummary} from '../compile_metadata';
|
||||
import {createPureProxy} from '../compiler_util/identifier_util';
|
||||
import {Identifiers, resolveIdentifier, resolveIdentifierToken} from '../identifiers';
|
||||
import * as o from '../output/output_ast';
|
||||
|
@ -39,7 +39,7 @@ export class CompilePipe {
|
|||
instance: o.ReadPropExpr;
|
||||
private _purePipeProxyCount = 0;
|
||||
|
||||
constructor(public view: CompileView, public meta: CompilePipeMetadata) {
|
||||
constructor(public view: CompileView, public meta: CompilePipeSummary) {
|
||||
this.instance = o.THIS_EXPR.prop(`_pipe_${meta.name}_${view.pipeCount++}`);
|
||||
var deps = this.meta.type.diDeps.map((diDep) => {
|
||||
if (diDep.token.reference ===
|
||||
|
@ -77,8 +77,8 @@ export class CompilePipe {
|
|||
}
|
||||
}
|
||||
|
||||
function _findPipeMeta(view: CompileView, name: string): CompilePipeMetadata {
|
||||
var pipeMeta: CompilePipeMetadata = null;
|
||||
function _findPipeMeta(view: CompileView, name: string): CompilePipeSummary {
|
||||
var pipeMeta: CompilePipeSummary = null;
|
||||
for (var i = view.pipeMetas.length - 1; i >= 0; i--) {
|
||||
var localPipeMeta = view.pipeMetas[i];
|
||||
if (localPipeMeta.name == name) {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
import {AnimationEntryCompileResult} from '../animation/animation_compiler';
|
||||
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompilePipeMetadata} from '../compile_metadata';
|
||||
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompilePipeSummary} from '../compile_metadata';
|
||||
import {EventHandlerVars, NameResolver} from '../compiler_util/expression_converter';
|
||||
import {createPureProxy} from '../compiler_util/identifier_util';
|
||||
import {CompilerConfig} from '../config';
|
||||
|
@ -82,7 +82,7 @@ export class CompileView implements NameResolver {
|
|||
|
||||
constructor(
|
||||
public component: CompileDirectiveMetadata, public genConfig: CompilerConfig,
|
||||
public pipeMetas: CompilePipeMetadata[], public styles: o.Expression,
|
||||
public pipeMetas: CompilePipeSummary[], public styles: o.Expression,
|
||||
public animations: AnimationEntryCompileResult[], public viewIndex: number,
|
||||
public declarationElement: CompileElement, public templateVariableBindings: string[][]) {
|
||||
this.createMethod = new CompileMethod(this);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {CompileDirectiveMetadata, CompilePipeMetadata} from '../compile_metadata';
|
||||
import {CompileDirectiveSummary, CompilePipeSummary} from '../compile_metadata';
|
||||
import {DirectiveWrapperExpressions} from '../directive_wrapper_compiler';
|
||||
import * as o from '../output/output_ast';
|
||||
import {LifecycleHooks} from '../private_import_core';
|
||||
|
@ -20,7 +20,7 @@ var STATE_IS_NEVER_CHECKED = o.THIS_EXPR.prop('numberOfChecks').identical(new o.
|
|||
var NOT_THROW_ON_CHANGES = o.not(DetectChangesVars.throwOnChange);
|
||||
|
||||
export function bindDirectiveAfterContentLifecycleCallbacks(
|
||||
directiveMeta: CompileDirectiveMetadata, directiveInstance: o.Expression,
|
||||
directiveMeta: CompileDirectiveSummary, directiveInstance: o.Expression,
|
||||
compileElement: CompileElement) {
|
||||
var view = compileElement.view;
|
||||
var lifecycleHooks = directiveMeta.type.lifecycleHooks;
|
||||
|
@ -38,7 +38,7 @@ export function bindDirectiveAfterContentLifecycleCallbacks(
|
|||
}
|
||||
|
||||
export function bindDirectiveAfterViewLifecycleCallbacks(
|
||||
directiveMeta: CompileDirectiveMetadata, directiveInstance: o.Expression,
|
||||
directiveMeta: CompileDirectiveSummary, directiveInstance: o.Expression,
|
||||
compileElement: CompileElement) {
|
||||
var view = compileElement.view;
|
||||
var lifecycleHooks = directiveMeta.type.lifecycleHooks;
|
||||
|
@ -77,7 +77,7 @@ export function bindInjectableDestroyLifecycleCallbacks(
|
|||
}
|
||||
|
||||
export function bindPipeDestroyLifecycleCallbacks(
|
||||
pipeMeta: CompilePipeMetadata, pipeInstance: o.Expression, view: CompileView) {
|
||||
pipeMeta: CompilePipeSummary, pipeInstance: o.Expression, view: CompileView) {
|
||||
var onDestroyMethod = view.destroyMethod;
|
||||
if (pipeMeta.type.lifecycleHooks.indexOf(LifecycleHooks.OnDestroy) !== -1) {
|
||||
onDestroyMethod.addStmt(pipeInstance.callMethod('ngOnDestroy', []).toStmt());
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
|
||||
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileTokenMetadata} from '../compile_metadata';
|
||||
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompileIdentifierMetadata, CompileTokenMetadata} from '../compile_metadata';
|
||||
import {createDiTokenExpression} from '../compiler_util/identifier_util';
|
||||
import {isPresent} from '../facade/lang';
|
||||
import {Identifiers, resolveIdentifier} from '../identifiers';
|
||||
|
@ -72,7 +72,8 @@ export function injectFromViewParentInjector(
|
|||
}
|
||||
|
||||
export function getViewClassName(
|
||||
component: CompileDirectiveMetadata, embeddedTemplateIndex: number): string {
|
||||
component: CompileDirectiveSummary | CompileDirectiveMetadata,
|
||||
embeddedTemplateIndex: number): string {
|
||||
return `View_${component.type.name}${embeddedTemplateIndex}`;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
import {ViewEncapsulation} from '@angular/core';
|
||||
|
||||
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileTokenMetadata} from '../compile_metadata';
|
||||
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompileIdentifierMetadata, CompileTokenMetadata} from '../compile_metadata';
|
||||
import {createSharedBindingVariablesIfNeeded} from '../compiler_util/expression_converter';
|
||||
import {createDiTokenExpression, createInlineArray} from '../compiler_util/identifier_util';
|
||||
import {isPresent} from '../facade/lang';
|
||||
|
@ -336,7 +336,7 @@ function _isNgContainer(node: CompileNode, view: CompileView): boolean {
|
|||
|
||||
|
||||
function _mergeHtmlAndDirectiveAttrs(
|
||||
declaredHtmlAttrs: {[key: string]: string}, directives: CompileDirectiveMetadata[]): string[] {
|
||||
declaredHtmlAttrs: {[key: string]: string}, directives: CompileDirectiveSummary[]): string[] {
|
||||
const mapResult: {[key: string]: string} = {};
|
||||
Object.keys(declaredHtmlAttrs).forEach(key => { mapResult[key] = declaredHtmlAttrs[key]; });
|
||||
directives.forEach(directiveMeta => {
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import {Injectable} from '@angular/core';
|
||||
|
||||
import {AnimationEntryCompileResult} from '../animation/animation_compiler';
|
||||
import {CompileDirectiveMetadata, CompilePipeMetadata} from '../compile_metadata';
|
||||
import {CompileDirectiveMetadata, CompilePipeSummary} from '../compile_metadata';
|
||||
import {CompilerConfig} from '../config';
|
||||
import * as o from '../output/output_ast';
|
||||
import {ElementSchemaRegistry} from '../schema/element_schema_registry';
|
||||
|
@ -36,7 +36,7 @@ export class ViewCompiler {
|
|||
|
||||
compileComponent(
|
||||
component: CompileDirectiveMetadata, template: TemplateAst[], styles: o.Expression,
|
||||
pipes: CompilePipeMetadata[],
|
||||
pipes: CompilePipeSummary[],
|
||||
compiledAnimations: AnimationEntryCompileResult[]): ViewCompileResult {
|
||||
const dependencies:
|
||||
Array<ViewClassDependency|ComponentFactoryDependency|DirectiveWrapperDependency> = [];
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {CompileAnimationEntryMetadata, CompileDiDependencyMetadata, CompileDirectiveMetadata, CompilePipeMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTemplateMetadata, CompileTokenMetadata, CompileTypeMetadata} from '@angular/compiler/src/compile_metadata';
|
||||
import {CompileAnimationEntryMetadata, CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileDirectiveSummary, CompilePipeMetadata, CompilePipeSummary, CompileProviderMetadata, CompileQueryMetadata, CompileTemplateMetadata, CompileTokenMetadata, CompileTypeMetadata} from '@angular/compiler/src/compile_metadata';
|
||||
import {DomElementSchemaRegistry} from '@angular/compiler/src/schema/dom_element_schema_registry';
|
||||
import {ElementSchemaRegistry} from '@angular/compiler/src/schema/element_schema_registry';
|
||||
import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, PropertyBindingType, ProviderAstType, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '@angular/compiler/src/template_parser/template_ast';
|
||||
|
@ -16,6 +16,7 @@ import {SchemaMetadata, SecurityContext, Type} from '@angular/core';
|
|||
import {Console} from '@angular/core/src/console';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {beforeEach, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
|
||||
|
||||
import {Identifiers, identifierToken, resolveIdentifierToken} from '../../src/identifiers';
|
||||
import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../../src/ml_parser/interpolation_config';
|
||||
import {MockSchemaRegistry} from '../../testing/index';
|
||||
|
@ -31,9 +32,9 @@ const MOCK_SCHEMA_REGISTRY = [{
|
|||
}];
|
||||
|
||||
export function main() {
|
||||
var ngIf: CompileDirectiveMetadata;
|
||||
var ngIf: CompileDirectiveSummary;
|
||||
var parse: (
|
||||
template: string, directives: CompileDirectiveMetadata[], pipes?: CompilePipeMetadata[],
|
||||
template: string, directives: CompileDirectiveSummary[], pipes?: CompilePipeSummary[],
|
||||
schemas?: SchemaMetadata[]) => TemplateAst[];
|
||||
var console: ArrayConsole;
|
||||
|
||||
|
@ -52,17 +53,19 @@ export function main() {
|
|||
{moduleUrl: someModuleUrl, name: 'Root', reference: {} as Type<any>}),
|
||||
isComponent: true
|
||||
});
|
||||
ngIf = CompileDirectiveMetadata.create({
|
||||
selector: '[ngIf]',
|
||||
template: someTemplate,
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'NgIf', reference: {} as Type<any>}),
|
||||
inputs: ['ngIf']
|
||||
});
|
||||
ngIf = CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: '[ngIf]',
|
||||
template: someTemplate,
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'NgIf', reference: {} as Type<any>}),
|
||||
inputs: ['ngIf']
|
||||
})
|
||||
.toSummary();
|
||||
|
||||
parse =
|
||||
(template: string, directives: CompileDirectiveMetadata[],
|
||||
pipes: CompilePipeMetadata[] = null, schemas: SchemaMetadata[] = []): TemplateAst[] => {
|
||||
(template: string, directives: CompileDirectiveSummary[],
|
||||
pipes: CompilePipeSummary[] = null, schemas: SchemaMetadata[] = []): TemplateAst[] => {
|
||||
if (pipes === null) {
|
||||
pipes = [];
|
||||
}
|
||||
|
@ -462,25 +465,34 @@ Binding to attribute 'onEvent' is disallowed for security reasons ("<my-componen
|
|||
it('should not issue a warning when host attributes contain a valid property-bound animation trigger',
|
||||
() => {
|
||||
const animationEntries = [new CompileAnimationEntryMetadata('prop', [])];
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: 'div',
|
||||
template: new CompileTemplateMetadata({animations: animationEntries}),
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
host: {'[@prop]': 'expr'}
|
||||
});
|
||||
var dirA =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: 'div',
|
||||
template: new CompileTemplateMetadata({animations: animationEntries}),
|
||||
type: new CompileTypeMetadata({
|
||||
moduleUrl: someModuleUrl,
|
||||
name: 'DirA',
|
||||
reference: {} as Type<any>
|
||||
}),
|
||||
host: {'[@prop]': 'expr'}
|
||||
})
|
||||
.toSummary();
|
||||
|
||||
humanizeTplAst(parse('<div></div>', [dirA]));
|
||||
expect(console.warnings.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('should throw descriptive error when a host binding is not a string expression', () => {
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: 'broken',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
host: {'[class.foo]': null}
|
||||
});
|
||||
var dirA =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: 'broken',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
host: {'[class.foo]': null}
|
||||
})
|
||||
.toSummary();
|
||||
|
||||
expect(() => { parse('<broken></broken>', [dirA]); })
|
||||
.toThrowError(
|
||||
|
@ -488,12 +500,15 @@ Binding to attribute 'onEvent' is disallowed for security reasons ("<my-componen
|
|||
});
|
||||
|
||||
it('should throw descriptive error when a host event is not a string expression', () => {
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: 'broken',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
host: {'(click)': null}
|
||||
});
|
||||
var dirA =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: 'broken',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
host: {'(click)': null}
|
||||
})
|
||||
.toSummary();
|
||||
|
||||
expect(() => { parse('<broken></broken>', [dirA]); })
|
||||
.toThrowError(
|
||||
|
@ -553,12 +568,17 @@ Binding to attribute 'onEvent' is disallowed for security reasons ("<my-componen
|
|||
|
||||
it('should allow events on explicit embedded templates that are emitted by a directive',
|
||||
() => {
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: 'template',
|
||||
outputs: ['e'],
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>})
|
||||
});
|
||||
var dirA = CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: 'template',
|
||||
outputs: ['e'],
|
||||
type: new CompileTypeMetadata({
|
||||
moduleUrl: someModuleUrl,
|
||||
name: 'DirA',
|
||||
reference: {} as Type<any>
|
||||
})
|
||||
})
|
||||
.toSummary();
|
||||
expect(humanizeTplAst(parse('<template (e)="f"></template>', [dirA]))).toEqual([
|
||||
[EmbeddedTemplateAst],
|
||||
[BoundEventAst, 'e', null, 'f'],
|
||||
|
@ -591,21 +611,36 @@ Binding to attribute 'onEvent' is disallowed for security reasons ("<my-componen
|
|||
describe('directives', () => {
|
||||
it('should order directives by the directives array in the View and match them only once',
|
||||
() => {
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: '[a]',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>})
|
||||
});
|
||||
var dirB = CompileDirectiveMetadata.create({
|
||||
selector: '[b]',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirB', reference: {} as Type<any>})
|
||||
});
|
||||
var dirC = CompileDirectiveMetadata.create({
|
||||
selector: '[c]',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirC', reference: {} as Type<any>})
|
||||
});
|
||||
var dirA = CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: '[a]',
|
||||
type: new CompileTypeMetadata({
|
||||
moduleUrl: someModuleUrl,
|
||||
name: 'DirA',
|
||||
reference: {} as Type<any>
|
||||
})
|
||||
})
|
||||
.toSummary();
|
||||
var dirB = CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: '[b]',
|
||||
type: new CompileTypeMetadata({
|
||||
moduleUrl: someModuleUrl,
|
||||
name: 'DirB',
|
||||
reference: {} as Type<any>
|
||||
})
|
||||
})
|
||||
.toSummary();
|
||||
var dirC = CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: '[c]',
|
||||
type: new CompileTypeMetadata({
|
||||
moduleUrl: someModuleUrl,
|
||||
name: 'DirC',
|
||||
reference: {} as Type<any>
|
||||
})
|
||||
})
|
||||
.toSummary();
|
||||
expect(humanizeTplAst(parse('<div a c b a b>', [dirA, dirB, dirC]))).toEqual([
|
||||
[ElementAst, 'div'], [AttrAst, 'a', ''], [AttrAst, 'c', ''], [AttrAst, 'b', ''],
|
||||
[AttrAst, 'a', ''], [AttrAst, 'b', ''], [DirectiveAst, dirA],
|
||||
|
@ -614,16 +649,22 @@ Binding to attribute 'onEvent' is disallowed for security reasons ("<my-componen
|
|||
});
|
||||
|
||||
it('should locate directives in property bindings', () => {
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: '[a=b]',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>})
|
||||
});
|
||||
var dirB = CompileDirectiveMetadata.create({
|
||||
selector: '[b]',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirB', reference: {} as Type<any>})
|
||||
});
|
||||
var dirA =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: '[a=b]',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>})
|
||||
})
|
||||
.toSummary();
|
||||
var dirB =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: '[b]',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirB', reference: {} as Type<any>})
|
||||
})
|
||||
.toSummary();
|
||||
expect(humanizeTplAst(parse('<div [a]="b">', [dirA, dirB]))).toEqual([
|
||||
[ElementAst, 'div'],
|
||||
[BoundElementPropertyAst, PropertyBindingType.Property, 'a', 'b', null],
|
||||
|
@ -632,11 +673,14 @@ Binding to attribute 'onEvent' is disallowed for security reasons ("<my-componen
|
|||
});
|
||||
|
||||
it('should locate directives in event bindings', () => {
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: '[a]',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirB', reference: {} as Type<any>})
|
||||
});
|
||||
var dirA =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: '[a]',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirB', reference: {} as Type<any>})
|
||||
})
|
||||
.toSummary();
|
||||
|
||||
expect(humanizeTplAst(parse('<div (a)="b">', [dirA]))).toEqual([
|
||||
[ElementAst, 'div'], [BoundEventAst, 'a', null, 'b'], [DirectiveAst, dirA]
|
||||
|
@ -644,12 +688,15 @@ Binding to attribute 'onEvent' is disallowed for security reasons ("<my-componen
|
|||
});
|
||||
|
||||
it('should parse directive host properties', () => {
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: 'div',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
host: {'[a]': 'expr'}
|
||||
});
|
||||
var dirA =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: 'div',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
host: {'[a]': 'expr'}
|
||||
})
|
||||
.toSummary();
|
||||
expect(humanizeTplAst(parse('<div></div>', [dirA]))).toEqual([
|
||||
[ElementAst, 'div'], [DirectiveAst, dirA],
|
||||
[BoundElementPropertyAst, PropertyBindingType.Property, 'a', 'expr', null]
|
||||
|
@ -657,24 +704,30 @@ Binding to attribute 'onEvent' is disallowed for security reasons ("<my-componen
|
|||
});
|
||||
|
||||
it('should parse directive host listeners', () => {
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: 'div',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
host: {'(a)': 'expr'}
|
||||
});
|
||||
var dirA =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: 'div',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
host: {'(a)': 'expr'}
|
||||
})
|
||||
.toSummary();
|
||||
expect(humanizeTplAst(parse('<div></div>', [dirA]))).toEqual([
|
||||
[ElementAst, 'div'], [DirectiveAst, dirA], [BoundEventAst, 'a', null, 'expr']
|
||||
]);
|
||||
});
|
||||
|
||||
it('should parse directive properties', () => {
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: 'div',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
inputs: ['aProp']
|
||||
});
|
||||
var dirA =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: 'div',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
inputs: ['aProp']
|
||||
})
|
||||
.toSummary();
|
||||
expect(humanizeTplAst(parse('<div [aProp]="expr"></div>', [dirA]))).toEqual([
|
||||
[ElementAst, 'div'], [DirectiveAst, dirA],
|
||||
[BoundDirectivePropertyAst, 'aProp', 'expr']
|
||||
|
@ -682,12 +735,15 @@ Binding to attribute 'onEvent' is disallowed for security reasons ("<my-componen
|
|||
});
|
||||
|
||||
it('should parse renamed directive properties', () => {
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: 'div',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
inputs: ['b:a']
|
||||
});
|
||||
var dirA =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: 'div',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
inputs: ['b:a']
|
||||
})
|
||||
.toSummary();
|
||||
expect(humanizeTplAst(parse('<div [a]="expr"></div>', [dirA]))).toEqual([
|
||||
[ElementAst, 'div'], [DirectiveAst, dirA],
|
||||
[BoundDirectivePropertyAst, 'b', 'expr']
|
||||
|
@ -695,12 +751,15 @@ Binding to attribute 'onEvent' is disallowed for security reasons ("<my-componen
|
|||
});
|
||||
|
||||
it('should parse literal directive properties', () => {
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: 'div',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
inputs: ['a']
|
||||
});
|
||||
var dirA =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: 'div',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
inputs: ['a']
|
||||
})
|
||||
.toSummary();
|
||||
expect(humanizeTplAst(parse('<div a="literal"></div>', [dirA]))).toEqual([
|
||||
[ElementAst, 'div'], [AttrAst, 'a', 'literal'], [DirectiveAst, dirA],
|
||||
[BoundDirectivePropertyAst, 'a', '"literal"']
|
||||
|
@ -708,12 +767,15 @@ Binding to attribute 'onEvent' is disallowed for security reasons ("<my-componen
|
|||
});
|
||||
|
||||
it('should favor explicit bound properties over literal properties', () => {
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: 'div',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
inputs: ['a']
|
||||
});
|
||||
var dirA =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: 'div',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
inputs: ['a']
|
||||
})
|
||||
.toSummary();
|
||||
expect(humanizeTplAst(parse('<div a="literal" [a]="\'literal2\'"></div>', [dirA])))
|
||||
.toEqual([
|
||||
[ElementAst, 'div'], [AttrAst, 'a', 'literal'], [DirectiveAst, dirA],
|
||||
|
@ -722,12 +784,15 @@ Binding to attribute 'onEvent' is disallowed for security reasons ("<my-componen
|
|||
});
|
||||
|
||||
it('should support optional directive properties', () => {
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: 'div',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
inputs: ['a']
|
||||
});
|
||||
var dirA =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: 'div',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
inputs: ['a']
|
||||
})
|
||||
.toSummary();
|
||||
expect(humanizeTplAst(parse('<div></div>', [dirA]))).toEqual([
|
||||
[ElementAst, 'div'], [DirectiveAst, dirA]
|
||||
]);
|
||||
|
@ -795,23 +860,25 @@ Binding to attribute 'onEvent' is disallowed for security reasons ("<my-componen
|
|||
viewProviders?: CompileProviderMetadata[],
|
||||
deps?: string[],
|
||||
queries?: string[]
|
||||
} = {}): CompileDirectiveMetadata {
|
||||
} = {}): CompileDirectiveSummary {
|
||||
var isComponent = !selector.startsWith('[');
|
||||
return CompileDirectiveMetadata.create({
|
||||
selector: selector,
|
||||
type: new CompileTypeMetadata({
|
||||
moduleUrl: someModuleUrl,
|
||||
name: selector,
|
||||
diDeps: deps.map(createDep),
|
||||
reference: selector as any as Type<any>
|
||||
}),
|
||||
isComponent: isComponent,
|
||||
template: new CompileTemplateMetadata({ngContentSelectors: []}),
|
||||
providers: providers,
|
||||
viewProviders: viewProviders,
|
||||
queries: queries.map(
|
||||
(value) => new CompileQueryMetadata({selectors: [createToken(value)]}))
|
||||
});
|
||||
return CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: selector,
|
||||
type: new CompileTypeMetadata({
|
||||
moduleUrl: someModuleUrl,
|
||||
name: selector,
|
||||
diDeps: deps.map(createDep),
|
||||
reference: selector as any as Type<any>
|
||||
}),
|
||||
isComponent: isComponent,
|
||||
template: new CompileTemplateMetadata({ngContentSelectors: []}),
|
||||
providers: providers,
|
||||
viewProviders: viewProviders,
|
||||
queries: queries.map(
|
||||
(value) => new CompileQueryMetadata({selectors: [createToken(value)]}))
|
||||
})
|
||||
.toSummary();
|
||||
}
|
||||
|
||||
beforeEach(() => { nextProviderId = 0; });
|
||||
|
@ -1051,12 +1118,15 @@ Binding to attribute 'onEvent' is disallowed for security reasons ("<my-componen
|
|||
});
|
||||
|
||||
it('should assign references to directives via exportAs', () => {
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: '[a]',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
exportAs: 'dirA'
|
||||
});
|
||||
var dirA =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: '[a]',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
exportAs: 'dirA'
|
||||
})
|
||||
.toSummary();
|
||||
expect(humanizeTplAst(parse('<div a #a="dirA"></div>', [dirA]))).toEqual([
|
||||
[ElementAst, 'div'],
|
||||
[AttrAst, 'a', ''],
|
||||
|
@ -1095,14 +1165,17 @@ Reference "#a" is defined several times ("<div #a></div><div [ERROR ->]#a></div>
|
|||
});
|
||||
|
||||
it('should assign references with empty value to components', () => {
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: '[a]',
|
||||
isComponent: true,
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
exportAs: 'dirA',
|
||||
template: new CompileTemplateMetadata({ngContentSelectors: []})
|
||||
});
|
||||
var dirA =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: '[a]',
|
||||
isComponent: true,
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
exportAs: 'dirA',
|
||||
template: new CompileTemplateMetadata({ngContentSelectors: []})
|
||||
})
|
||||
.toSummary();
|
||||
expect(humanizeTplAst(parse('<div a #a></div>', [dirA]))).toEqual([
|
||||
[ElementAst, 'div'],
|
||||
[AttrAst, 'a', ''],
|
||||
|
@ -1112,11 +1185,14 @@ Reference "#a" is defined several times ("<div #a></div><div [ERROR ->]#a></div>
|
|||
});
|
||||
|
||||
it('should not locate directives in references', () => {
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: '[a]',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>})
|
||||
});
|
||||
var dirA =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: '[a]',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>})
|
||||
})
|
||||
.toSummary();
|
||||
expect(humanizeTplAst(parse('<div ref-a>', [dirA]))).toEqual([
|
||||
[ElementAst, 'div'], [ReferenceAst, 'a', null]
|
||||
]);
|
||||
|
@ -1159,11 +1235,14 @@ Reference "#a" is defined several times ("<div #a></div><div [ERROR ->]#a></div>
|
|||
});
|
||||
|
||||
it('should not locate directives in variables', () => {
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: '[a]',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>})
|
||||
});
|
||||
var dirA =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: '[a]',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>})
|
||||
})
|
||||
.toSummary();
|
||||
expect(humanizeTplAst(parse('<template let-a="b"></template>', [dirA]))).toEqual([
|
||||
[EmbeddedTemplateAst], [VariableAst, 'a', 'b']
|
||||
]);
|
||||
|
@ -1202,17 +1281,25 @@ Reference "#a" is defined several times ("<div #a></div><div [ERROR ->]#a></div>
|
|||
|
||||
describe('directives', () => {
|
||||
it('should locate directives in property bindings', () => {
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: '[a=b]',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
inputs: ['a']
|
||||
});
|
||||
var dirB = CompileDirectiveMetadata.create({
|
||||
selector: '[b]',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirB', reference: {} as Type<any>})
|
||||
});
|
||||
var dirA =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: '[a=b]',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
inputs: ['a']
|
||||
})
|
||||
.toSummary();
|
||||
var dirB = CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: '[b]',
|
||||
type: new CompileTypeMetadata({
|
||||
moduleUrl: someModuleUrl,
|
||||
name: 'DirB',
|
||||
reference: {} as Type<any>
|
||||
})
|
||||
})
|
||||
.toSummary();
|
||||
expect(humanizeTplAst(parse('<div template="a b" b>', [dirA, dirB]))).toEqual([
|
||||
[EmbeddedTemplateAst], [DirectiveAst, dirA],
|
||||
[BoundDirectivePropertyAst, 'a', 'b'], [ElementAst, 'div'], [AttrAst, 'b', ''],
|
||||
|
@ -1221,22 +1308,32 @@ Reference "#a" is defined several times ("<div #a></div><div [ERROR ->]#a></div>
|
|||
});
|
||||
|
||||
it('should not locate directives in variables', () => {
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: '[a]',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>})
|
||||
});
|
||||
var dirA = CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: '[a]',
|
||||
type: new CompileTypeMetadata({
|
||||
moduleUrl: someModuleUrl,
|
||||
name: 'DirA',
|
||||
reference: {} as Type<any>
|
||||
})
|
||||
})
|
||||
.toSummary();
|
||||
expect(humanizeTplAst(parse('<div template="let a=b">', [dirA]))).toEqual([
|
||||
[EmbeddedTemplateAst], [VariableAst, 'a', 'b'], [ElementAst, 'div']
|
||||
]);
|
||||
});
|
||||
|
||||
it('should not locate directives in references', () => {
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: '[a]',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>})
|
||||
});
|
||||
var dirA = CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: '[a]',
|
||||
type: new CompileTypeMetadata({
|
||||
moduleUrl: someModuleUrl,
|
||||
name: 'DirA',
|
||||
reference: {} as Type<any>
|
||||
})
|
||||
})
|
||||
.toSummary();
|
||||
expect(humanizeTplAst(parse('<div ref-a>', [dirA]))).toEqual([
|
||||
[ElementAst, 'div'], [ReferenceAst, 'a', null]
|
||||
]);
|
||||
|
@ -1265,28 +1362,32 @@ Reference "#a" is defined several times ("<div #a></div><div [ERROR ->]#a></div>
|
|||
beforeEach(() => { compCounter = 0; });
|
||||
|
||||
function createComp(
|
||||
selector: string, ngContentSelectors: string[]): CompileDirectiveMetadata {
|
||||
return CompileDirectiveMetadata.create({
|
||||
selector: selector,
|
||||
isComponent: true,
|
||||
type: new CompileTypeMetadata({
|
||||
moduleUrl: someModuleUrl,
|
||||
name: `SomeComp${compCounter++}`,
|
||||
reference: {} as Type<any>
|
||||
}),
|
||||
template: new CompileTemplateMetadata({ngContentSelectors: ngContentSelectors})
|
||||
});
|
||||
selector: string, ngContentSelectors: string[]): CompileDirectiveSummary {
|
||||
return CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: selector,
|
||||
isComponent: true,
|
||||
type: new CompileTypeMetadata({
|
||||
moduleUrl: someModuleUrl,
|
||||
name: `SomeComp${compCounter++}`,
|
||||
reference: {} as Type<any>
|
||||
}),
|
||||
template: new CompileTemplateMetadata({ngContentSelectors: ngContentSelectors})
|
||||
})
|
||||
.toSummary();
|
||||
}
|
||||
|
||||
function createDir(selector: string): CompileDirectiveMetadata {
|
||||
return CompileDirectiveMetadata.create({
|
||||
selector: selector,
|
||||
type: new CompileTypeMetadata({
|
||||
moduleUrl: someModuleUrl,
|
||||
name: `SomeDir${compCounter++}`,
|
||||
reference: {} as Type<any>
|
||||
})
|
||||
});
|
||||
function createDir(selector: string): CompileDirectiveSummary {
|
||||
return CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: selector,
|
||||
type: new CompileTypeMetadata({
|
||||
moduleUrl: someModuleUrl,
|
||||
name: `SomeDir${compCounter++}`,
|
||||
reference: {} as Type<any>
|
||||
})
|
||||
})
|
||||
.toSummary();
|
||||
}
|
||||
|
||||
describe('project text nodes', () => {
|
||||
|
@ -1454,12 +1555,15 @@ Can't bind to 'invalidProp' since it isn't a known property of 'div'. ("<div [ER
|
|||
});
|
||||
|
||||
it('should report invalid host property names', () => {
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: 'div',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
host: {'[invalidProp]': 'someProp'}
|
||||
});
|
||||
var dirA =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: 'div',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
host: {'[invalidProp]': 'someProp'}
|
||||
})
|
||||
.toSummary();
|
||||
expect(() => parse('<div></div>', [dirA])).toThrowError(`Template parse errors:
|
||||
Can't bind to 'invalidProp' since it isn't a known property of 'div'. ("[ERROR ->]<div></div>"): TestComp@0:0, Directive DirA`);
|
||||
});
|
||||
|
@ -1471,30 +1575,39 @@ Parser Error: Unexpected token 'b' at column 3 in [a b] in TestComp@0:5 ("<div [
|
|||
|
||||
it('should not throw on invalid property names if the property is used by a directive',
|
||||
() => {
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: 'div',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
inputs: ['invalidProp']
|
||||
});
|
||||
var dirA =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: 'div',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
inputs: ['invalidProp']
|
||||
})
|
||||
.toSummary();
|
||||
expect(() => parse('<div [invalid-prop]></div>', [dirA])).not.toThrow();
|
||||
});
|
||||
|
||||
it('should not allow more than 1 component per element', () => {
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: 'div',
|
||||
isComponent: true,
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
template: new CompileTemplateMetadata({ngContentSelectors: []})
|
||||
});
|
||||
var dirB = CompileDirectiveMetadata.create({
|
||||
selector: 'div',
|
||||
isComponent: true,
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirB', reference: {} as Type<any>}),
|
||||
template: new CompileTemplateMetadata({ngContentSelectors: []})
|
||||
});
|
||||
var dirA =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: 'div',
|
||||
isComponent: true,
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
template: new CompileTemplateMetadata({ngContentSelectors: []})
|
||||
})
|
||||
.toSummary();
|
||||
var dirB =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: 'div',
|
||||
isComponent: true,
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirB', reference: {} as Type<any>}),
|
||||
template: new CompileTemplateMetadata({ngContentSelectors: []})
|
||||
})
|
||||
.toSummary();
|
||||
expect(() => parse('<div>', [dirB, dirA]))
|
||||
.toThrowError(
|
||||
`Template parse errors:\n` +
|
||||
|
@ -1505,13 +1618,16 @@ Parser Error: Unexpected token 'b' at column 3 in [a b] in TestComp@0:5 ("<div [
|
|||
|
||||
it('should not allow components or element bindings nor dom events on explicit embedded templates',
|
||||
() => {
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: '[a]',
|
||||
isComponent: true,
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
template: new CompileTemplateMetadata({ngContentSelectors: []})
|
||||
});
|
||||
var dirA =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: '[a]',
|
||||
isComponent: true,
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
template: new CompileTemplateMetadata({ngContentSelectors: []})
|
||||
})
|
||||
.toSummary();
|
||||
expect(() => parse('<template [a]="b" (e)="f"></template>', [dirA]))
|
||||
.toThrowError(`Template parse errors:
|
||||
Event binding e not emitted by any directive on an embedded template. Make sure that the event name is spelled correctly and all directives are listed in the "directives" section. ("<template [a]="b" [ERROR ->](e)="f"></template>"): TestComp@0:18
|
||||
|
@ -1520,13 +1636,16 @@ Property binding a not used by any directive on an embedded template. Make sure
|
|||
});
|
||||
|
||||
it('should not allow components or element bindings on inline embedded templates', () => {
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: '[a]',
|
||||
isComponent: true,
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
template: new CompileTemplateMetadata({ngContentSelectors: []})
|
||||
});
|
||||
var dirA =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: '[a]',
|
||||
isComponent: true,
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
template: new CompileTemplateMetadata({ngContentSelectors: []})
|
||||
})
|
||||
.toSummary();
|
||||
expect(() => parse('<div *a="b"></div>', [dirA])).toThrowError(`Template parse errors:
|
||||
Components on an embedded template: DirA ("[ERROR ->]<div *a="b"></div>"): TestComp@0:0
|
||||
Property binding a not used by any directive on an embedded template. Make sure that the property name is spelled correctly and all directives are listed in the "directives" section. ("[ERROR ->]<div *a="b"></div>"): TestComp@0:0`);
|
||||
|
@ -1678,18 +1797,24 @@ Property binding a not used by any directive on an embedded template. Make sure
|
|||
});
|
||||
|
||||
it('should support directive', () => {
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: '[a]',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>})
|
||||
});
|
||||
var comp = CompileDirectiveMetadata.create({
|
||||
selector: 'div',
|
||||
isComponent: true,
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'ZComp', reference: {} as Type<any>}),
|
||||
template: new CompileTemplateMetadata({ngContentSelectors: []})
|
||||
});
|
||||
var dirA =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: '[a]',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>})
|
||||
})
|
||||
.toSummary();
|
||||
var comp =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: 'div',
|
||||
isComponent: true,
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'ZComp', reference: {} as Type<any>}),
|
||||
template: new CompileTemplateMetadata({ngContentSelectors: []})
|
||||
})
|
||||
.toSummary();
|
||||
expect(humanizeTplAstSourceSpans(parse('<div a>', [dirA, comp]))).toEqual([
|
||||
[ElementAst, 'div', '<div a>'], [AttrAst, 'a', '', 'a'],
|
||||
[DirectiveAst, dirA, '<div a>'], [DirectiveAst, comp, '<div a>']
|
||||
|
@ -1697,16 +1822,22 @@ Property binding a not used by any directive on an embedded template. Make sure
|
|||
});
|
||||
|
||||
it('should support directive in namespace', () => {
|
||||
var tagSel = CompileDirectiveMetadata.create({
|
||||
selector: 'circle',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'elDir', reference: {} as Type<any>})
|
||||
});
|
||||
var attrSel = CompileDirectiveMetadata.create({
|
||||
selector: '[href]',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'attrDir', reference: {} as Type<any>})
|
||||
});
|
||||
var tagSel =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: 'circle',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'elDir', reference: {} as Type<any>})
|
||||
})
|
||||
.toSummary();
|
||||
var attrSel =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: '[href]',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'attrDir', reference: {} as Type<any>})
|
||||
})
|
||||
.toSummary();
|
||||
|
||||
expect(humanizeTplAstSourceSpans(
|
||||
parse('<svg><circle /><use xlink:href="Port" /></svg>', [tagSel, attrSel])))
|
||||
|
@ -1721,12 +1852,15 @@ Property binding a not used by any directive on an embedded template. Make sure
|
|||
});
|
||||
|
||||
it('should support directive property', () => {
|
||||
var dirA = CompileDirectiveMetadata.create({
|
||||
selector: 'div',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
inputs: ['aProp']
|
||||
});
|
||||
var dirA =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: 'div',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>}),
|
||||
inputs: ['aProp']
|
||||
})
|
||||
.toSummary();
|
||||
expect(humanizeTplAstSourceSpans(parse('<div [aProp]="foo"></div>', [dirA]))).toEqual([
|
||||
[ElementAst, 'div', '<div [aProp]="foo">'],
|
||||
[DirectiveAst, dirA, '<div [aProp]="foo">'],
|
||||
|
@ -1735,11 +1869,14 @@ Property binding a not used by any directive on an embedded template. Make sure
|
|||
});
|
||||
|
||||
it('should support endSourceSpan for elements', () => {
|
||||
const tagSel = CompileDirectiveMetadata.create({
|
||||
selector: 'circle',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'elDir', reference: {} as Type<any>})
|
||||
});
|
||||
const tagSel =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: 'circle',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'elDir', reference: {} as Type<any>})
|
||||
})
|
||||
.toSummary();
|
||||
const result = parse('<circle></circle>', [tagSel]);
|
||||
const circle = result[0] as ElementAst;
|
||||
expect(circle.endSourceSpan).toBeDefined();
|
||||
|
@ -1748,16 +1885,22 @@ Property binding a not used by any directive on an embedded template. Make sure
|
|||
});
|
||||
|
||||
it('should report undefined for endSourceSpan for elements without an end-tag', () => {
|
||||
const ulSel = CompileDirectiveMetadata.create({
|
||||
selector: 'ul',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'ulDir', reference: {} as Type<any>})
|
||||
});
|
||||
const liSel = CompileDirectiveMetadata.create({
|
||||
selector: 'li',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'liDir', reference: {} as Type<any>})
|
||||
});
|
||||
const ulSel =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: 'ul',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'ulDir', reference: {} as Type<any>})
|
||||
})
|
||||
.toSummary();
|
||||
const liSel =
|
||||
CompileDirectiveMetadata
|
||||
.create({
|
||||
selector: 'li',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'liDir', reference: {} as Type<any>})
|
||||
})
|
||||
.toSummary();
|
||||
const result = parse('<ul><li><li></ul>', [ulSel, liSel]);
|
||||
const ul = result[0] as ElementAst;
|
||||
const li = ul.children[0] as ElementAst;
|
||||
|
@ -1767,11 +1910,12 @@ Property binding a not used by any directive on an embedded template. Make sure
|
|||
|
||||
describe('pipes', () => {
|
||||
it('should allow pipes that have been defined as dependencies', () => {
|
||||
var testPipe = new CompilePipeMetadata({
|
||||
name: 'test',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>})
|
||||
});
|
||||
var testPipe =
|
||||
new CompilePipeMetadata({
|
||||
name: 'test',
|
||||
type: new CompileTypeMetadata(
|
||||
{moduleUrl: someModuleUrl, name: 'DirA', reference: {} as Type<any>})
|
||||
}).toSummary();
|
||||
expect(() => parse('{{a | test}}', [], [testPipe])).not.toThrow();
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue