test(ivy): add injection canonical specs (#22595)

PR Close #22595
This commit is contained in:
Misko Hevery
2018-03-04 20:21:23 -08:00
committed by Kara Erickson
parent f13f4db9dc
commit 2fee5cc095
14 changed files with 403 additions and 128 deletions

View File

@ -14,7 +14,7 @@ export {
detectChanges as ɵdetectChanges,
renderComponent as ɵrenderComponent,
ComponentType as ɵComponentType,
inject as ɵinject,
directiveInject as ɵdirectiveInject,
injectTemplateRef as ɵinjectTemplateRef,
injectViewContainerRef as ɵinjectViewContainerRef,
injectChangeDetectorRef as ɵinjectChangeDetectorRef,

View File

@ -47,7 +47,6 @@ export function defineComponent<T>(componentDefinition: ComponentDefArgs<T>): Co
inputs: invertObject(componentDefinition.inputs),
inputsPropertyName: componentDefinition.inputsPropertyName || null,
outputs: invertObject(componentDefinition.outputs),
methods: invertObject(componentDefinition.methods),
rendererType: resolveRendererType2(componentDefinition.rendererType) || null,
exportAs: componentDefinition.exportAs,
onInit: type.prototype.ngOnInit || null,

View File

@ -174,7 +174,7 @@ export function diPublic(def: DirectiveDef<any>): void {
}
/**
* Searches for an instance of the given directive type up the injector tree and returns
* Searches for an instance of the given type up the injector tree and returns
* that instance if found.
*
* If not found, it will propagate up to the next parent injector until the token
@ -187,15 +187,18 @@ export function diPublic(def: DirectiveDef<any>): void {
*
* static ngDirectiveDef = defineDirective({
* type: SomeDirective,
* factory: () => new SomeDirective(inject(DirectiveA))
* factory: () => new SomeDirective(directiveInject(DirectiveA))
* });
* }
*
* NOTE: use `directiveInject` with `@Directive`, `@Component`, and `@Pipe`. For
* all other injection use `inject` which does not walk the DOM render tree.
*
* @param token The directive type to search for
* @param flags Injection flags (e.g. CheckParent)
* @returns The instance found
*/
export function inject<T>(token: Type<T>, flags?: InjectFlags, defaultValue?: T): T {
export function directiveInject<T>(token: Type<T>, flags?: InjectFlags, defaultValue?: T): T {
return getOrCreateInjectable<T>(getOrCreateNodeInjector(), token, flags, defaultValue);
}

View File

@ -11,7 +11,7 @@ import {NgOnChangesFeature, PublicFeature, defineComponent, defineDirective, def
import {InjectFlags} from './di';
import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveDefFlags, DirectiveType} from './interfaces/definition';
export {InjectFlags, QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_READ_FROM_NODE, QUERY_READ_TEMPLATE_REF, inject, injectAttribute, injectChangeDetectorRef, injectElementRef, injectTemplateRef, injectViewContainerRef} from './di';
export {InjectFlags, QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_READ_FROM_NODE, QUERY_READ_TEMPLATE_REF, directiveInject, injectAttribute, injectChangeDetectorRef, injectElementRef, injectTemplateRef, injectViewContainerRef} from './di';
export {CssSelector} from './interfaces/projection';

View File

@ -8,10 +8,13 @@
import {ChangeDetectionStrategy} from '../../change_detection/constants';
import {PipeTransform} from '../../change_detection/pipe_transform';
import {Provider} from '../../core';
import {RendererType2} from '../../render/api';
import {Type} from '../../type';
import {resolveRendererType2} from '../../view/util';
/**
* Definition of what a template rendering function should look like.
*/
@ -19,16 +22,37 @@ export type ComponentTemplate<T> = {
(ctx: T, creationMode: boolean): void; ngPrivateData?: never;
};
/**
* A subclass of `Type` which has a static `ngComponentDef`:`ComponentDef` field making it
* consumable for rendering.
*/
export interface ComponentType<T> extends Type<T> { ngComponentDef: ComponentDef<T>; }
/**
* A subclass of `Type` which has a static `ngDirectiveDef`:`DirectiveDef` field making it
* consumable for rendering.
*/
export interface DirectiveType<T> extends Type<T> { ngDirectiveDef: DirectiveDef<T>; }
export const enum DirectiveDefFlags {ContentQuery = 0b10}
/**
* A subclass of `Type` which has a static `ngPipeDef`:`PipeDef` field making it
* consumable for rendering.
*/
export interface PipeType<T> extends Type<T> { ngPipeDef: PipeDef<T>; }
/**
* `DirectiveDef` is a compiled version of the Directive used by the renderer instructions.
* Runtime link information for Directives.
*
* This is internal data structure used by the render to link
* directives into templates.
*
* NOTE: Always use `defineDirective` function to create this object,
* never create the object directly since the shape of this object
* can change between versions.
*
* See: {@link defineDirective}
*/
export interface DirectiveDef<T> {
/** Token representing the directive. Used by DI. */
@ -59,11 +83,6 @@ export interface DirectiveDef<T> {
*/
readonly outputs: {[P in keyof T]: P};
/**
* A dictionary mapping the methods' minified names to their original unminified ones.
*/
readonly methods: {[P in keyof T]: P};
/**
* Name under which the directive is exported (for use with local references in template)
*/
@ -104,6 +123,18 @@ export interface DirectiveDef<T> {
onDestroy: (() => void)|null;
}
/**
* Runtime link information for Components.
*
* This is internal data structure used by the render to link
* components into templates.
*
* NOTE: Always use `defineComponent` function to create this object,
* never create the object directly since the shape of this object
* can change between versions.
*
* See: {@link defineComponent}
*/
export interface ComponentDef<T> extends DirectiveDef<T> {
/**
* The tag name which should be used by the component.
@ -128,10 +159,31 @@ export interface ComponentDef<T> extends DirectiveDef<T> {
/** Whether or not this component's ChangeDetectionStrategy is OnPush */
readonly onPush: boolean;
/**
* Defines the set of injectable providers that are visible to a Directive and its content DOM
* children.
*/
readonly providers?: Provider[];
/**
* Defines the set of injectable providers that are visible to a Directive and its view DOM
* children only.
*/
readonly viewProviders?: Provider[];
}
/**
* Runtime link information for Pipes.
*
* This is internal data structure used by the renderer to link
* pipes into templates.
*
* NOTE: Always use `definePipe` function to create this object,
* never create the object directly since the shape of this object
* can change between versions.
*
* See: {@link definePipe}
*/
export interface PipeDef<T> {
/**
@ -154,30 +206,142 @@ export interface PipeDef<T> {
onDestroy: (() => void)|null;
}
/**
* Arguments for `defineDirective`
*/
export interface DirectiveDefArgs<T> {
/**
* Directive type, needed to configure the injector.
*/
type: Type<T>;
/**
* Factory method used to create an instance of directive.
*/
factory: () => T | [T];
/**
* Static attributes to set on host element.
*
* Even indices: attribute name
* Odd indices: attribute value
*/
attributes?: string[];
/**
* A map of input names.
*
* The format is in: `{[actualPropertyName: string]:string}`.
*
* Which the minifier may translate to: `{[minifiedPropertyName: string]:string}`.
*
* This allows the render to re-construct the minified and non-minified names
* of properties.
*/
inputs?: {[P in keyof T]?: string};
/**
* TODO: Remove per https://github.com/angular/angular/issues/22591
*/
inputsPropertyName?: {[P in keyof T]?: string};
/**
* A map of output names.
*
* The format is in: `{[actualPropertyName: string]:string}`.
*
* Which the minifier may translate to: `{[minifiedPropertyName: string]:string}`.
*
* This allows the render to re-construct the minified and non-minified names
* of properties.
*/
outputs?: {[P in keyof T]?: string};
methods?: {[P in keyof T]?: string};
/**
* A list of optional features to apply.
*
* See: {@link NgOnChangesFeature}, {@link PublicFeature}
*/
features?: DirectiveDefFeature[];
/**
* Function executed by the parent template to allow child directive to apply host bindings.
*/
hostBindings?: (directiveIndex: number, elementIndex: number) => void;
/**
* Defines the name that can be used in the template to assign this directive to a variable.
*
* See: {@link Directive.exportAs}
*/
exportAs?: string;
}
/**
* Arguments for `defineComponent`.
*/
export interface ComponentDefArgs<T> extends DirectiveDefArgs<T> {
/**
* HTML tag name to use in place where this component should be instantiated.
*/
tag: string;
/**
* Template function use for rendering DOM.
*
* This function has following structure.
*
* ```
* function Template<T>(ctx:T, creationMode: boolean) {
* if (creationMode) {
* // Contains creation mode instructions.
* }
* // Contains binding update instructions
* }
* ```
*
* Common instructions are:
* Creation mode instructions:
* - `elementStart`, `elementEnd`
* - `text`
* - `container`
* - `listener`
*
* Binding update instructions:
* - `bind`
* - `elementAttribute`
* - `elementProperty`
* - `elementClass`
* - `elementStyle`
*
*/
template: ComponentTemplate<T>;
/**
* A list of optional features to apply.
*
* See: {@link NgOnChancesFeature}, {@link PublicFeature}
*/
features?: ComponentDefFeature[];
rendererType?: RendererType2;
changeDetection?: ChangeDetectionStrategy;
/**
* Defines the set of injectable objects that are visible to a Directive and its light DOM
* children.
*/
providers?: Provider[];
/**
* Defines the set of injectable objects that are visible to its view DOM children.
*/
viewProviders?: Provider[];
}
export type DirectiveDefFeature = <T>(directiveDef: DirectiveDef<T>) => void;
export type ComponentDefFeature = <T>(directiveDef: DirectiveDef<T>) => void;
export type ComponentDefFeature = <T>(componentDef: ComponentDef<T>) => void;
// Note: This hack is necessary so we don't erroneously get a circular dependency
// failure based on types.