refactor(ivy): remove type from DirectiveDef (#21374)

This change makes the code cleaner for the user. It does mean
a little bit more work for us since we have to patch the `type` back
into the `DirectiveDef`. However since the patching happens only once
on startup it should not be significant.

PR Close #21374
This commit is contained in:
Miško Hevery
2018-01-09 16:43:12 -08:00
committed by Alex Eagle
parent 16232f000f
commit 5eaaac35a8
23 changed files with 108 additions and 212 deletions

View File

@ -13,13 +13,14 @@ import {ComponentRef as viewEngine_ComponentRef} from '../linker/component_facto
import {EmbeddedViewRef as viewEngine_EmbeddedViewRef} from '../linker/view_ref';
import {assertNotNull} from './assert';
import {NG_HOST_SYMBOL, createError, createLView, directive, enterView, hostElement, leaveView, locateHostElement, renderComponentOrTemplate, directiveCreate} from './instructions';
import {ComponentDef, ComponentType} from './interfaces/definition';
import {NG_HOST_SYMBOL, createError, createLView, directive, directiveCreate, enterView, hostElement, leaveView, locateHostElement, renderComponentOrTemplate} from './instructions';
import {ComponentDef, ComponentType, TypedComponentDef} from './interfaces/definition';
import {LElementNode} from './interfaces/node';
import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
import {notImplemented, stringify} from './util';
/** Options that control how the component should be bootstrapped. */
export interface CreateComponentOptions {
/** Which renderer factory to use. */
@ -165,7 +166,8 @@ export const NULL_INJECTOR: Injector = {
export function renderComponent<T>(
componentType: ComponentType<T>, opts: CreateComponentOptions = {}): T {
const rendererFactory = opts.rendererFactory || domRendererFactory3;
const componentDef = componentType.ngComponentDef;
const componentDef = componentType.ngComponentDef as TypedComponentDef<T>;
if (componentDef.type != componentType) componentDef.type = componentType;
let component: T;
const hostNode = locateHostElement(rendererFactory, opts.host || componentDef.tag);
const oldView = enterView(

View File

@ -32,7 +32,6 @@ import {ComponentDef, ComponentDefArgs, DirectiveDef, DirectiveDefArgs} from './
*/
export function defineComponent<T>(componentDefinition: ComponentDefArgs<T>): ComponentDef<T> {
const def = <ComponentDef<any>>{
type: componentDefinition.type,
diPublic: null,
n: componentDefinition.factory,
tag: (componentDefinition as ComponentDefArgs<T>).tag || null !,

View File

@ -17,7 +17,7 @@ import {ViewContainerRef as viewEngine_ViewContainerRef} from '../linker/view_co
import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, ViewRef as viewEngine_ViewRef} from '../linker/view_ref';
import {Type} from '../type';
import {ComponentTemplate, DirectiveDef} from './interfaces/definition';
import {ComponentTemplate, DirectiveDef, TypedDirectiveDef} from './interfaces/definition';
import {LInjector} from './interfaces/injector';
import {LContainerNode, LElementNode, LNodeFlags} from './interfaces/node';
import {assertNodeType} from './node_assert';
@ -147,7 +147,7 @@ function createInjectionError(text: string, token: any) {
* @param di The node injector in which a directive will be added
* @param def The definition of the directive to be made public
*/
export function diPublicInInjector(di: LInjector, def: DirectiveDef<any>): void {
export function diPublicInInjector(di: LInjector, def: TypedDirectiveDef<any>): void {
bloomAdd(di, def.type);
}
@ -211,7 +211,7 @@ export function getOrCreateInjectable<T>(di: LInjector, token: Type<T>, flags?:
for (let i = start, ii = start + size; i < ii; i++) {
// Get the definition for the directive at this index and, if it is injectable (diPublic),
// and matches the given token, return the directive instance.
const directiveDef = ngStaticData[i] as DirectiveDef<any>;
const directiveDef = ngStaticData[i] as TypedDirectiveDef<any>;
if (directiveDef.diPublic && directiveDef.type == token) {
return node.view.data[i];
}

View File

@ -24,7 +24,7 @@ import {LContainerNode, LElementNode, LNode, LNodeFlags, LProjectionNode, LTextN
import {assertNodeType} from './node_assert';
import {appendChild, insertChild, insertView, processProjectedNode, removeView} from './node_manipulation';
import {isNodeMatchingSelector} from './node_selector_matcher';
import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveType} from './interfaces/definition';
import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveType, TypedDirectiveDef, TypedComponentDef} from './interfaces/definition';
import {InjectFlags, diPublicInInjector, getOrCreateNodeInjectorForNode, getOrCreateElementRef, getOrCreateTemplateRef, getOrCreateContainerRef, getOrCreateInjectable} from './di';
import {QueryList, LQuery_} from './query';
import {RComment, RElement, RText, Renderer3, RendererFactory3, ProceduralRenderer3, ObjectOrientedRenderer3, RendererStyleFlags3} from './interfaces/renderer';
@ -343,7 +343,7 @@ export function getOrCreateNodeInjector(): LInjector {
*
* @param def The definition of the directive to be made public
*/
export function diPublic(def: DirectiveDef<any>): void {
export function diPublic(def: TypedDirectiveDef<any>): void {
diPublicInInjector(getOrCreateNodeInjector(), def);
}
@ -475,6 +475,8 @@ export function elementStart(
if (hostComponentDef) {
// TODO(mhevery): This assumes that the directives come in correct order, which
// is not guaranteed. Must be refactored to take it into account.
(hostComponentDef as TypedComponentDef<any>).type =
nameOrComponentType as ComponentType<any>;
directiveCreate(++index, hostComponentDef.n(), hostComponentDef, queryName);
}
hack_declareDirectives(index, directiveTypes, localRefs);
@ -500,7 +502,9 @@ function hack_declareDirectives(
// template
// code for slight startup(first run) performance. (No impact on subsequent runs)
// TODO(misko): refactor this to store the `DirectiveDef` in `TView.data`.
const directiveDef = directiveTypes[i].ngDirectiveDef;
const directiveType = directiveTypes[i];
const directiveDef = directiveType.ngDirectiveDef;
(directiveDef as TypedDirectiveDef<any>).type = directiveType;
directiveCreate(
++index, directiveDef.n(), directiveDef, hack_findQueryName(directiveDef, localRefs));
}
@ -945,8 +949,7 @@ export function directiveCreate<T>(
if (index >= ngStaticData.length) {
ngStaticData[index] = directiveDef !;
if (queryName) {
ngDevMode &&
assertNotNull(previousOrParentNode.tNode, 'previousOrParentNode.staticData');
ngDevMode && assertNotNull(previousOrParentNode.tNode, 'previousOrParentNode.staticData');
const nodeStaticData = previousOrParentNode !.tNode !;
(nodeStaticData.localNames || (nodeStaticData.localNames = [])).push(queryName, index);
}

View File

@ -28,11 +28,6 @@ export const enum DirectiveDefFlags {ContentQuery = 0b10}
* `DirectiveDef` is a compiled version of the Directive used by the renderer instructions.
*/
export interface DirectiveDef<T> {
/**
* Token representing the directive. Used by DI.
*/
type: Type<T>;
/** Function that makes a directive public to the DI system. */
diPublic: ((def: DirectiveDef<any>) => void)|null;
@ -41,26 +36,26 @@ export interface DirectiveDef<T> {
*
* The key is minified property name whereas the value is the original unminified name.
*/
inputs: {[P in keyof T]: P};
readonly inputs: {[P in keyof T]: P};
/**
* List of outputs which are part of the components public API.
*
* The key is minified property name whereas the value is the original unminified name.=
*/
outputs: {[P in keyof T]: P};
readonly outputs: {[P in keyof T]: P};
/**
* List of methods which are part of the components public API.
*
* The key is minified property name whereas the value is the original unminified name.
*/
methods: {[P in keyof T]: P};
readonly methods: {[P in keyof T]: P};
/**
* Name under which the directive is exported (for use with local references in template)
*/
exportAs: string|null;
readonly exportAs: string|null;
/**
* factory function used to create a new directive instance.
@ -111,25 +106,34 @@ export interface ComponentDef<T> extends DirectiveDef<T> {
*
* NOTE: only used with component directives.
*/
tag: string;
readonly tag: string;
/**
* The View template of the component.
*
* NOTE: only used with component directives.
*/
template: ComponentTemplate<T>;
readonly template: ComponentTemplate<T>;
/**
* Renderer type data of the component.
*
* NOTE: only used with component directives.
*/
rendererType: RendererType2|null;
readonly rendererType: RendererType2|null;
}
/**
* Private: do not export
*/
export interface TypedDirectiveDef<T> extends DirectiveDef<T> { type: DirectiveType<T>; }
/**
* Private: do not export
*/
export interface TypedComponentDef<T> extends ComponentDef<T> { type: ComponentType<T>; }
export interface DirectiveDefArgs<T> {
type: Type<T>;
factory: () => T;
refresh?: (directiveIndex: number, elementIndex: number) => void;
inputs?: {[P in keyof T]?: string};

View File

@ -17,13 +17,14 @@ import {Type} from '../type';
import {assertNotNull} from './assert';
import {getOrCreateContainerRef, getOrCreateElementRef, getOrCreateNodeInjectorForNode, getOrCreateTemplateRef} from './di';
import {DirectiveDef} from './interfaces/definition';
import {DirectiveDef, TypedDirectiveDef} from './interfaces/definition';
import {LInjector} from './interfaces/injector';
import {LContainerNode, LElementNode, LNode, LNodeFlags, LViewNode, TNode} from './interfaces/node';
import {LQuery, QueryReadType} from './interfaces/query';
import {assertNodeOfPossibleTypes} from './node_assert';
/**
* A predicate which determines if a given element/directive should be included in the query
*/
@ -142,7 +143,7 @@ function geIdxOfMatchingDirective(node: LNode, type: Type<any>): number|null {
for (let i = flags >> LNodeFlags.INDX_SHIFT,
ii = i + ((flags & LNodeFlags.SIZE_MASK) >> LNodeFlags.SIZE_SHIFT);
i < ii; i++) {
const def = ngStaticData[i] as DirectiveDef<any>;
const def = ngStaticData[i] as TypedDirectiveDef<any>;
if (def.diPublic && def.type === type) {
return i;
}