angular/modules/@angular/compiler/testing/directive_resolver_mock.ts
Tobias Bosch 1b15170c89 refactor(core): simplify decorators
Every decorator now is made of the following:
- a function that can be used
as a decorator or as a constructor. This function
also can be used for `instanceof` checks.
- a type for this function (callable and newable)
- a type that describes the shape of the data
  that the user needs to pass to the decorator
  as well as the instance of the metadata

The docs for decorators live at the followig places
so that IDEs can discover them correctly:
- General description of the decorator is placed on the
  `...Decorator` interface on the callable function
  definition
- Property descriptions are placed on the interface
  that describes the metadata produces by the decorator
2016-09-12 22:47:54 -07:00

166 lines
5.2 KiB
TypeScript

/**
* @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 {DirectiveResolver} from '@angular/compiler';
import {AnimationEntryMetadata, Compiler, ComponentMetadata, DirectiveMetadata, Injectable, Injector, Provider, Type, resolveForwardRef} from '@angular/core';
import {Map} from './facade/collection';
import {isArray, isPresent} from './facade/lang';
import {ViewMetadata} from './private_import_core';
/**
* An implementation of {@link DirectiveResolver} that allows overriding
* various properties of directives.
*/
@Injectable()
export class MockDirectiveResolver extends DirectiveResolver {
private _directives = new Map<Type<any>, DirectiveMetadata>();
private _providerOverrides = new Map<Type<any>, any[]>();
private _viewProviderOverrides = new Map<Type<any>, any[]>();
private _views = new Map<Type<any>, ViewMetadata>();
private _inlineTemplates = new Map<Type<any>, string>();
private _animations = new Map<Type<any>, AnimationEntryMetadata[]>();
constructor(private _injector: Injector) { super(); }
private get _compiler(): Compiler { return this._injector.get(Compiler); }
private _clearCacheFor(component: Type<any>) { this._compiler.clearCacheFor(component); }
resolve(type: Type<any>, throwIfNotFound = true): DirectiveMetadata {
let metadata = this._directives.get(type);
if (!metadata) {
metadata = super.resolve(type, throwIfNotFound);
}
if (!metadata) {
return null;
}
const providerOverrides = this._providerOverrides.get(type);
const viewProviderOverrides = this._viewProviderOverrides.get(type);
let providers = metadata.providers;
if (isPresent(providerOverrides)) {
const originalViewProviders: Provider[] =
isPresent(metadata.providers) ? metadata.providers : [];
providers = originalViewProviders.concat(providerOverrides);
}
if (metadata instanceof ComponentMetadata) {
let viewProviders = metadata.viewProviders;
if (isPresent(viewProviderOverrides)) {
const originalViewProviders: Provider[] =
isPresent(metadata.viewProviders) ? metadata.viewProviders : [];
viewProviders = originalViewProviders.concat(viewProviderOverrides);
}
let view = this._views.get(type);
if (!view) {
view = <any>metadata;
}
let animations = view.animations;
let templateUrl = view.templateUrl;
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;
}
return new ComponentMetadata({
selector: metadata.selector,
inputs: metadata.inputs,
outputs: metadata.outputs,
host: metadata.host,
exportAs: metadata.exportAs,
moduleId: metadata.moduleId,
queries: metadata.queries,
changeDetection: metadata.changeDetection,
providers: providers,
viewProviders: viewProviders,
entryComponents: metadata.entryComponents,
template: inlineTemplate,
templateUrl: templateUrl,
animations: animations,
styles: view.styles,
styleUrls: view.styleUrls,
encapsulation: view.encapsulation,
interpolation: view.interpolation
});
}
return new DirectiveMetadata({
selector: metadata.selector,
inputs: metadata.inputs,
outputs: metadata.outputs,
host: metadata.host,
providers: providers,
exportAs: metadata.exportAs,
queries: metadata.queries
});
}
/**
* Overrides the {@link DirectiveMetadata} for a directive.
*/
setDirective(type: Type<any>, metadata: DirectiveMetadata): void {
this._directives.set(type, metadata);
this._clearCacheFor(type);
}
setProvidersOverride(type: Type<any>, providers: Provider[]): void {
this._providerOverrides.set(type, providers);
this._clearCacheFor(type);
}
setViewProvidersOverride(type: Type<any>, viewProviders: Provider[]): void {
this._viewProviderOverrides.set(type, viewProviders);
this._clearCacheFor(type);
}
/**
* Overrides the {@link ViewMetadata} for a component.
*/
setView(component: Type<any>, 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<any>, template: string): void {
this._inlineTemplates.set(component, template);
this._clearCacheFor(component);
}
setAnimations(component: Type<any>, animations: AnimationEntryMetadata[]): void {
this._animations.set(component, animations);
this._clearCacheFor(component);
}
}
function flattenArray(tree: any[], out: Array<Type<any>|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);
}
}
}