
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
166 lines
5.2 KiB
TypeScript
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);
|
|
}
|
|
}
|
|
}
|