refactor(core): remove `ViewResolver` and `ViewResolverMock`
The methods on `ViewResolverMock` have been merged into `DirectiveResolver`. BREAKING CHANGE: - ES5 users can no longer use the `View(…)` function to provide `ViewMetadata`. This mirrors the removal of the `@View` decorator a while ago.
This commit is contained in:
parent
20b03bad11
commit
0988cc82b0
|
@ -143,8 +143,7 @@ export class CodeGenerator {
|
|||
const resolver = new CompileMetadataResolver(
|
||||
new compiler.NgModuleResolver(staticReflector),
|
||||
new compiler.DirectiveResolver(staticReflector), new compiler.PipeResolver(staticReflector),
|
||||
new compiler.ViewResolver(staticReflector), config, console, elementSchemaRegistry,
|
||||
staticReflector);
|
||||
config, console, elementSchemaRegistry, staticReflector);
|
||||
const offlineCompiler = new compiler.OfflineCompiler(
|
||||
resolver, normalizer, tmplParser, new StyleCompiler(urlResolver), new ViewCompiler(config),
|
||||
new NgModuleCompiler(), new TypeScriptEmitter(reflectorHost));
|
||||
|
|
|
@ -152,8 +152,7 @@ class Extractor {
|
|||
const resolver = new CompileMetadataResolver(
|
||||
new compiler.NgModuleResolver(staticReflector),
|
||||
new compiler.DirectiveResolver(staticReflector), new compiler.PipeResolver(staticReflector),
|
||||
new compiler.ViewResolver(staticReflector), config, console, elementSchemaRegistry,
|
||||
staticReflector);
|
||||
config, console, elementSchemaRegistry, staticReflector);
|
||||
|
||||
// TODO(vicb): handle implicit
|
||||
const extractor = new MessageExtractor(htmlParser, expressionParser, [], {});
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
* @description
|
||||
* Starting point to import all compiler APIs.
|
||||
*/
|
||||
export {COMPILER_PROVIDERS, CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileFactoryMetadata, CompileIdentifierMetadata, CompileMetadataWithIdentifier, CompilePipeMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTemplateMetadata, CompileTokenMetadata, CompileTypeMetadata, CompilerConfig, DEFAULT_PACKAGE_URL_PROVIDER, DirectiveResolver, NgModuleResolver, OfflineCompiler, PipeResolver, RenderTypes, RuntimeCompiler, SourceModule, TEMPLATE_TRANSFORMS, UrlResolver, ViewResolver, XHR, analyzeAppProvidersForDeprecatedConfiguration, createOfflineCompileUrlResolver, platformCoreDynamic} from './src/compiler';
|
||||
export {COMPILER_PROVIDERS, CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileFactoryMetadata, CompileIdentifierMetadata, CompileMetadataWithIdentifier, CompilePipeMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTemplateMetadata, CompileTokenMetadata, CompileTypeMetadata, CompilerConfig, DEFAULT_PACKAGE_URL_PROVIDER, DirectiveResolver, NgModuleResolver, OfflineCompiler, PipeResolver, RenderTypes, RuntimeCompiler, SourceModule, TEMPLATE_TRANSFORMS, UrlResolver, XHR, analyzeAppProvidersForDeprecatedConfiguration, createOfflineCompileUrlResolver, platformCoreDynamic} from './src/compiler';
|
||||
export {ElementSchemaRegistry} from './src/schema/element_schema_registry';
|
||||
|
||||
export * from './src/template_ast';
|
||||
|
|
|
@ -406,7 +406,8 @@ export class CompileTemplateMetadata {
|
|||
export class CompileDirectiveMetadata implements CompileMetadataWithIdentifier {
|
||||
static create(
|
||||
{type, isComponent, selector, exportAs, changeDetection, inputs, outputs, host,
|
||||
lifecycleHooks, providers, viewProviders, queries, viewQueries, entryComponents, template}: {
|
||||
lifecycleHooks, providers, viewProviders, queries, viewQueries, entryComponents,
|
||||
viewDirectives, viewPipes, template}: {
|
||||
type?: CompileTypeMetadata,
|
||||
isComponent?: boolean,
|
||||
selector?: string,
|
||||
|
@ -423,6 +424,8 @@ export class CompileDirectiveMetadata implements CompileMetadataWithIdentifier {
|
|||
queries?: CompileQueryMetadata[],
|
||||
viewQueries?: CompileQueryMetadata[],
|
||||
entryComponents?: CompileTypeMetadata[],
|
||||
viewDirectives?: CompileTypeMetadata[],
|
||||
viewPipes?: CompileTypeMetadata[],
|
||||
template?: CompileTemplateMetadata
|
||||
} = {}): CompileDirectiveMetadata {
|
||||
var hostListeners: {[key: string]: string} = {};
|
||||
|
@ -472,6 +475,8 @@ export class CompileDirectiveMetadata implements CompileMetadataWithIdentifier {
|
|||
queries,
|
||||
viewQueries,
|
||||
entryComponents,
|
||||
viewDirectives,
|
||||
viewPipes,
|
||||
template,
|
||||
});
|
||||
}
|
||||
|
@ -492,12 +497,17 @@ export class CompileDirectiveMetadata implements CompileMetadataWithIdentifier {
|
|||
viewQueries: CompileQueryMetadata[];
|
||||
// Note: Need to keep types here to prevent cycles!
|
||||
entryComponents: CompileTypeMetadata[];
|
||||
// Note: Need to keep types here to prevent cycles!
|
||||
viewDirectives: CompileTypeMetadata[];
|
||||
// Note: Need to keep types here to prevent cycles!
|
||||
viewPipes: CompileTypeMetadata[];
|
||||
|
||||
template: CompileTemplateMetadata;
|
||||
|
||||
constructor(
|
||||
{type, isComponent, selector, exportAs, changeDetection, inputs, outputs, hostListeners,
|
||||
hostProperties, hostAttributes, lifecycleHooks, providers, viewProviders, queries,
|
||||
viewQueries, entryComponents, template}: {
|
||||
viewQueries, entryComponents, viewDirectives, viewPipes, template}: {
|
||||
type?: CompileTypeMetadata,
|
||||
isComponent?: boolean,
|
||||
selector?: string,
|
||||
|
@ -516,6 +526,8 @@ export class CompileDirectiveMetadata implements CompileMetadataWithIdentifier {
|
|||
queries?: CompileQueryMetadata[],
|
||||
viewQueries?: CompileQueryMetadata[],
|
||||
entryComponents?: CompileTypeMetadata[],
|
||||
viewDirectives?: CompileTypeMetadata[],
|
||||
viewPipes?: CompileTypeMetadata[],
|
||||
template?: CompileTemplateMetadata,
|
||||
} = {}) {
|
||||
this.type = type;
|
||||
|
@ -534,6 +546,9 @@ export class CompileDirectiveMetadata implements CompileMetadataWithIdentifier {
|
|||
this.queries = _normalizeArray(queries);
|
||||
this.viewQueries = _normalizeArray(viewQueries);
|
||||
this.entryComponents = _normalizeArray(entryComponents);
|
||||
this.viewDirectives = _normalizeArray(viewDirectives);
|
||||
this.viewPipes = _normalizeArray(viewPipes);
|
||||
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ export {RuntimeCompiler} from './runtime_compiler';
|
|||
export * from './url_resolver';
|
||||
export * from './xhr';
|
||||
|
||||
export {ViewResolver} from './view_resolver';
|
||||
export {DirectiveResolver} from './directive_resolver';
|
||||
export {PipeResolver} from './pipe_resolver';
|
||||
export {NgModuleResolver} from './ng_module_resolver';
|
||||
|
@ -38,7 +37,6 @@ import {DomElementSchemaRegistry} from './schema/dom_element_schema_registry';
|
|||
import {UrlResolver, DEFAULT_PACKAGE_URL_PROVIDER} from './url_resolver';
|
||||
import {Parser} from './expression_parser/parser';
|
||||
import {Lexer} from './expression_parser/lexer';
|
||||
import {ViewResolver} from './view_resolver';
|
||||
import {DirectiveResolver} from './directive_resolver';
|
||||
import {PipeResolver} from './pipe_resolver';
|
||||
import {NgModuleResolver} from './ng_module_resolver';
|
||||
|
@ -76,7 +74,6 @@ export const COMPILER_PROVIDERS: Array<any|Type|{[k: string]: any}|any[]> =
|
|||
DomElementSchemaRegistry,
|
||||
/*@ts2dart_Provider*/ {provide: ElementSchemaRegistry, useExisting: DomElementSchemaRegistry},
|
||||
UrlResolver,
|
||||
ViewResolver,
|
||||
DirectiveResolver,
|
||||
PipeResolver,
|
||||
NgModuleResolver
|
||||
|
|
|
@ -143,7 +143,16 @@ export class DirectiveResolver {
|
|||
changeDetection: dm.changeDetection,
|
||||
providers: dm.providers,
|
||||
viewProviders: dm.viewProviders,
|
||||
entryComponents: dm.entryComponents
|
||||
entryComponents: dm.entryComponents,
|
||||
directives: dm.directives,
|
||||
pipes: dm.pipes,
|
||||
template: dm.template,
|
||||
templateUrl: dm.templateUrl,
|
||||
styles: dm.styles,
|
||||
styleUrls: dm.styleUrls,
|
||||
encapsulation: dm.encapsulation,
|
||||
animations: dm.animations,
|
||||
interpolation: dm.interpolation
|
||||
});
|
||||
|
||||
} else {
|
||||
|
|
|
@ -24,7 +24,6 @@ import {PipeResolver} from './pipe_resolver';
|
|||
import {ElementSchemaRegistry} from './schema/element_schema_registry';
|
||||
import {getUrlScheme} from './url_resolver';
|
||||
import {MODULE_SUFFIX, ValueTransformer, sanitizeIdentifier, visitValue} from './util';
|
||||
import {ViewResolver} from './view_resolver';
|
||||
|
||||
@Injectable()
|
||||
export class CompileMetadataResolver {
|
||||
|
@ -37,10 +36,8 @@ export class CompileMetadataResolver {
|
|||
|
||||
constructor(
|
||||
private _ngModuleResolver: NgModuleResolver, private _directiveResolver: DirectiveResolver,
|
||||
private _pipeResolver: PipeResolver, private _viewResolver: ViewResolver,
|
||||
private _config: CompilerConfig, private _console: Console,
|
||||
private _schemaRegistry: ElementSchemaRegistry,
|
||||
private _reflector: ReflectorReader = reflector) {}
|
||||
private _pipeResolver: PipeResolver, private _config: CompilerConfig,
|
||||
private _console: Console, private _schemaRegistry: ElementSchemaRegistry, private _reflector: ReflectorReader = reflector) {}
|
||||
|
||||
private sanitizeTokenName(token: any): string {
|
||||
let identifier = stringify(token);
|
||||
|
@ -125,27 +122,28 @@ export class CompileMetadataResolver {
|
|||
var changeDetectionStrategy: ChangeDetectionStrategy = null;
|
||||
var viewProviders: Array<cpl.CompileProviderMetadata|cpl.CompileTypeMetadata|any[]> = [];
|
||||
var moduleUrl = staticTypeModuleUrl(directiveType);
|
||||
var viewDirectiveTypes: cpl.CompileTypeMetadata[] = [];
|
||||
var viewPipeTypes: cpl.CompileTypeMetadata[] = [];
|
||||
var entryComponentTypes: cpl.CompileTypeMetadata[] = [];
|
||||
let selector = dirMeta.selector;
|
||||
if (dirMeta instanceof ComponentMetadata) {
|
||||
var cmpMeta = <ComponentMetadata>dirMeta;
|
||||
var viewMeta = this._viewResolver.resolve(directiveType);
|
||||
assertArrayOfStrings('styles', viewMeta.styles);
|
||||
assertInterpolationSymbols('interpolation', viewMeta.interpolation);
|
||||
var animations = isPresent(viewMeta.animations) ?
|
||||
viewMeta.animations.map(e => this.getAnimationEntryMetadata(e)) :
|
||||
assertArrayOfStrings('styles', cmpMeta.styles);
|
||||
assertInterpolationSymbols('interpolation', cmpMeta.interpolation);
|
||||
var animations = isPresent(cmpMeta.animations) ?
|
||||
cmpMeta.animations.map(e => this.getAnimationEntryMetadata(e)) :
|
||||
null;
|
||||
assertArrayOfStrings('styles', viewMeta.styles);
|
||||
assertArrayOfStrings('styleUrls', viewMeta.styleUrls);
|
||||
assertArrayOfStrings('styles', cmpMeta.styles);
|
||||
assertArrayOfStrings('styleUrls', cmpMeta.styleUrls);
|
||||
|
||||
templateMeta = new cpl.CompileTemplateMetadata({
|
||||
encapsulation: viewMeta.encapsulation,
|
||||
template: viewMeta.template,
|
||||
templateUrl: viewMeta.templateUrl,
|
||||
styles: viewMeta.styles,
|
||||
styleUrls: viewMeta.styleUrls,
|
||||
encapsulation: cmpMeta.encapsulation,
|
||||
template: cmpMeta.template,
|
||||
templateUrl: cmpMeta.templateUrl,
|
||||
styles: cmpMeta.styles,
|
||||
styleUrls: cmpMeta.styleUrls,
|
||||
animations: animations,
|
||||
interpolation: viewMeta.interpolation
|
||||
interpolation: cmpMeta.interpolation
|
||||
});
|
||||
changeDetectionStrategy = cmpMeta.changeDetection;
|
||||
if (isPresent(dirMeta.viewProviders)) {
|
||||
|
@ -156,7 +154,26 @@ export class CompileMetadataResolver {
|
|||
if (cmpMeta.entryComponents) {
|
||||
entryComponentTypes =
|
||||
flattenArray(cmpMeta.entryComponents)
|
||||
.map((cmp) => this.getTypeMetadata(cmp, staticTypeModuleUrl(cmp)));
|
||||
.map((type) => this.getTypeMetadata(type, staticTypeModuleUrl(type)));
|
||||
}
|
||||
if (cmpMeta.directives) {
|
||||
viewDirectiveTypes = flattenArray(cmpMeta.directives).map((type) => {
|
||||
if (!type) {
|
||||
throw new BaseException(
|
||||
`Unexpected directive value '${type}' on the View of component '${stringify(directiveType)}'`);
|
||||
}
|
||||
|
||||
return this.getTypeMetadata(type, staticTypeModuleUrl(type));
|
||||
});
|
||||
}
|
||||
if (cmpMeta.pipes) {
|
||||
viewPipeTypes = flattenArray(cmpMeta.pipes).map((type) => {
|
||||
if (!type) {
|
||||
throw new BaseException(
|
||||
`Unexpected pipe value '${type}' on the View of component '${stringify(directiveType)}'`);
|
||||
}
|
||||
return this.getTypeMetadata(type, staticTypeModuleUrl(type));
|
||||
});
|
||||
}
|
||||
if (!selector) {
|
||||
selector = this._schemaRegistry.getDefaultComponentElementName();
|
||||
|
@ -196,6 +213,8 @@ export class CompileMetadataResolver {
|
|||
viewProviders: viewProviders,
|
||||
queries: queries,
|
||||
viewQueries: viewQueries,
|
||||
viewDirectives: viewDirectiveTypes,
|
||||
viewPipes: viewPipeTypes,
|
||||
entryComponents: entryComponentTypes
|
||||
});
|
||||
this._directiveCache.set(directiveType, meta);
|
||||
|
@ -386,20 +405,12 @@ export class CompileMetadataResolver {
|
|||
return;
|
||||
}
|
||||
const addPipe = (pipeType: Type) => {
|
||||
if (!pipeType) {
|
||||
throw new BaseException(
|
||||
`Unexpected pipe value '${pipeType}' on the View of component '${stringify(compMeta.type.runtime)}'`);
|
||||
}
|
||||
const pipeMeta = this.getPipeMetadata(pipeType);
|
||||
this._addPipeToModule(
|
||||
pipeMeta, moduleMeta.type.runtime, moduleMeta.transitiveModule, moduleMeta.declaredPipes);
|
||||
};
|
||||
|
||||
const addDirective = (dirType: Type) => {
|
||||
if (!dirType) {
|
||||
throw new BaseException(
|
||||
`Unexpected directive value '${dirType}' on the View of component '${stringify(compMeta.type.runtime)}'`);
|
||||
}
|
||||
const dirMeta = this.getDirectiveMetadata(dirType);
|
||||
if (this._addDirectiveToModule(
|
||||
dirMeta, moduleMeta.type.runtime, moduleMeta.transitiveModule,
|
||||
|
@ -407,12 +418,11 @@ export class CompileMetadataResolver {
|
|||
this._getTransitiveViewDirectivesAndPipes(dirMeta, moduleMeta);
|
||||
}
|
||||
};
|
||||
const view = this._viewResolver.resolve(compMeta.type.runtime);
|
||||
if (view.pipes) {
|
||||
flattenArray(view.pipes).forEach(addPipe);
|
||||
if (compMeta.viewPipes) {
|
||||
compMeta.viewPipes.forEach((cplType) => addPipe(cplType.runtime));
|
||||
}
|
||||
if (view.directives) {
|
||||
flattenArray(view.directives).forEach(addDirective);
|
||||
if (compMeta.viewDirectives) {
|
||||
compMeta.viewDirectives.forEach((cplType) => addDirective(cplType.runtime));
|
||||
}
|
||||
compMeta.entryComponents.forEach((entryComponentType) => {
|
||||
if (!moduleMeta.transitiveModule.directivesSet.has(entryComponentType.runtime)) {
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Injectable, ViewMetadata, ComponentMetadata,} from '@angular/core';
|
||||
import {ReflectorReader, reflector} from '../core_private';
|
||||
import {Type, stringify, isBlank, isPresent} from '../src/facade/lang';
|
||||
import {BaseException} from '../src/facade/exceptions';
|
||||
|
||||
function _isComponentMetadata(obj: any): obj is ComponentMetadata {
|
||||
return obj instanceof ComponentMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves types to {@link ViewMetadata}.
|
||||
*/
|
||||
@Injectable()
|
||||
export class ViewResolver {
|
||||
constructor(private _reflector: ReflectorReader = reflector) {}
|
||||
|
||||
resolve(component: Type, throwIfNotFound = true): ViewMetadata {
|
||||
const compMeta: ComponentMetadata =
|
||||
this._reflector.annotations(component).find(_isComponentMetadata);
|
||||
|
||||
if (isPresent(compMeta)) {
|
||||
if (isBlank(compMeta.template) && isBlank(compMeta.templateUrl)) {
|
||||
throw new BaseException(
|
||||
`Component '${stringify(component)}' must have either 'template' or 'templateUrl' set.`);
|
||||
|
||||
} else {
|
||||
return new ViewMetadata({
|
||||
templateUrl: compMeta.templateUrl,
|
||||
template: compMeta.template,
|
||||
directives: compMeta.directives,
|
||||
pipes: compMeta.pipes,
|
||||
encapsulation: compMeta.encapsulation,
|
||||
styles: compMeta.styles,
|
||||
styleUrls: compMeta.styleUrls,
|
||||
animations: compMeta.animations,
|
||||
interpolation: compMeta.interpolation
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (throwIfNotFound) {
|
||||
throw new BaseException(
|
||||
`Could not compile '${stringify(component)}' because it is not a component.`);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,34 +9,35 @@
|
|||
import {beforeEach, ddescribe, describe, expect, iit, it, inject,} from '@angular/core/testing/testing_internal';
|
||||
|
||||
import {stringify, isBlank} from '../src/facade/lang';
|
||||
import {MockViewResolver} from '../testing';
|
||||
import {Component, ViewMetadata, Injector} from '@angular/core';
|
||||
import {MockDirectiveResolver} from '../testing';
|
||||
import {Component, ViewMetadata, Injector, ComponentMetadata} from '@angular/core';
|
||||
|
||||
export function main() {
|
||||
describe('MockViewResolver', () => {
|
||||
var viewResolver: MockViewResolver;
|
||||
describe('MockDirectiveResolver', () => {
|
||||
var dirResolver: MockDirectiveResolver;
|
||||
|
||||
beforeEach(inject(
|
||||
[Injector], (injector: Injector) => { viewResolver = new MockViewResolver(injector); }));
|
||||
beforeEach(inject([Injector], (injector: Injector) => {
|
||||
dirResolver = new MockDirectiveResolver(injector);
|
||||
}));
|
||||
|
||||
describe('View overriding', () => {
|
||||
it('should fallback to the default ViewResolver when templates are not overridden', () => {
|
||||
var view = viewResolver.resolve(SomeComponent);
|
||||
var view = <ComponentMetadata>dirResolver.resolve(SomeComponent);
|
||||
expect(view.template).toEqual('template');
|
||||
expect(view.directives).toEqual([SomeDirective]);
|
||||
});
|
||||
|
||||
it('should allow overriding the @View', () => {
|
||||
viewResolver.setView(SomeComponent, new ViewMetadata({template: 'overridden template'}));
|
||||
var view = viewResolver.resolve(SomeComponent);
|
||||
dirResolver.setView(SomeComponent, new ViewMetadata({template: 'overridden template'}));
|
||||
var view = <ComponentMetadata>dirResolver.resolve(SomeComponent);
|
||||
expect(view.template).toEqual('overridden template');
|
||||
expect(isBlank(view.directives)).toBe(true);
|
||||
});
|
||||
|
||||
it('should allow overriding a view after it has been resolved', () => {
|
||||
viewResolver.resolve(SomeComponent);
|
||||
viewResolver.setView(SomeComponent, new ViewMetadata({template: 'overridden template'}));
|
||||
var view = viewResolver.resolve(SomeComponent);
|
||||
dirResolver.resolve(SomeComponent);
|
||||
dirResolver.setView(SomeComponent, new ViewMetadata({template: 'overridden template'}));
|
||||
var view = <ComponentMetadata>dirResolver.resolve(SomeComponent);
|
||||
expect(view.template).toEqual('overridden template');
|
||||
expect(isBlank(view.directives)).toBe(true);
|
||||
});
|
||||
|
@ -44,23 +45,23 @@ export function main() {
|
|||
|
||||
describe('inline template definition overriding', () => {
|
||||
it('should allow overriding the default template', () => {
|
||||
viewResolver.setInlineTemplate(SomeComponent, 'overridden template');
|
||||
var view = viewResolver.resolve(SomeComponent);
|
||||
dirResolver.setInlineTemplate(SomeComponent, 'overridden template');
|
||||
var view = <ComponentMetadata>dirResolver.resolve(SomeComponent);
|
||||
expect(view.template).toEqual('overridden template');
|
||||
expect(view.directives).toEqual([SomeDirective]);
|
||||
});
|
||||
|
||||
it('should allow overriding an overridden @View', () => {
|
||||
viewResolver.setView(SomeComponent, new ViewMetadata({template: 'overridden template'}));
|
||||
viewResolver.setInlineTemplate(SomeComponent, 'overridden template x 2');
|
||||
var view = viewResolver.resolve(SomeComponent);
|
||||
dirResolver.setView(SomeComponent, new ViewMetadata({template: 'overridden template'}));
|
||||
dirResolver.setInlineTemplate(SomeComponent, 'overridden template x 2');
|
||||
var view = <ComponentMetadata>dirResolver.resolve(SomeComponent);
|
||||
expect(view.template).toEqual('overridden template x 2');
|
||||
});
|
||||
|
||||
it('should allow overriding a view after it has been resolved', () => {
|
||||
viewResolver.resolve(SomeComponent);
|
||||
viewResolver.setInlineTemplate(SomeComponent, 'overridden template');
|
||||
var view = viewResolver.resolve(SomeComponent);
|
||||
dirResolver.resolve(SomeComponent);
|
||||
dirResolver.setInlineTemplate(SomeComponent, 'overridden template');
|
||||
var view = <ComponentMetadata>dirResolver.resolve(SomeComponent);
|
||||
expect(view.template).toEqual('overridden template');
|
||||
});
|
||||
});
|
||||
|
@ -68,31 +69,31 @@ export function main() {
|
|||
|
||||
describe('Directive overriding', () => {
|
||||
it('should allow overriding a directive from the default view', () => {
|
||||
viewResolver.overrideViewDirective(SomeComponent, SomeDirective, SomeOtherDirective);
|
||||
var view = viewResolver.resolve(SomeComponent);
|
||||
dirResolver.overrideViewDirective(SomeComponent, SomeDirective, SomeOtherDirective);
|
||||
var view = <ComponentMetadata>dirResolver.resolve(SomeComponent);
|
||||
expect(view.directives.length).toEqual(1);
|
||||
expect(view.directives[0]).toBe(SomeOtherDirective);
|
||||
});
|
||||
|
||||
it('should allow overriding a directive from an overridden @View', () => {
|
||||
viewResolver.setView(SomeComponent, new ViewMetadata({directives: [SomeOtherDirective]}));
|
||||
viewResolver.overrideViewDirective(SomeComponent, SomeOtherDirective, SomeComponent);
|
||||
var view = viewResolver.resolve(SomeComponent);
|
||||
dirResolver.setView(SomeComponent, new ViewMetadata({directives: [SomeOtherDirective]}));
|
||||
dirResolver.overrideViewDirective(SomeComponent, SomeOtherDirective, SomeComponent);
|
||||
var view = <ComponentMetadata>dirResolver.resolve(SomeComponent);
|
||||
expect(view.directives.length).toEqual(1);
|
||||
expect(view.directives[0]).toBe(SomeComponent);
|
||||
});
|
||||
|
||||
it('should throw when the overridden directive is not present', () => {
|
||||
viewResolver.overrideViewDirective(SomeComponent, SomeOtherDirective, SomeDirective);
|
||||
expect(() => { viewResolver.resolve(SomeComponent); })
|
||||
dirResolver.overrideViewDirective(SomeComponent, SomeOtherDirective, SomeDirective);
|
||||
expect(() => { dirResolver.resolve(SomeComponent); })
|
||||
.toThrowError(
|
||||
`Overriden directive ${stringify(SomeOtherDirective)} not found in the template of ${stringify(SomeComponent)}`);
|
||||
});
|
||||
|
||||
it('should allow overriding a directive after its view has been resolved', () => {
|
||||
viewResolver.resolve(SomeComponent);
|
||||
viewResolver.overrideViewDirective(SomeComponent, SomeDirective, SomeOtherDirective);
|
||||
var view = viewResolver.resolve(SomeComponent);
|
||||
dirResolver.resolve(SomeComponent);
|
||||
dirResolver.overrideViewDirective(SomeComponent, SomeDirective, SomeOtherDirective);
|
||||
var view = <ComponentMetadata>dirResolver.resolve(SomeComponent);
|
||||
expect(view.directives.length).toEqual(1);
|
||||
expect(view.directives[0]).toBe(SomeOtherDirective);
|
||||
});
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
import {DirectiveResolver} from '@angular/compiler/src/directive_resolver';
|
||||
import {ContentChild, ContentChildren, Directive, DirectiveMetadata, HostBinding, HostListener, Input, Output, ViewChild, ViewChildren} from '@angular/core/src/metadata';
|
||||
import {Component, ComponentMetadata, ContentChild, ContentChildren, Directive, DirectiveMetadata, HostBinding, HostListener, Input, Output, ViewChild, ViewChildren} from '@angular/core/src/metadata';
|
||||
|
||||
@Directive({selector: 'someDirective'})
|
||||
class SomeDirective {
|
||||
|
@ -104,6 +104,19 @@ class SomeDirectiveWithViewChild {
|
|||
c: any;
|
||||
}
|
||||
|
||||
class SomeDir {}
|
||||
class SomePipe {}
|
||||
|
||||
@Component({
|
||||
selector: 'sample',
|
||||
template: 'some template',
|
||||
directives: [SomeDir],
|
||||
pipes: [SomePipe],
|
||||
styles: ['some styles']
|
||||
})
|
||||
class ComponentWithTemplate {
|
||||
}
|
||||
|
||||
class SomeDirectiveWithoutMetadata {}
|
||||
|
||||
export function main() {
|
||||
|
@ -218,5 +231,15 @@ export function main() {
|
|||
.toEqual({'c': new ViewChild('c'), 'a': new ViewChild('a')});
|
||||
});
|
||||
});
|
||||
|
||||
describe('view', () => {
|
||||
it('should read out the template related metadata from the Component metadata', () => {
|
||||
var compMetadata = <ComponentMetadata>resolver.resolve(ComponentWithTemplate);
|
||||
expect(compMetadata.template).toEqual('some template');
|
||||
expect(compMetadata.directives).toEqual([SomeDir]);
|
||||
expect(compMetadata.pipes).toEqual([SomePipe]);
|
||||
expect(compMetadata.styles).toEqual(['some styles']);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -35,8 +35,8 @@ export function main() {
|
|||
beforeEach(() => { resolver = new NgModuleResolver(); });
|
||||
|
||||
it('should read out the metadata from the class', () => {
|
||||
var viewMetadata = resolver.resolve(SomeModule);
|
||||
expect(viewMetadata).toEqual(new NgModuleMetadata({
|
||||
var moduleMetadata = resolver.resolve(SomeModule);
|
||||
expect(moduleMetadata).toEqual(new NgModuleMetadata({
|
||||
declarations: [SomeClass1],
|
||||
imports: [SomeClass2],
|
||||
exports: [SomeClass3],
|
||||
|
|
|
@ -11,8 +11,8 @@ import {expect} from '@angular/platform-browser/testing/matchers';
|
|||
import {Injectable, Component, Input, ViewMetadata, Compiler, ComponentFactory, Injector, NgModule, NgModuleFactory} from '@angular/core';
|
||||
import {ConcreteType, stringify} from '../src/facade/lang';
|
||||
import {fakeAsync, tick, TestComponentBuilder, ComponentFixture, configureCompiler} from '@angular/core/testing';
|
||||
import {XHR, ViewResolver} from '@angular/compiler';
|
||||
import {MockViewResolver} from '@angular/compiler/testing';
|
||||
import {XHR, DirectiveResolver} from '@angular/compiler';
|
||||
import {MockDirectiveResolver} from '@angular/compiler/testing';
|
||||
|
||||
import {SpyXHR} from './spies';
|
||||
|
||||
|
@ -33,19 +33,19 @@ export function main() {
|
|||
let compiler: Compiler;
|
||||
let xhr: SpyXHR;
|
||||
let tcb: TestComponentBuilder;
|
||||
let viewResolver: MockViewResolver;
|
||||
let dirResolver: MockDirectiveResolver;
|
||||
let injector: Injector;
|
||||
|
||||
beforeEach(() => { configureCompiler({providers: [{provide: XHR, useClass: SpyXHR}]}); });
|
||||
|
||||
beforeEach(inject(
|
||||
[Compiler, TestComponentBuilder, XHR, ViewResolver, Injector],
|
||||
[Compiler, TestComponentBuilder, XHR, DirectiveResolver, Injector],
|
||||
(_compiler: Compiler, _tcb: TestComponentBuilder, _xhr: SpyXHR,
|
||||
_viewResolver: MockViewResolver, _injector: Injector) => {
|
||||
_dirResolver: MockDirectiveResolver, _injector: Injector) => {
|
||||
compiler = _compiler;
|
||||
tcb = _tcb;
|
||||
xhr = _xhr;
|
||||
viewResolver = _viewResolver;
|
||||
dirResolver = _dirResolver;
|
||||
injector = _injector;
|
||||
}));
|
||||
|
||||
|
@ -74,12 +74,12 @@ export function main() {
|
|||
});
|
||||
|
||||
it('should not update existing compilation results', () => {
|
||||
viewResolver.setView(
|
||||
dirResolver.setView(
|
||||
SomeComp,
|
||||
new ViewMetadata({template: '<child-cmp></child-cmp>', directives: [ChildComp]}));
|
||||
viewResolver.setInlineTemplate(ChildComp, 'oldChild');
|
||||
dirResolver.setInlineTemplate(ChildComp, 'oldChild');
|
||||
let compFactory = compiler.compileComponentSync(SomeComp);
|
||||
viewResolver.setInlineTemplate(ChildComp, 'newChild');
|
||||
dirResolver.setInlineTemplate(ChildComp, 'newChild');
|
||||
compiler.compileComponentSync(SomeComp);
|
||||
let compRef = compFactory.create(injector);
|
||||
expect(compRef.location.nativeElement).toHaveText('oldChild');
|
||||
|
@ -151,9 +151,8 @@ export function main() {
|
|||
}
|
||||
|
||||
xhr.spy('get').andCallFake(() => Promise.resolve(''));
|
||||
viewResolver.setView(
|
||||
SomeComp, new ViewMetadata({template: '', directives: [ChildComp]}));
|
||||
viewResolver.setView(ChildComp, new ViewMetadata({templateUrl: '/someTpl.html'}));
|
||||
dirResolver.setView(SomeComp, new ViewMetadata({template: '', directives: [ChildComp]}));
|
||||
dirResolver.setView(ChildComp, new ViewMetadata({templateUrl: '/someTpl.html'}));
|
||||
expect(() => compiler.compileModuleSync(SomeModule))
|
||||
.toThrowError(
|
||||
`Can't compile synchronously as ${stringify(ChildComp)} is still being loaded!`);
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ViewResolver} from '@angular/compiler/src/view_resolver';
|
||||
import {Component, ViewMetadata} from '@angular/core/src/metadata';
|
||||
|
||||
class SomeDir {}
|
||||
class SomePipe {}
|
||||
|
||||
@Component({
|
||||
selector: 'sample',
|
||||
template: 'some template',
|
||||
directives: [SomeDir],
|
||||
pipes: [SomePipe],
|
||||
styles: ['some styles']
|
||||
})
|
||||
class ComponentWithTemplate {
|
||||
}
|
||||
|
||||
@Component({selector: 'sample'})
|
||||
class ComponentWithoutView {
|
||||
}
|
||||
|
||||
|
||||
class SimpleClass {}
|
||||
|
||||
export function main() {
|
||||
describe('ViewResolver', () => {
|
||||
var resolver: ViewResolver;
|
||||
|
||||
beforeEach(() => { resolver = new ViewResolver(); });
|
||||
|
||||
it('should read out the View metadata from the Component metadata', () => {
|
||||
var viewMetadata = resolver.resolve(ComponentWithTemplate);
|
||||
expect(viewMetadata).toEqual(new ViewMetadata({
|
||||
template: 'some template',
|
||||
directives: [SomeDir],
|
||||
pipes: [SomePipe],
|
||||
styles: ['some styles']
|
||||
}));
|
||||
});
|
||||
|
||||
it('should throw when Component has neither template nor templateUrl set', () => {
|
||||
expect(() => resolver.resolve(ComponentWithoutView))
|
||||
.toThrowError(
|
||||
/Component 'ComponentWithoutView' must have either 'template' or 'templateUrl' set/);
|
||||
});
|
||||
|
||||
it('should throw when simple class has no component decorator', () => {
|
||||
expect(() => resolver.resolve(SimpleClass))
|
||||
.toThrowError('Could not compile \'SimpleClass\' because it is not a component.');
|
||||
});
|
||||
});
|
||||
}
|
|
@ -7,14 +7,12 @@
|
|||
*/
|
||||
|
||||
export * from './testing/schema_registry_mock';
|
||||
export * from './testing/view_resolver_mock';
|
||||
export * from './testing/test_component_builder';
|
||||
export * from './testing/directive_resolver_mock';
|
||||
export * from './testing/ng_module_resolver_mock';
|
||||
|
||||
import {createPlatformFactory, CompilerOptions, PlatformRef} from '@angular/core';
|
||||
import {platformCoreDynamic, DirectiveResolver, ViewResolver, NgModuleResolver} from './index';
|
||||
import {MockViewResolver} from './testing/view_resolver_mock';
|
||||
import {platformCoreDynamic, DirectiveResolver, NgModuleResolver} from './index';
|
||||
import {MockDirectiveResolver} from './testing/directive_resolver_mock';
|
||||
import {MockNgModuleResolver} from './testing/ng_module_resolver_mock';
|
||||
|
||||
|
@ -30,7 +28,6 @@ export const platformCoreDynamicTesting =
|
|||
useValue: {
|
||||
providers: [
|
||||
{provide: DirectiveResolver, useClass: MockDirectiveResolver},
|
||||
{provide: ViewResolver, useClass: MockViewResolver},
|
||||
{provide: NgModuleResolver, useClass: MockNgModuleResolver}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Compiler, ComponentMetadata, DirectiveMetadata, Injectable, Injector} from '@angular/core';
|
||||
import {AnimationEntryMetadata, Compiler, ComponentMetadata, DirectiveMetadata, Injectable, Injector, ViewMetadata, resolveForwardRef} from '@angular/core';
|
||||
|
||||
import {DirectiveResolver} from '../src/directive_resolver';
|
||||
import {Map} from '../src/facade/collection';
|
||||
import {Type, isPresent} from '../src/facade/lang';
|
||||
|
||||
import {BaseException} from '../src/facade/exceptions';
|
||||
import {Type, isArray, isPresent, stringify} from '../src/facade/lang';
|
||||
|
||||
|
||||
/**
|
||||
|
@ -22,33 +22,75 @@ import {Type, isPresent} from '../src/facade/lang';
|
|||
export class MockDirectiveResolver extends DirectiveResolver {
|
||||
private _providerOverrides = new Map<Type, any[]>();
|
||||
private viewProviderOverrides = new Map<Type, any[]>();
|
||||
private _views = new Map<Type, ViewMetadata>();
|
||||
private _inlineTemplates = new Map<Type, string>();
|
||||
private _animations = new Map<Type, AnimationEntryMetadata[]>();
|
||||
private _directiveOverrides = new Map<Type, Map<Type, Type>>();
|
||||
|
||||
constructor(private _injector: Injector) { super(); }
|
||||
|
||||
private get _compiler(): Compiler { return this._injector.get(Compiler); }
|
||||
|
||||
private _clearCacheFor(component: Type) { this._compiler.clearCacheFor(component); }
|
||||
|
||||
resolve(type: Type, throwIfNotFound = true): DirectiveMetadata {
|
||||
var dm = super.resolve(type, throwIfNotFound);
|
||||
const dm = super.resolve(type, throwIfNotFound);
|
||||
if (!dm) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var providerOverrides = this._providerOverrides.get(type);
|
||||
var viewProviderOverrides = this.viewProviderOverrides.get(type);
|
||||
const providerOverrides = this._providerOverrides.get(type);
|
||||
const viewProviderOverrides = this.viewProviderOverrides.get(type);
|
||||
|
||||
var providers = dm.providers;
|
||||
let providers = dm.providers;
|
||||
if (isPresent(providerOverrides)) {
|
||||
var originalViewProviders: any[] = isPresent(dm.providers) ? dm.providers : [];
|
||||
const originalViewProviders: any[] = isPresent(dm.providers) ? dm.providers : [];
|
||||
providers = originalViewProviders.concat(providerOverrides);
|
||||
}
|
||||
|
||||
if (dm instanceof ComponentMetadata) {
|
||||
var viewProviders = dm.viewProviders;
|
||||
let viewProviders = dm.viewProviders;
|
||||
if (isPresent(viewProviderOverrides)) {
|
||||
var originalViewProviders: any[] = isPresent(dm.viewProviders) ? dm.viewProviders : [];
|
||||
const originalViewProviders: any[] = isPresent(dm.viewProviders) ? dm.viewProviders : [];
|
||||
viewProviders = originalViewProviders.concat(viewProviderOverrides);
|
||||
}
|
||||
|
||||
let view = this._views.get(type);
|
||||
if (!view) {
|
||||
view = dm;
|
||||
}
|
||||
|
||||
const directives: any[] = [];
|
||||
if (isPresent(view.directives)) {
|
||||
flattenArray(view.directives, directives);
|
||||
}
|
||||
let animations = view.animations;
|
||||
let templateUrl = view.templateUrl;
|
||||
const directiveOverrides = this._directiveOverrides.get(type);
|
||||
|
||||
const inlineAnimations = this._animations.get(type);
|
||||
if (isPresent(inlineAnimations)) {
|
||||
animations = inlineAnimations;
|
||||
}
|
||||
|
||||
let inlineTemplate = this._inlineTemplates.get(type);
|
||||
if (isPresent(inlineTemplate)) {
|
||||
templateUrl = null;
|
||||
} else {
|
||||
inlineTemplate = view.template;
|
||||
}
|
||||
|
||||
if (isPresent(directiveOverrides) && isPresent(view.directives)) {
|
||||
directiveOverrides.forEach((to, from) => {
|
||||
var srcIndex = directives.indexOf(from);
|
||||
if (srcIndex == -1) {
|
||||
throw new BaseException(
|
||||
`Overriden directive ${stringify(from)} not found in the template of ${stringify(type)}`);
|
||||
}
|
||||
directives[srcIndex] = to;
|
||||
});
|
||||
}
|
||||
|
||||
return new ComponentMetadata({
|
||||
selector: dm.selector,
|
||||
inputs: dm.inputs,
|
||||
|
@ -60,7 +102,16 @@ export class MockDirectiveResolver extends DirectiveResolver {
|
|||
changeDetection: dm.changeDetection,
|
||||
providers: providers,
|
||||
viewProviders: viewProviders,
|
||||
entryComponents: dm.entryComponents
|
||||
entryComponents: dm.entryComponents,
|
||||
template: inlineTemplate,
|
||||
templateUrl: templateUrl,
|
||||
directives: directives.length > 0 ? directives : null,
|
||||
animations: animations,
|
||||
styles: view.styles,
|
||||
styleUrls: view.styleUrls,
|
||||
pipes: view.pipes,
|
||||
encapsulation: view.encapsulation,
|
||||
interpolation: view.interpolation
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -77,11 +128,58 @@ export class MockDirectiveResolver extends DirectiveResolver {
|
|||
|
||||
setProvidersOverride(type: Type, providers: any[]): void {
|
||||
this._providerOverrides.set(type, providers);
|
||||
this._compiler.clearCacheFor(type);
|
||||
this._clearCacheFor(type);
|
||||
}
|
||||
|
||||
setViewProvidersOverride(type: Type, viewProviders: any[]): void {
|
||||
this.viewProviderOverrides.set(type, viewProviders);
|
||||
this._compiler.clearCacheFor(type);
|
||||
this._clearCacheFor(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the {@link ViewMetadata} for a component.
|
||||
*/
|
||||
setView(component: Type, view: ViewMetadata): void {
|
||||
this._views.set(component, view);
|
||||
this._clearCacheFor(component);
|
||||
}
|
||||
/**
|
||||
* Overrides the inline template for a component - other configuration remains unchanged.
|
||||
*/
|
||||
setInlineTemplate(component: Type, template: string): void {
|
||||
this._inlineTemplates.set(component, template);
|
||||
this._clearCacheFor(component);
|
||||
}
|
||||
|
||||
setAnimations(component: Type, animations: AnimationEntryMetadata[]): void {
|
||||
this._animations.set(component, animations);
|
||||
this._clearCacheFor(component);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides a directive from the component {@link ViewMetadata}.
|
||||
*/
|
||||
overrideViewDirective(component: Type, from: Type, to: Type): void {
|
||||
var overrides = this._directiveOverrides.get(component);
|
||||
|
||||
if (!overrides) {
|
||||
overrides = new Map<Type, Type>();
|
||||
this._directiveOverrides.set(component, overrides);
|
||||
}
|
||||
|
||||
overrides.set(from, to);
|
||||
this._clearCacheFor(component);
|
||||
}
|
||||
}
|
||||
|
||||
function flattenArray(tree: any[], out: Array<Type|any[]>): void {
|
||||
if (!isPresent(tree)) return;
|
||||
for (var i = 0; i < tree.length; i++) {
|
||||
var item = resolveForwardRef(tree[i]);
|
||||
if (isArray(item)) {
|
||||
flattenArray(item, out);
|
||||
} else {
|
||||
out.push(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import {AnimationEntryMetadata, Compiler, ComponentFactory, Inject, Injectable, Injector, NgZone, ViewMetadata} from '@angular/core';
|
||||
import {ComponentFixture, ComponentFixtureNoNgZone, TestBed, TestComponentBuilder} from '@angular/core/testing';
|
||||
|
||||
import {DirectiveResolver, ViewResolver} from '../index';
|
||||
import {DirectiveResolver} from '../index';
|
||||
import {MapWrapper} from '../src/facade/collection';
|
||||
import {ConcreteType, IS_DART, Type, isPresent} from '../src/facade/lang';
|
||||
|
||||
|
@ -101,15 +101,14 @@ export class OverridingTestComponentBuilder extends TestComponentBuilder {
|
|||
|
||||
private _applyMetadataOverrides() {
|
||||
let mockDirectiveResolver = this._injector.get(DirectiveResolver);
|
||||
let mockViewResolver = this._injector.get(ViewResolver);
|
||||
this._viewOverrides.forEach((view, type) => { mockViewResolver.setView(type, view); });
|
||||
this._viewOverrides.forEach((view, type) => { mockDirectiveResolver.setView(type, view); });
|
||||
this._templateOverrides.forEach(
|
||||
(template, type) => mockViewResolver.setInlineTemplate(type, template));
|
||||
(template, type) => mockDirectiveResolver.setInlineTemplate(type, template));
|
||||
this._animationOverrides.forEach(
|
||||
(animationsEntry, type) => mockViewResolver.setAnimations(type, animationsEntry));
|
||||
(animationsEntry, type) => mockDirectiveResolver.setAnimations(type, animationsEntry));
|
||||
this._directiveOverrides.forEach((overrides, component) => {
|
||||
overrides.forEach(
|
||||
(to, from) => { mockViewResolver.overrideViewDirective(component, from, to); });
|
||||
(to, from) => { mockDirectiveResolver.overrideViewDirective(component, from, to); });
|
||||
});
|
||||
this._bindingsOverrides.forEach(
|
||||
(bindings, type) => mockDirectiveResolver.setProvidersOverride(type, bindings));
|
||||
|
|
|
@ -1,141 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AnimationEntryMetadata, BaseException, Compiler, Injectable, Injector, Type, ViewMetadata, resolveForwardRef} from '@angular/core';
|
||||
|
||||
import {ViewResolver} from '../index';
|
||||
import {Map} from '../src/facade/collection';
|
||||
import {isArray, isBlank, isPresent, stringify} from '../src/facade/lang';
|
||||
|
||||
@Injectable()
|
||||
export class MockViewResolver extends ViewResolver {
|
||||
/** @internal */
|
||||
_views = new Map<Type, ViewMetadata>();
|
||||
/** @internal */
|
||||
_inlineTemplates = new Map<Type, string>();
|
||||
/** @internal */
|
||||
_animations = new Map<Type, AnimationEntryMetadata[]>();
|
||||
/** @internal */
|
||||
_directiveOverrides = new Map<Type, Map<Type, Type>>();
|
||||
|
||||
constructor(private _injector: Injector) { super(); }
|
||||
|
||||
private get _compiler(): Compiler { return this._injector.get(Compiler); }
|
||||
|
||||
private _clearCacheFor(component: Type) { this._compiler.clearCacheFor(component); }
|
||||
|
||||
/**
|
||||
* Overrides the {@link ViewMetadata} for a component.
|
||||
*/
|
||||
setView(component: Type, view: ViewMetadata): void {
|
||||
this._views.set(component, view);
|
||||
this._clearCacheFor(component);
|
||||
}
|
||||
/**
|
||||
* Overrides the inline template for a component - other configuration remains unchanged.
|
||||
*/
|
||||
setInlineTemplate(component: Type, template: string): void {
|
||||
this._inlineTemplates.set(component, template);
|
||||
this._clearCacheFor(component);
|
||||
}
|
||||
|
||||
setAnimations(component: Type, animations: AnimationEntryMetadata[]): void {
|
||||
this._animations.set(component, animations);
|
||||
this._clearCacheFor(component);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides a directive from the component {@link ViewMetadata}.
|
||||
*/
|
||||
overrideViewDirective(component: Type, from: Type, to: Type): void {
|
||||
var overrides = this._directiveOverrides.get(component);
|
||||
|
||||
if (isBlank(overrides)) {
|
||||
overrides = new Map<Type, Type>();
|
||||
this._directiveOverrides.set(component, overrides);
|
||||
}
|
||||
|
||||
overrides.set(from, to);
|
||||
this._clearCacheFor(component);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ViewMetadata} for a component:
|
||||
* - Set the {@link ViewMetadata} to the overridden view when it exists or fallback to the default
|
||||
* `ViewResolver`,
|
||||
* see `setView`.
|
||||
* - Override the directives, see `overrideViewDirective`.
|
||||
* - Override the @View definition, see `setInlineTemplate`.
|
||||
*/
|
||||
resolve(component: Type, throwIfNotFound = true): ViewMetadata {
|
||||
var view = this._views.get(component);
|
||||
if (isBlank(view)) {
|
||||
view = super.resolve(component, throwIfNotFound);
|
||||
if (!view) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
var directives: any[] /** TODO #9100 */ = [];
|
||||
if (isPresent(view.directives)) {
|
||||
flattenArray(view.directives, directives);
|
||||
}
|
||||
var animations = view.animations;
|
||||
var templateUrl = view.templateUrl;
|
||||
var overrides = this._directiveOverrides.get(component);
|
||||
|
||||
var inlineAnimations = this._animations.get(component);
|
||||
if (isPresent(inlineAnimations)) {
|
||||
animations = inlineAnimations;
|
||||
}
|
||||
|
||||
var inlineTemplate = this._inlineTemplates.get(component);
|
||||
if (isPresent(inlineTemplate)) {
|
||||
templateUrl = null;
|
||||
} else {
|
||||
inlineTemplate = view.template;
|
||||
}
|
||||
|
||||
if (isPresent(overrides) && isPresent(view.directives)) {
|
||||
overrides.forEach((to, from) => {
|
||||
var srcIndex = directives.indexOf(from);
|
||||
if (srcIndex == -1) {
|
||||
throw new BaseException(
|
||||
`Overriden directive ${stringify(from)} not found in the template of ${stringify(component)}`);
|
||||
}
|
||||
directives[srcIndex] = to;
|
||||
});
|
||||
}
|
||||
|
||||
view = new ViewMetadata({
|
||||
template: inlineTemplate,
|
||||
templateUrl: templateUrl,
|
||||
directives: directives.length > 0 ? directives : null,
|
||||
animations: animations,
|
||||
styles: view.styles,
|
||||
styleUrls: view.styleUrls,
|
||||
pipes: view.pipes,
|
||||
encapsulation: view.encapsulation,
|
||||
interpolation: view.interpolation
|
||||
});
|
||||
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
||||
function flattenArray(tree: any[], out: Array<Type|any[]>): void {
|
||||
if (!isPresent(tree)) return;
|
||||
for (var i = 0; i < tree.length; i++) {
|
||||
var item = resolveForwardRef(tree[i]);
|
||||
if (isArray(item)) {
|
||||
flattenArray(item, out);
|
||||
} else {
|
||||
out.push(item);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,7 +17,7 @@ import {AnimationEntryMetadata} from './animation/metadata';
|
|||
import {AttributeMetadata, ContentChildMetadata, ContentChildrenMetadata, QueryMetadata, ViewChildMetadata, ViewChildrenMetadata, ViewQueryMetadata} from './metadata/di';
|
||||
import {ComponentMetadata, DirectiveMetadata, HostBindingMetadata, HostListenerMetadata, InputMetadata, OutputMetadata, PipeMetadata} from './metadata/directives';
|
||||
import {ModuleWithProviders, NgModuleMetadata, SchemaMetadata} from './metadata/ng_module';
|
||||
import {ViewEncapsulation, ViewMetadata} from './metadata/view';
|
||||
import {ViewEncapsulation} from './metadata/view';
|
||||
|
||||
export {ANALYZE_FOR_ENTRY_COMPONENTS, AttributeMetadata, ContentChildMetadata, ContentChildrenMetadata, QueryMetadata, ViewChildMetadata, ViewChildrenMetadata, ViewQueryMetadata} from './metadata/di';
|
||||
export {ComponentMetadata, DirectiveMetadata, HostBindingMetadata, HostListenerMetadata, InputMetadata, OutputMetadata, PipeMetadata} from './metadata/directives';
|
||||
|
@ -44,46 +44,7 @@ export interface DirectiveDecorator extends TypeDecorator {}
|
|||
*
|
||||
* @stable
|
||||
*/
|
||||
export interface ComponentDecorator extends TypeDecorator {
|
||||
/**
|
||||
* Chain {@link ViewMetadata} annotation.
|
||||
*/
|
||||
View(obj: {
|
||||
templateUrl?: string,
|
||||
template?: string,
|
||||
directives?: Array<Type|any[]>,
|
||||
pipes?: Array<Type|any[]>,
|
||||
renderer?: string,
|
||||
styles?: string[],
|
||||
styleUrls?: string[],
|
||||
animations?: AnimationEntryMetadata[],
|
||||
interpolation?: [string, string]
|
||||
}): ViewDecorator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for the {@link ViewMetadata} decorator function.
|
||||
*
|
||||
* See {@link ViewMetadataFactory}.
|
||||
*
|
||||
* @experimental
|
||||
*/
|
||||
export interface ViewDecorator extends TypeDecorator {
|
||||
/**
|
||||
* Chain {@link ViewMetadata} annotation.
|
||||
*/
|
||||
View(obj: {
|
||||
templateUrl?: string,
|
||||
template?: string,
|
||||
directives?: Array<Type|any[]>,
|
||||
pipes?: Array<Type|any[]>,
|
||||
renderer?: string,
|
||||
styles?: string[],
|
||||
styleUrls?: string[],
|
||||
animations?: AnimationEntryMetadata[],
|
||||
interpolation?: [string, string]
|
||||
}): ViewDecorator;
|
||||
}
|
||||
export interface ComponentDecorator extends TypeDecorator {}
|
||||
|
||||
/**
|
||||
* Interface for the {@link NgModuleMetadata} decorator function.
|
||||
|
@ -237,75 +198,6 @@ export interface ComponentMetadataFactory {
|
|||
}): ComponentMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ViewMetadata} factory for creating annotations, decorators or DSL.
|
||||
*
|
||||
* ### Example as TypeScript Decorator
|
||||
*
|
||||
* ```
|
||||
* import {Component, View} from '@angular/core';
|
||||
*
|
||||
* @Component({...})
|
||||
* class MyComponent {
|
||||
* constructor() {
|
||||
* ...
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* ### Example as ES5 DSL
|
||||
*
|
||||
* ```
|
||||
* var MyComponent = ng
|
||||
* .Component({...})
|
||||
* .View({...})
|
||||
* .Class({
|
||||
* constructor: function() {
|
||||
* ...
|
||||
* }
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* ### Example as ES5 annotation
|
||||
*
|
||||
* ```
|
||||
* var MyComponent = function() {
|
||||
* ...
|
||||
* };
|
||||
*
|
||||
* MyComponent.annotations = [
|
||||
* new ng.Component({...}),
|
||||
* new ng.View({...})
|
||||
* ]
|
||||
* ```
|
||||
*
|
||||
* @experimental You should most likely use ComponentMetadataFactory instead
|
||||
*/
|
||||
export interface ViewMetadataFactory {
|
||||
(obj: {
|
||||
templateUrl?: string,
|
||||
template?: string,
|
||||
directives?: Array<Type|any[]>,
|
||||
pipes?: Array<Type|any[]>,
|
||||
encapsulation?: ViewEncapsulation,
|
||||
styles?: string[],
|
||||
styleUrls?: string[],
|
||||
animations?: AnimationEntryMetadata[],
|
||||
interpolation?: [string, string]
|
||||
}): ViewDecorator;
|
||||
new (obj: {
|
||||
templateUrl?: string,
|
||||
template?: string,
|
||||
directives?: Array<Type|any[]>,
|
||||
pipes?: Array<Type|any[]>,
|
||||
encapsulation?: ViewEncapsulation,
|
||||
styles?: string[],
|
||||
styleUrls?: string[],
|
||||
animations?: AnimationEntryMetadata[],
|
||||
interpolation?: [string, string]
|
||||
}): ViewMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AttributeMetadata} factory for creating annotations, decorators or DSL.
|
||||
*
|
||||
|
@ -541,7 +433,7 @@ export interface NgModuleMetadataFactory {
|
|||
* @Annotation
|
||||
*/
|
||||
export var Component: ComponentMetadataFactory =
|
||||
<ComponentMetadataFactory>makeDecorator(ComponentMetadata, (fn: any) => fn.View = View);
|
||||
<ComponentMetadataFactory>makeDecorator(ComponentMetadata);
|
||||
|
||||
// TODO(alexeagle): remove the duplication of this doc. It is copied from DirectiveMetadata.
|
||||
/**
|
||||
|
@ -580,7 +472,7 @@ export var Component: ComponentMetadataFactory =
|
|||
* current `ElementInjector` resolves the constructor dependencies for each directive.
|
||||
*
|
||||
* Angular then resolves dependencies as follows, according to the order in which they appear in the
|
||||
* {@link ViewMetadata}:
|
||||
* {@link ComponentMetadata}:
|
||||
*
|
||||
* 1. Dependencies on the current element
|
||||
* 2. Dependencies on element injectors and their parents until it encounters a Shadow DOM boundary
|
||||
|
@ -829,7 +721,8 @@ export var Component: ComponentMetadataFactory =
|
|||
* location in the current view
|
||||
* where these actions are performed.
|
||||
*
|
||||
* Views are always created as children of the current {@link ViewMetadata}, and as siblings of the
|
||||
* Views are always created as children of the current {@link ComponentMetadata}, and as siblings of
|
||||
* the
|
||||
* `<template>` element. Thus a
|
||||
* directive in a child view cannot inject the directive that created it.
|
||||
*
|
||||
|
@ -928,41 +821,6 @@ export var Component: ComponentMetadataFactory =
|
|||
export var Directive: DirectiveMetadataFactory =
|
||||
<DirectiveMetadataFactory>makeDecorator(DirectiveMetadata);
|
||||
|
||||
// TODO(alexeagle): remove the duplication of this doc. It is copied from ViewMetadata.
|
||||
/**
|
||||
* Metadata properties available for configuring Views.
|
||||
*
|
||||
* Each Angular component requires a single `@Component` and at least one `@View` annotation. The
|
||||
* `@View` annotation specifies the HTML template to use, and lists the directives that are active
|
||||
* within the template.
|
||||
*
|
||||
* When a component is instantiated, the template is loaded into the component's shadow root, and
|
||||
* the expressions and statements in the template are evaluated against the component.
|
||||
*
|
||||
* For details on the `@Component` annotation, see {@link ComponentMetadata}.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* ```
|
||||
* @Component({
|
||||
* selector: 'greet',
|
||||
* template: 'Hello {{name}}!',
|
||||
* directives: [GreetUser, Bold]
|
||||
* })
|
||||
* class Greet {
|
||||
* name: string;
|
||||
*
|
||||
* constructor() {
|
||||
* this.name = 'World';
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
* @deprecated
|
||||
* @Annotation
|
||||
*/
|
||||
var View: ViewMetadataFactory =
|
||||
<ViewMetadataFactory>makeDecorator(ViewMetadata, (fn: any) => fn.View = View);
|
||||
|
||||
/**
|
||||
* Specifies that a constant attribute value should be injected.
|
||||
*
|
||||
|
|
|
@ -50,7 +50,7 @@ import {ViewEncapsulation} from './view';
|
|||
* current `ElementInjector` resolves the constructor dependencies for each directive.
|
||||
*
|
||||
* Angular then resolves dependencies as follows, according to the order in which they appear in the
|
||||
* {@link ViewMetadata}:
|
||||
* {@link ComponentMetadata}:
|
||||
*
|
||||
* 1. Dependencies on the current element
|
||||
* 2. Dependencies on element injectors and their parents until it encounters a Shadow DOM boundary
|
||||
|
@ -299,7 +299,8 @@ import {ViewEncapsulation} from './view';
|
|||
* location in the current view
|
||||
* where these actions are performed.
|
||||
*
|
||||
* Views are always created as children of the current {@link ViewMetadata}, and as siblings of the
|
||||
* Views are always created as children of the current {@link ComponentMetadata}, and as siblings of
|
||||
* the
|
||||
* `<template>` element. Thus a
|
||||
* directive in a child view cannot inject the directive that created it.
|
||||
*
|
||||
|
@ -787,8 +788,6 @@ export class DirectiveMetadata extends InjectableMetadata {
|
|||
*
|
||||
* All template expressions and statements are then evaluated against the component instance.
|
||||
*
|
||||
* For details on the `@View` annotation, see {@link ViewMetadata}.
|
||||
*
|
||||
* ## Lifecycle hooks
|
||||
*
|
||||
* When the component class implements some {@linkDocs guide/lifecycle-hooks} the
|
||||
|
@ -877,12 +876,32 @@ export class ComponentMetadata extends DirectiveMetadata {
|
|||
*/
|
||||
moduleId: string;
|
||||
|
||||
/**
|
||||
* Specifies a template URL for an Angular component.
|
||||
*
|
||||
* NOTE: Only one of `templateUrl` or `template` can be defined per View.
|
||||
*
|
||||
* <!-- TODO: what's the url relative to? -->
|
||||
*/
|
||||
templateUrl: string;
|
||||
|
||||
/**
|
||||
* Specifies an inline template for an Angular component.
|
||||
*
|
||||
* NOTE: Only one of `templateUrl` or `template` can be defined per View.
|
||||
*/
|
||||
template: string;
|
||||
|
||||
/**
|
||||
* Specifies stylesheet URLs for an Angular component.
|
||||
*
|
||||
* <!-- TODO: what's the url relative to? -->
|
||||
*/
|
||||
styleUrls: string[];
|
||||
|
||||
/**
|
||||
* Specifies an inline stylesheet for an Angular component.
|
||||
*/
|
||||
styles: string[];
|
||||
|
||||
/**
|
||||
|
@ -962,6 +981,12 @@ export class ComponentMetadata extends DirectiveMetadata {
|
|||
|
||||
pipes: Array<Type|any[]>;
|
||||
|
||||
/**
|
||||
* Specify how the template and the styles should be encapsulated.
|
||||
* The default is {@link ViewEncapsulation#Emulated `ViewEncapsulation.Emulated`} if the view
|
||||
* has styles,
|
||||
* otherwise {@link ViewEncapsulation#None `ViewEncapsulation.None`}.
|
||||
*/
|
||||
encapsulation: ViewEncapsulation;
|
||||
|
||||
interpolation: [string, string];
|
||||
|
|
|
@ -73,7 +73,7 @@ export var VIEW_ENCAPSULATION_VALUES =
|
|||
* ```
|
||||
* @ts2dart_const
|
||||
*
|
||||
* @experimental You should most likely be using ComponentMetadata instead.
|
||||
* @deprecated Use ComponentMetadata instead.
|
||||
*/
|
||||
export class ViewMetadata {
|
||||
/**
|
||||
|
|
|
@ -1525,7 +1525,8 @@ function declareTests({useJit}: {useJit: boolean}) {
|
|||
tcb.createAsync(ComponentWithoutView);
|
||||
expect(true).toBe(false);
|
||||
} catch (e) {
|
||||
expect(e.message).toContain(`must have either 'template' or 'templateUrl' set.`);
|
||||
expect(e.message).toContain(
|
||||
`No template specified for component ${stringify(ComponentWithoutView)}`);
|
||||
}
|
||||
}));
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
*/
|
||||
|
||||
import {LowerCasePipe, NgIf} from '@angular/common';
|
||||
import {CompilerConfig, NgModuleResolver, ViewResolver} from '@angular/compiler';
|
||||
import {MockNgModuleResolver, MockViewResolver} from '@angular/compiler/testing';
|
||||
import {CompilerConfig, NgModuleResolver} from '@angular/compiler';
|
||||
import {MockNgModuleResolver} from '@angular/compiler/testing';
|
||||
import {ANALYZE_FOR_ENTRY_COMPONENTS, CUSTOM_ELEMENTS_SCHEMA, Compiler, Component, ComponentFactoryResolver, ComponentRef, ComponentResolver, DebugElement, Directive, Host, HostBinding, Inject, Injectable, Injector, Input, ModuleWithProviders, NgModule, NgModuleMetadata, NgModuleRef, OpaqueToken, Optional, Pipe, Provider, ReflectiveInjector, SelfMetadata, SkipSelf, SkipSelfMetadata, ViewMetadata, forwardRef, getDebugNode, provide} from '@angular/core';
|
||||
import {Console} from '@angular/core/src/console';
|
||||
import {ComponentFixture, configureCompiler} from '@angular/core/testing';
|
||||
|
@ -125,11 +125,10 @@ function declareTests({useJit}: {useJit: boolean}) {
|
|||
configureCompiler({useJit: useJit, providers: [{provide: Console, useValue: console}]});
|
||||
});
|
||||
|
||||
beforeEach(
|
||||
inject([Compiler, Injector, ViewResolver], (_compiler: Compiler, _injector: Injector) => {
|
||||
compiler = _compiler;
|
||||
injector = _injector;
|
||||
}));
|
||||
beforeEach(inject([Compiler, Injector], (_compiler: Compiler, _injector: Injector) => {
|
||||
compiler = _compiler;
|
||||
injector = _injector;
|
||||
}));
|
||||
|
||||
function createModule<T>(
|
||||
moduleType: ConcreteType<T>, parentInjector: Injector = null): NgModuleRef<T> {
|
||||
|
|
|
@ -19,15 +19,14 @@ export function main() {
|
|||
});
|
||||
|
||||
it('should declare Component class', () => {
|
||||
var MyComponent =
|
||||
Component({}).View({}).View({}).Class({constructor: function() { this.works = true; }});
|
||||
var MyComponent = Component({}).Class({constructor: function() { this.works = true; }});
|
||||
expect(new MyComponent().works).toEqual(true);
|
||||
});
|
||||
|
||||
it('should create type in ES5', () => {
|
||||
function MyComponent(){};
|
||||
var as: any /** TODO #9100 */;
|
||||
(<any>MyComponent).annotations = as = Component({}).View({});
|
||||
(<any>MyComponent).annotations = as = Component({});
|
||||
expect(reflector.annotations(MyComponent)).toEqual(as.annotations);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {CompilerConfig, DirectiveResolver, NgModuleResolver, ViewResolver, analyzeAppProvidersForDeprecatedConfiguration} from '@angular/compiler';
|
||||
import {CompilerConfig, DirectiveResolver, NgModuleResolver, analyzeAppProvidersForDeprecatedConfiguration} from '@angular/compiler';
|
||||
import {OverridingTestComponentBuilder, platformCoreDynamicTesting} from '@angular/compiler/testing';
|
||||
import {Compiler, CompilerFactory, CompilerOptions, NgModule, PlatformRef, Provider, ReflectiveInjector, Type, createPlatform, createPlatformFactory} from '@angular/core';
|
||||
import {TestComponentBuilder, TestComponentRenderer, initTestEnvironment} from '@angular/core/testing';
|
||||
|
|
|
@ -13,7 +13,7 @@ import {
|
|||
ViewMetadata
|
||||
} from '@angular/core';
|
||||
|
||||
import {CompilerConfig, ViewResolver} from '@angular/compiler';
|
||||
import {CompilerConfig, DirectiveResolver} from '@angular/compiler';
|
||||
|
||||
import {getIntParameter, bindAction} from '@angular/testing/src/benchmark_util';
|
||||
|
||||
|
@ -21,8 +21,8 @@ function _createBindings(): any[] {
|
|||
var multiplyTemplatesBy = getIntParameter('elements');
|
||||
return [
|
||||
{
|
||||
provide: ViewResolver,
|
||||
useFactory: () => new MultiplyViewResolver(
|
||||
provide: DirectiveResolver,
|
||||
useFactory: () => new MultiplyDirectiveResolver(
|
||||
multiplyTemplatesBy,
|
||||
[BenchmarkComponentNoBindings, BenchmarkComponentWithBindings]),
|
||||
deps: []
|
||||
|
@ -59,7 +59,7 @@ function measureWrapper(func, desc) {
|
|||
}
|
||||
|
||||
|
||||
class MultiplyViewResolver extends ViewResolver {
|
||||
class MultiplyDirectiveResolver extends DirectiveResolver {
|
||||
_multiplyBy: number;
|
||||
_cache = new Map<Type, ViewMetadata>();
|
||||
|
||||
|
|
Loading…
Reference in New Issue