diff --git a/modules/benchmarks/src/tree/ng2_next/README.md b/modules/benchmarks/src/tree/ng2_next/README.md index 5b2960b7c1..06f8c442a7 100644 --- a/modules/benchmarks/src/tree/ng2_next/README.md +++ b/modules/benchmarks/src/tree/ng2_next/README.md @@ -6,7 +6,7 @@ more functionality from codegen into runtime to reduce generated code size. As we introduce more runtime code, we need to be very careful to not regress in performance, compared to the pure codegen solution. -## Initial resuls: size of Deep Tree Benchmark +## Initial results: size of Deep Tree Benchmark File size for Tree benchmark template, view class of the component + the 2 embedded view classes (without imports nor host view factory): diff --git a/modules/benchmarks/src/tree/ng2_next/tree.ts b/modules/benchmarks/src/tree/ng2_next/tree.ts index 573b8fec24..3ed87ed055 100644 --- a/modules/benchmarks/src/tree/ng2_next/tree.ts +++ b/modules/benchmarks/src/tree/ng2_next/tree.ts @@ -26,8 +26,8 @@ let viewFlags = ViewFlags.None; function TreeComponent_Host(): ViewDefinition { return viewDef(viewFlags, [ - elementDef(NodeFlags.None, null, null, 1, 'tree', null, null, null, null, TreeComponent_0), - directiveDef(NodeFlags.Component, null, 0, TreeComponent, []), + elementDef(0, NodeFlags.None, null, null, 1, 'tree', null, null, null, null, TreeComponent_0), + directiveDef(1, NodeFlags.Component, null, 0, TreeComponent, []), ]); } @@ -35,8 +35,9 @@ function TreeComponent_1() { return viewDef( viewFlags, [ - elementDef(NodeFlags.None, null, null, 1, 'tree', null, null, null, null, TreeComponent_0), - directiveDef(NodeFlags.Component, null, 0, TreeComponent, [], {data: [0, 'data']}), + elementDef( + 0, NodeFlags.None, null, null, 1, 'tree', null, null, null, null, TreeComponent_0), + directiveDef(1, NodeFlags.Component, null, 0, TreeComponent, [], {data: [0, 'data']}), ], (check, view) => { const cmp = view.component; @@ -48,8 +49,9 @@ function TreeComponent_2() { return viewDef( viewFlags, [ - elementDef(NodeFlags.None, null, null, 1, 'tree', null, null, null, null, TreeComponent_0), - directiveDef(NodeFlags.Component, null, 0, TreeComponent, [], {data: [0, 'data']}), + elementDef( + 0, NodeFlags.None, null, null, 1, 'tree', null, null, null, null, TreeComponent_0), + directiveDef(1, NodeFlags.Component, null, 0, TreeComponent, [], {data: [0, 'data']}), ], (check, view) => { const cmp = view.component; @@ -62,15 +64,15 @@ function TreeComponent_0(): ViewDefinition { viewFlags, [ elementDef( - NodeFlags.None, null, null, 1, 'span', null, + 0, NodeFlags.None, null, null, 1, 'span', null, [[BindingFlags.TypeElementStyle, 'backgroundColor', null]]), - textDef(null, [' ', ' ']), + textDef(1, null, [' ', ' ']), anchorDef(NodeFlags.EmbeddedViews, null, null, 1, null, TreeComponent_1), directiveDef( - NodeFlags.None, null, 0, NgIf, [ViewContainerRef, TemplateRef], {ngIf: [0, 'ngIf']}), + 3, NodeFlags.None, null, 0, NgIf, [ViewContainerRef, TemplateRef], {ngIf: [0, 'ngIf']}), anchorDef(NodeFlags.EmbeddedViews, null, null, 1, null, TreeComponent_2), directiveDef( - NodeFlags.None, null, 0, NgIf, [ViewContainerRef, TemplateRef], {ngIf: [0, 'ngIf']}), + 5, NodeFlags.None, null, 0, NgIf, [ViewContainerRef, TemplateRef], {ngIf: [0, 'ngIf']}), ], (check, view) => { const cmp = view.component; diff --git a/packages/compiler/src/view_compiler/view_compiler.ts b/packages/compiler/src/view_compiler/view_compiler.ts index e53606959b..2c0b130f89 100644 --- a/packages/compiler/src/view_compiler/view_compiler.ts +++ b/packages/compiler/src/view_compiler/view_compiler.ts @@ -230,12 +230,15 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { } visitText(ast: TextAst, context: any): any { - // textDef(ngContentIndex: number, constants: string[]): NodeDef; + // Static text nodes have no check function + const checkIndex = -1; this.nodes.push(() => ({ sourceSpan: ast.sourceSpan, nodeFlags: NodeFlags.TypeText, nodeDef: o.importExpr(Identifiers.textDef).callFn([ - o.literal(ast.ngContentIndex), o.literalArr([o.literal(ast.value)]) + o.literal(checkIndex), + o.literal(ast.ngContentIndex), + o.literalArr([o.literal(ast.value)]), ]) })); } @@ -252,12 +255,17 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { (expr, bindingIndex) => this._preprocessUpdateExpression( {nodeIndex, bindingIndex, sourceSpan: ast.sourceSpan, context: COMP_VAR, value: expr})); - // textDef(ngContentIndex: number, constants: string[]): NodeDef; + // Check index is the same as the node index during compilation + // They might only differ at runtime + const checkIndex = nodeIndex; + this.nodes[nodeIndex] = () => ({ sourceSpan: ast.sourceSpan, nodeFlags: NodeFlags.TypeText, nodeDef: o.importExpr(Identifiers.textDef).callFn([ - o.literal(ast.ngContentIndex), o.literalArr(inter.strings.map(s => o.literal(s))) + o.literal(checkIndex), + o.literal(ast.ngContentIndex), + o.literalArr(inter.strings.map(s => o.literal(s))), ]), updateRenderer: updateRendererExpressions }); @@ -344,18 +352,15 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { compRendererType = this.outputCtx.importExpr(compAst.directive.rendererType); } - // elementDef( - // flags: NodeFlags, matchedQueriesDsl: [string | number, QueryValueType][], - // ngContentIndex: number, childCount: number, namespaceAndName: string, - // fixedAttrs: [string, string][] = [], - // bindings?: [BindingFlags, string, string | SecurityContext][], - // outputs?: ([OutputType.ElementOutput | OutputType.DirectiveHostOutput, string, string])[], - // handleEvent?: ElementHandleEventFn, - // componentView?: () => ViewDefinition, componentRendererType?: RendererType2): NodeDef; + // Check index is the same as the node index during compilation + // They might only differ at runtime + const checkIndex = nodeIndex; + this.nodes[nodeIndex] = () => ({ sourceSpan: ast.sourceSpan, nodeFlags: NodeFlags.TypeElement | flags, nodeDef: o.importExpr(Identifiers.elementDef).callFn([ + o.literal(checkIndex), o.literal(flags), queryMatchesExpr, o.literal(ast.ngContentIndex), @@ -561,20 +566,22 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { eventAst: hostEventAst, dirAst, })); + // Check index is the same as the node index during compilation + // They might only differ at runtime + const checkIndex = nodeIndex; - // directiveDef( - // flags: NodeFlags, matchedQueries: [string, QueryValueType][], childCount: number, ctor: - // any, - // deps: ([DepFlags, any] | any)[], props?: {[name: string]: [number, string]}, - // outputs?: {[name: string]: string}, component?: () => ViewDefinition): NodeDef; this.nodes[nodeIndex] = () => ({ sourceSpan: dirAst.sourceSpan, nodeFlags: NodeFlags.TypeDirective | flags, nodeDef: o.importExpr(Identifiers.directiveDef).callFn([ - o.literal(flags), queryMatchExprs.length ? o.literalArr(queryMatchExprs) : o.NULL_EXPR, - o.literal(childCount), providerExpr, depsExpr, + o.literal(checkIndex), + o.literal(flags), + queryMatchExprs.length ? o.literalArr(queryMatchExprs) : o.NULL_EXPR, + o.literal(childCount), + providerExpr, + depsExpr, inputDefs.length ? new o.LiteralMapExpr(inputDefs) : o.NULL_EXPR, - outputDefs.length ? new o.LiteralMapExpr(outputDefs) : o.NULL_EXPR + outputDefs.length ? new o.LiteralMapExpr(outputDefs) : o.NULL_EXPR, ]), updateDirectives: updateDirectiveExpressions, directive: dirAst.directive.type, @@ -687,15 +694,18 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { return () => valueExpr; } - const nodeIndex = this.nodes.length; - // pureArrayDef(argCount: number): NodeDef; + const checkIndex = this.nodes.length; + this.nodes.push(() => ({ sourceSpan, nodeFlags: NodeFlags.TypePureArray, - nodeDef: o.importExpr(Identifiers.pureArrayDef).callFn([o.literal(argCount)]) + nodeDef: o.importExpr(Identifiers.pureArrayDef).callFn([ + o.literal(checkIndex), + o.literal(argCount), + ]) })); - return (args: o.Expression[]) => callCheckStmt(nodeIndex, args); + return (args: o.Expression[]) => callCheckStmt(checkIndex, args); } private _createLiteralMapConverter( @@ -705,28 +715,32 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { return () => valueExpr; } - // function pureObjectDef(propToIndex: {[p: string]: number}): NodeDef const map = o.literalMap(keys.map((e, i) => ({...e, value: o.literal(i)}))); - const nodeIndex = this.nodes.length; + const checkIndex = this.nodes.length; this.nodes.push(() => ({ sourceSpan, nodeFlags: NodeFlags.TypePureObject, - nodeDef: o.importExpr(Identifiers.pureObjectDef).callFn([map]) + nodeDef: o.importExpr(Identifiers.pureObjectDef).callFn([ + o.literal(checkIndex), + map, + ]) })); - return (args: o.Expression[]) => callCheckStmt(nodeIndex, args); + return (args: o.Expression[]) => callCheckStmt(checkIndex, args); } private _createPipeConverter(expression: UpdateExpression, name: string, argCount: number): BuiltinConverter { const pipe = this.usedPipes.find((pipeSummary) => pipeSummary.name === name) !; if (pipe.pure) { - const nodeIndex = this.nodes.length; - // function purePipeDef(argCount: number): NodeDef; + const checkIndex = this.nodes.length; this.nodes.push(() => ({ sourceSpan: expression.sourceSpan, nodeFlags: NodeFlags.TypePurePipe, - nodeDef: o.importExpr(Identifiers.purePipeDef).callFn([o.literal(argCount)]) + nodeDef: o.importExpr(Identifiers.purePipeDef).callFn([ + o.literal(checkIndex), + o.literal(argCount), + ]) })); // find underlying pipe in the component view @@ -742,7 +756,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { return (args: o.Expression[]) => callUnwrapValue( expression.nodeIndex, expression.bindingIndex, - callCheckStmt(nodeIndex, [pipeValueExpr].concat(args))); + callCheckStmt(checkIndex, [pipeValueExpr].concat(args))); } else { const nodeIndex = this._createPipe(expression.sourceSpan, pipe); const nodeValueExpr = diff --git a/packages/core/src/view/element.ts b/packages/core/src/view/element.ts index 69b4b9339b..31c47cb90b 100644 --- a/packages/core/src/view/element.ts +++ b/packages/core/src/view/element.ts @@ -13,8 +13,8 @@ import {BindingDef, BindingFlags, ElementData, ElementHandleEventFn, NodeDef, No import {NOOP, calcBindingFlags, checkAndUpdateBinding, dispatchEvent, elementEventFullName, getParentRenderElement, resolveDefinition, resolveRendererType2, splitMatchedQueriesDsl, splitNamespace} from './util'; export function anchorDef( - flags: NodeFlags, matchedQueriesDsl: [string | number, QueryValueType][], - ngContentIndex: number, childCount: number, handleEvent?: ElementHandleEventFn, + flags: NodeFlags, matchedQueriesDsl: null | [string | number, QueryValueType][], + ngContentIndex: null | number, childCount: number, handleEvent?: null | ElementHandleEventFn, templateFactory?: ViewDefinitionFactory): NodeDef { flags |= NodeFlags.TypeElement; const {matchedQueries, references, matchedQueryIds} = splitMatchedQueriesDsl(matchedQueriesDsl); @@ -22,13 +22,14 @@ export function anchorDef( return { // will bet set by the view definition - index: -1, + nodeIndex: -1, parent: null, renderParent: null, bindingIndex: -1, outputIndex: -1, // regular values flags, + checkIndex: -1, childFlags: 0, directChildFlags: 0, childMatchedQueries: 0, matchedQueries, matchedQueryIds, references, ngContentIndex, childCount, @@ -54,11 +55,12 @@ export function anchorDef( } export function elementDef( - flags: NodeFlags, matchedQueriesDsl: [string | number, QueryValueType][], - ngContentIndex: number, childCount: number, namespaceAndName: string | null, - fixedAttrs: [string, string][] = [], - bindings?: [BindingFlags, string, string | SecurityContext][], outputs?: ([string, string])[], - handleEvent?: ElementHandleEventFn, componentView?: ViewDefinitionFactory, + checkIndex: number, flags: NodeFlags, + matchedQueriesDsl: null | [string | number, QueryValueType][], ngContentIndex: null | number, + childCount: number, namespaceAndName: string | null, fixedAttrs: null | [string, string][] = [], + bindings?: null | [BindingFlags, string, string | SecurityContext | null][], + outputs?: null | ([string, string])[], handleEvent?: null | ElementHandleEventFn, + componentView?: null | ViewDefinitionFactory, componentRendererType?: RendererType2 | null): NodeDef { if (!handleEvent) { handleEvent = NOOP; @@ -111,12 +113,13 @@ export function elementDef( flags |= NodeFlags.TypeElement; return { // will bet set by the view definition - index: -1, + nodeIndex: -1, parent: null, renderParent: null, bindingIndex: -1, outputIndex: -1, // regular values + checkIndex, flags, childFlags: 0, directChildFlags: 0, @@ -175,7 +178,7 @@ export function listenToElementOutputs(view: ViewData, compView: ViewData, def: for (let i = 0; i < def.outputs.length; i++) { const output = def.outputs[i]; const handleEventClosure = renderEventHandlerClosure( - view, def.index, elementEventFullName(output.target, output.eventName)); + view, def.nodeIndex, elementEventFullName(output.target, output.eventName)); let listenTarget: 'window'|'document'|'body'|'component'|null = output.target; let listenerView = view; if (output.target === 'component') { @@ -224,7 +227,7 @@ function checkAndUpdateElementValue(view: ViewData, def: NodeDef, bindingIdx: nu return false; } const binding = def.bindings[bindingIdx]; - const elData = asElementData(view, def.index); + const elData = asElementData(view, def.nodeIndex); const renderNode = elData.renderElement; const name = binding.name !; switch (binding.flags & BindingFlags.Types) { diff --git a/packages/core/src/view/ng_content.ts b/packages/core/src/view/ng_content.ts index dfe251ab55..fd7ce7e9fc 100644 --- a/packages/core/src/view/ng_content.ts +++ b/packages/core/src/view/ng_content.ts @@ -9,15 +9,16 @@ import {NodeDef, NodeFlags, ViewData} from './types'; import {RenderNodeAction, getParentRenderElement, visitProjectedRenderNodes} from './util'; -export function ngContentDef(ngContentIndex: number, index: number): NodeDef { +export function ngContentDef(ngContentIndex: null | number, index: number): NodeDef { return { // will bet set by the view definition - index: -1, + nodeIndex: -1, parent: null, renderParent: null, bindingIndex: -1, outputIndex: -1, // regular values + checkIndex: -1, flags: NodeFlags.TypeNgContent, childFlags: 0, directChildFlags: 0, diff --git a/packages/core/src/view/ng_module.ts b/packages/core/src/view/ng_module.ts index 25a5c3e715..e8d9f485d2 100644 --- a/packages/core/src/view/ng_module.ts +++ b/packages/core/src/view/ng_module.ts @@ -7,10 +7,10 @@ */ import {resolveForwardRef} from '../di/forward_ref'; -import {Injector, THROW_IF_NOT_FOUND} from '../di/injector'; +import {Injector} from '../di/injector'; import {NgModuleRef} from '../linker/ng_module_factory'; -import {DepDef, DepFlags, NgModuleData, NgModuleDefinition, NgModuleDefinitionFactory, NgModuleProviderDef, NodeFlags} from './types'; +import {DepDef, DepFlags, NgModuleData, NgModuleDefinition, NgModuleProviderDef, NodeFlags} from './types'; import {splitDepsDsl, tokenKey} from './util'; const NOT_CREATED = new Object(); @@ -89,80 +89,60 @@ export function resolveNgModuleDep( function _createProviderInstance(ngModule: NgModuleData, providerDef: NgModuleProviderDef): any { - let injectable: any; switch (providerDef.flags & NodeFlags.Types) { case NodeFlags.TypeClassProvider: - injectable = _createClass(ngModule, providerDef.value, providerDef.deps); - break; + return _createClass(ngModule, providerDef.value, providerDef.deps); case NodeFlags.TypeFactoryProvider: - injectable = _callFactory(ngModule, providerDef.value, providerDef.deps); - break; + return _callFactory(ngModule, providerDef.value, providerDef.deps); case NodeFlags.TypeUseExistingProvider: - injectable = resolveNgModuleDep(ngModule, providerDef.deps[0]); - break; + return resolveNgModuleDep(ngModule, providerDef.deps[0]); case NodeFlags.TypeValueProvider: - injectable = providerDef.value; - break; + return providerDef.value; } - return injectable; } function _createClass(ngModule: NgModuleData, ctor: any, deps: DepDef[]): any { const len = deps.length; - let injectable: any; switch (len) { case 0: - injectable = new ctor(); - break; + return new ctor(); case 1: - injectable = new ctor(resolveNgModuleDep(ngModule, deps[0])); - break; + return new ctor(resolveNgModuleDep(ngModule, deps[0])); case 2: - injectable = - new ctor(resolveNgModuleDep(ngModule, deps[0]), resolveNgModuleDep(ngModule, deps[1])); - break; + return new ctor(resolveNgModuleDep(ngModule, deps[0]), resolveNgModuleDep(ngModule, deps[1])); case 3: - injectable = new ctor( + return new ctor( resolveNgModuleDep(ngModule, deps[0]), resolveNgModuleDep(ngModule, deps[1]), resolveNgModuleDep(ngModule, deps[2])); - break; default: const depValues = new Array(len); for (let i = 0; i < len; i++) { depValues[i] = resolveNgModuleDep(ngModule, deps[i]); } - injectable = new ctor(...depValues); + return new ctor(...depValues); } - return injectable; } function _callFactory(ngModule: NgModuleData, factory: any, deps: DepDef[]): any { const len = deps.length; - let injectable: any; switch (len) { case 0: - injectable = factory(); - break; + return factory(); case 1: - injectable = factory(resolveNgModuleDep(ngModule, deps[0])); - break; + return factory(resolveNgModuleDep(ngModule, deps[0])); case 2: - injectable = - factory(resolveNgModuleDep(ngModule, deps[0]), resolveNgModuleDep(ngModule, deps[1])); - break; + return factory(resolveNgModuleDep(ngModule, deps[0]), resolveNgModuleDep(ngModule, deps[1])); case 3: - injectable = factory( + return factory( resolveNgModuleDep(ngModule, deps[0]), resolveNgModuleDep(ngModule, deps[1]), resolveNgModuleDep(ngModule, deps[2])); - break; default: const depValues = Array(len); for (let i = 0; i < len; i++) { depValues[i] = resolveNgModuleDep(ngModule, deps[i]); } - injectable = factory(...depValues); + return factory(...depValues); } - return injectable; } export function callNgModuleLifecycle(ngModule: NgModuleData, lifecycles: NodeFlags) { diff --git a/packages/core/src/view/provider.ts b/packages/core/src/view/provider.ts index 93cfd2c611..a4a810d7ed 100644 --- a/packages/core/src/view/provider.ts +++ b/packages/core/src/view/provider.ts @@ -28,9 +28,10 @@ const InjectorRefTokenKey = tokenKey(Injector); const NOT_CREATED = new Object(); export function directiveDef( - flags: NodeFlags, matchedQueries: [string | number, QueryValueType][], childCount: number, - ctor: any, deps: ([DepFlags, any] | any)[], props?: {[name: string]: [number, string]}, - outputs?: {[name: string]: string}): NodeDef { + checkIndex: number, flags: NodeFlags, + matchedQueries: null | [string | number, QueryValueType][], childCount: number, ctor: any, + deps: ([DepFlags, any] | any)[], props?: null | {[name: string]: [number, string]}, + outputs?: null | {[name: string]: string}): NodeDef { const bindings: BindingDef[] = []; if (props) { for (let prop in props) { @@ -52,24 +53,26 @@ export function directiveDef( } } flags |= NodeFlags.TypeDirective; - return _def(flags, matchedQueries, childCount, ctor, ctor, deps, bindings, outputDefs); + return _def( + checkIndex, flags, matchedQueries, childCount, ctor, ctor, deps, bindings, outputDefs); } export function pipeDef(flags: NodeFlags, ctor: any, deps: ([DepFlags, any] | any)[]): NodeDef { flags |= NodeFlags.TypePipe; - return _def(flags, null, 0, ctor, ctor, deps); + return _def(-1, flags, null, 0, ctor, ctor, deps); } export function providerDef( - flags: NodeFlags, matchedQueries: [string | number, QueryValueType][], token: any, value: any, - deps: ([DepFlags, any] | any)[]): NodeDef { - return _def(flags, matchedQueries, 0, token, value, deps); + flags: NodeFlags, matchedQueries: null | [string | number, QueryValueType][], token: any, + value: any, deps: ([DepFlags, any] | any)[]): NodeDef { + return _def(-1, flags, matchedQueries, 0, token, value, deps); } export function _def( - flags: NodeFlags, matchedQueriesDsl: [string | number, QueryValueType][] | null, - childCount: number, token: any, value: any, deps: ([DepFlags, any] | any)[], - bindings?: BindingDef[], outputs?: OutputDef[]): NodeDef { + checkIndex: number, flags: NodeFlags, + matchedQueriesDsl: [string | number, QueryValueType][] | null, childCount: number, token: any, + value: any, deps: ([DepFlags, any] | any)[], bindings?: BindingDef[], + outputs?: OutputDef[]): NodeDef { const {matchedQueries, references, matchedQueryIds} = splitMatchedQueriesDsl(matchedQueriesDsl); if (!outputs) { outputs = []; @@ -86,12 +89,13 @@ export function _def( return { // will bet set by the view definition - index: -1, + nodeIndex: -1, parent: null, renderParent: null, bindingIndex: -1, outputIndex: -1, // regular values + checkIndex, flags, childFlags: 0, directChildFlags: 0, @@ -134,7 +138,7 @@ export function createDirectiveInstance(view: ViewData, def: NodeDef): any { for (let i = 0; i < def.outputs.length; i++) { const output = def.outputs[i]; const subscription = instance[output.propName !].subscribe( - eventHandlerClosure(view, def.parent !.index, output.eventName)); + eventHandlerClosure(view, def.parent !.nodeIndex, output.eventName)); view.disposables ![def.outputIndex + i] = subscription.unsubscribe.bind(subscription); } } @@ -148,7 +152,7 @@ function eventHandlerClosure(view: ViewData, index: number, eventName: string) { export function checkAndUpdateDirectiveInline( view: ViewData, def: NodeDef, v0: any, v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any, v8: any, v9: any): boolean { - const providerData = asProviderData(view, def.index); + const providerData = asProviderData(view, def.nodeIndex); const directive = providerData.instance; let changed = false; let changes: SimpleChanges = undefined !; @@ -207,7 +211,7 @@ export function checkAndUpdateDirectiveInline( export function checkAndUpdateDirectiveDynamic( view: ViewData, def: NodeDef, values: any[]): boolean { - const providerData = asProviderData(view, def.index); + const providerData = asProviderData(view, def.nodeIndex); const directive = providerData.instance; let changed = false; let changes: SimpleChanges = undefined !; @@ -233,89 +237,71 @@ function _createProviderInstance(view: ViewData, def: NodeDef): any { // private services can see other private services const allowPrivateServices = (def.flags & NodeFlags.PrivateProvider) > 0; const providerDef = def.provider; - let injectable: any; switch (def.flags & NodeFlags.Types) { case NodeFlags.TypeClassProvider: - injectable = createClass( + return createClass( view, def.parent !, allowPrivateServices, providerDef !.value, providerDef !.deps); - break; case NodeFlags.TypeFactoryProvider: - injectable = callFactory( + return callFactory( view, def.parent !, allowPrivateServices, providerDef !.value, providerDef !.deps); - break; case NodeFlags.TypeUseExistingProvider: - injectable = resolveDep(view, def.parent !, allowPrivateServices, providerDef !.deps[0]); - break; + return resolveDep(view, def.parent !, allowPrivateServices, providerDef !.deps[0]); case NodeFlags.TypeValueProvider: - injectable = providerDef !.value; - break; + return providerDef !.value; } - return injectable; } function createClass( view: ViewData, elDef: NodeDef, allowPrivateServices: boolean, ctor: any, deps: DepDef[]): any { const len = deps.length; - let injectable: any; switch (len) { case 0: - injectable = new ctor(); - break; + return new ctor(); case 1: - injectable = new ctor(resolveDep(view, elDef, allowPrivateServices, deps[0])); - break; + return new ctor(resolveDep(view, elDef, allowPrivateServices, deps[0])); case 2: - injectable = new ctor( + return new ctor( resolveDep(view, elDef, allowPrivateServices, deps[0]), resolveDep(view, elDef, allowPrivateServices, deps[1])); - break; case 3: - injectable = new ctor( + return new ctor( resolveDep(view, elDef, allowPrivateServices, deps[0]), resolveDep(view, elDef, allowPrivateServices, deps[1]), resolveDep(view, elDef, allowPrivateServices, deps[2])); - break; default: const depValues = new Array(len); for (let i = 0; i < len; i++) { depValues[i] = resolveDep(view, elDef, allowPrivateServices, deps[i]); } - injectable = new ctor(...depValues); + return new ctor(...depValues); } - return injectable; } function callFactory( view: ViewData, elDef: NodeDef, allowPrivateServices: boolean, factory: any, deps: DepDef[]): any { const len = deps.length; - let injectable: any; switch (len) { case 0: - injectable = factory(); - break; + return factory(); case 1: - injectable = factory(resolveDep(view, elDef, allowPrivateServices, deps[0])); - break; + return factory(resolveDep(view, elDef, allowPrivateServices, deps[0])); case 2: - injectable = factory( + return factory( resolveDep(view, elDef, allowPrivateServices, deps[0]), resolveDep(view, elDef, allowPrivateServices, deps[1])); - break; case 3: - injectable = factory( + return factory( resolveDep(view, elDef, allowPrivateServices, deps[0]), resolveDep(view, elDef, allowPrivateServices, deps[1]), resolveDep(view, elDef, allowPrivateServices, deps[2])); - break; default: const depValues = Array(len); for (let i = 0; i < len; i++) { depValues[i] = resolveDep(view, elDef, allowPrivateServices, deps[i]); } - injectable = factory(...depValues); + return factory(...depValues); } - return injectable; } // This default value is when checking the hierarchy for a token. @@ -372,12 +358,12 @@ export function resolveDep( return compView.renderer; } case ElementRefTokenKey: - return new ElementRef(asElementData(view, elDef.index).renderElement); + return new ElementRef(asElementData(view, elDef.nodeIndex).renderElement); case ViewContainerRefTokenKey: - return asElementData(view, elDef.index).viewContainer; + return asElementData(view, elDef.nodeIndex).viewContainer; case TemplateRefTokenKey: { if (elDef.element !.template) { - return asElementData(view, elDef.index).template; + return asElementData(view, elDef.nodeIndex).template; } break; } @@ -392,7 +378,7 @@ export function resolveDep( (allowPrivateServices ? elDef.element !.allProviders : elDef.element !.publicProviders) ![tokenKey]; if (providerDef) { - const providerData = asProviderData(view, providerDef.index); + const providerData = asProviderData(view, providerDef.nodeIndex); if (providerData.instance === NOT_CREATED) { providerData.instance = _createProviderInstance(view, providerDef); } @@ -423,7 +409,7 @@ export function resolveDep( function findCompView(view: ViewData, elDef: NodeDef, allowPrivateServices: boolean) { let compView: ViewData; if (allowPrivateServices) { - compView = asElementData(view, elDef.index).componentView; + compView = asElementData(view, elDef.nodeIndex).componentView; } else { compView = view; while (compView.parent && !isComponentView(compView)) { @@ -437,7 +423,7 @@ function updateProp( view: ViewData, providerData: ProviderData, def: NodeDef, bindingIdx: number, value: any, changes: SimpleChanges): SimpleChanges { if (def.flags & NodeFlags.Component) { - const compView = asElementData(view, def.parent !.index).componentView; + const compView = asElementData(view, def.parent !.nodeIndex).componentView; if (compView.def.flags & ViewFlags.OnPush) { compView.state |= ViewState.ChecksEnabled; } @@ -479,7 +465,7 @@ export function callLifecycleHooksChildrenFirst(view: ViewData, lifecycles: Node i += nodeDef.childCount; } while (parent && (parent.flags & NodeFlags.TypeElement) && - i === parent.index + parent.childCount) { + i === parent.nodeIndex + parent.childCount) { // last child of an element if (parent.directChildFlags & lifecycles) { callElementProvidersLifecycles(view, parent, lifecycles); @@ -490,7 +476,7 @@ export function callLifecycleHooksChildrenFirst(view: ViewData, lifecycles: Node } function callElementProvidersLifecycles(view: ViewData, elDef: NodeDef, lifecycles: NodeFlags) { - for (let i = elDef.index + 1; i <= elDef.index + elDef.childCount; i++) { + for (let i = elDef.nodeIndex + 1; i <= elDef.nodeIndex + elDef.childCount; i++) { const nodeDef = view.def.nodes[i]; if (nodeDef.flags & lifecycles) { callProviderLifecycles(view, i, nodeDef.flags & lifecycles); diff --git a/packages/core/src/view/pure_expression.ts b/packages/core/src/view/pure_expression.ts index d8ab3c87f3..8eb27f05b1 100644 --- a/packages/core/src/view/pure_expression.ts +++ b/packages/core/src/view/pure_expression.ts @@ -9,16 +9,16 @@ import {BindingDef, BindingFlags, NodeDef, NodeFlags, PureExpressionData, ViewData, asPureExpressionData} from './types'; import {calcBindingFlags, checkAndUpdateBinding} from './util'; -export function purePipeDef(argCount: number): NodeDef { +export function purePipeDef(checkIndex: number, argCount: number): NodeDef { // argCount + 1 to include the pipe as first arg - return _pureExpressionDef(NodeFlags.TypePurePipe, new Array(argCount + 1)); + return _pureExpressionDef(NodeFlags.TypePurePipe, checkIndex, new Array(argCount + 1)); } -export function pureArrayDef(argCount: number): NodeDef { - return _pureExpressionDef(NodeFlags.TypePureArray, new Array(argCount)); +export function pureArrayDef(checkIndex: number, argCount: number): NodeDef { + return _pureExpressionDef(NodeFlags.TypePureArray, checkIndex, new Array(argCount)); } -export function pureObjectDef(propToIndex: {[p: string]: number}): NodeDef { +export function pureObjectDef(checkIndex: number, propToIndex: {[p: string]: number}): NodeDef { const keys = Object.keys(propToIndex); const nbKeys = keys.length; const propertyNames = new Array(nbKeys); @@ -28,10 +28,11 @@ export function pureObjectDef(propToIndex: {[p: string]: number}): NodeDef { propertyNames[index] = key; } - return _pureExpressionDef(NodeFlags.TypePureObject, propertyNames); + return _pureExpressionDef(NodeFlags.TypePureObject, checkIndex, propertyNames); } -function _pureExpressionDef(flags: NodeFlags, propertyNames: string[]): NodeDef { +function _pureExpressionDef( + flags: NodeFlags, checkIndex: number, propertyNames: string[]): NodeDef { const bindings: BindingDef[] = new Array(propertyNames.length); for (let i = 0; i < propertyNames.length; i++) { const prop = propertyNames[i]; @@ -46,12 +47,13 @@ function _pureExpressionDef(flags: NodeFlags, propertyNames: string[]): NodeDef } return { // will bet set by the view definition - index: -1, + nodeIndex: -1, parent: null, renderParent: null, bindingIndex: -1, outputIndex: -1, // regular values + checkIndex, flags, childFlags: 0, directChildFlags: 0, @@ -93,7 +95,7 @@ export function checkAndUpdatePureExpressionInline( if (bindLen > 9 && checkAndUpdateBinding(view, def, 9, v9)) changed = true; if (changed) { - const data = asPureExpressionData(view, def.index); + const data = asPureExpressionData(view, def.nodeIndex); let value: any; switch (def.flags & NodeFlags.Types) { case NodeFlags.TypePureArray: @@ -175,7 +177,7 @@ export function checkAndUpdatePureExpressionDynamic( } } if (changed) { - const data = asPureExpressionData(view, def.index); + const data = asPureExpressionData(view, def.nodeIndex); let value: any; switch (def.flags & NodeFlags.Types) { case NodeFlags.TypePureArray: diff --git a/packages/core/src/view/query.ts b/packages/core/src/view/query.ts index b211b1f002..9e734b4be3 100644 --- a/packages/core/src/view/query.ts +++ b/packages/core/src/view/query.ts @@ -22,13 +22,14 @@ export function queryDef( return { // will bet set by the view definition - index: -1, + nodeIndex: -1, parent: null, renderParent: null, bindingIndex: -1, outputIndex: -1, // regular values - flags, + // TODO(vicb): check + checkIndex: -1, flags, childFlags: 0, directChildFlags: 0, childMatchedQueries: 0, @@ -58,7 +59,7 @@ export function dirtyParentQueries(view: ViewData) { let tplDef = view.parentNodeDef !; view = view.parent; // content queries - const end = tplDef.index + tplDef.childCount; + const end = tplDef.nodeIndex + tplDef.childCount; for (let i = 0; i <= end; i++) { const nodeDef = view.def.nodes[i]; if ((nodeDef.flags & NodeFlags.TypeContentQuery) && @@ -66,7 +67,7 @@ export function dirtyParentQueries(view: ViewData) { (nodeDef.query !.filterId & queryIds) === nodeDef.query !.filterId) { asQueryList(view, i).setDirty(); } - if ((nodeDef.flags & NodeFlags.TypeElement && i + nodeDef.childCount < tplDef.index) || + if ((nodeDef.flags & NodeFlags.TypeElement && i + nodeDef.childCount < tplDef.nodeIndex) || !(nodeDef.childFlags & NodeFlags.TypeContentQuery) || !(nodeDef.childFlags & NodeFlags.DynamicQuery)) { // skip elements that don't contain the template element or no query. @@ -89,7 +90,7 @@ export function dirtyParentQueries(view: ViewData) { } export function checkAndUpdateQuery(view: ViewData, nodeDef: NodeDef) { - const queryList = asQueryList(view, nodeDef.index); + const queryList = asQueryList(view, nodeDef.nodeIndex); if (!queryList.dirty) { return; } @@ -98,8 +99,9 @@ export function checkAndUpdateQuery(view: ViewData, nodeDef: NodeDef) { if (nodeDef.flags & NodeFlags.TypeContentQuery) { const elementDef = nodeDef.parent !.parent !; newValues = calcQueryValues( - view, elementDef.index, elementDef.index + elementDef.childCount, nodeDef.query !, []); - directiveInstance = asProviderData(view, nodeDef.parent !.index).instance; + view, elementDef.nodeIndex, elementDef.nodeIndex + elementDef.childCount, nodeDef.query !, + []); + directiveInstance = asProviderData(view, nodeDef.parent !.nodeIndex).instance; } else if (nodeDef.flags & NodeFlags.TypeViewQuery) { newValues = calcQueryValues(view, 0, view.def.nodes.length - 1, nodeDef.query !, []); directiveInstance = view.component; @@ -175,24 +177,17 @@ export function getQueryValue( view: ViewData, nodeDef: NodeDef, queryValueType: QueryValueType): any { if (queryValueType != null) { // a match - let value: any; switch (queryValueType) { case QueryValueType.RenderElement: - value = asElementData(view, nodeDef.index).renderElement; - break; + return asElementData(view, nodeDef.nodeIndex).renderElement; case QueryValueType.ElementRef: - value = new ElementRef(asElementData(view, nodeDef.index).renderElement); - break; + return new ElementRef(asElementData(view, nodeDef.nodeIndex).renderElement); case QueryValueType.TemplateRef: - value = asElementData(view, nodeDef.index).template; - break; + return asElementData(view, nodeDef.nodeIndex).template; case QueryValueType.ViewContainerRef: - value = asElementData(view, nodeDef.index).viewContainer; - break; + return asElementData(view, nodeDef.nodeIndex).viewContainer; case QueryValueType.Provider: - value = asProviderData(view, nodeDef.index).instance; - break; + return asProviderData(view, nodeDef.nodeIndex).instance; } - return value; } } diff --git a/packages/core/src/view/refs.ts b/packages/core/src/view/refs.ts index 27de9521a6..e72f3c8588 100644 --- a/packages/core/src/view/refs.ts +++ b/packages/core/src/view/refs.ts @@ -88,7 +88,7 @@ class ComponentFactory_ extends ComponentFactory { throw new Error('ngModule should be provided'); } const viewDef = resolveDefinition(this.viewDefFactory); - const componentNodeIndex = viewDef.nodes[0].element !.componentProvider !.index; + const componentNodeIndex = viewDef.nodes[0].element !.componentProvider !.nodeIndex; const view = Services.createRootView( injector, projectableNodes || [], rootSelectorOrNode, viewDef, ngModule, EMPTY_CONTEXT); const component = asProviderData(view, componentNodeIndex).instance; @@ -113,7 +113,7 @@ class ComponentRef_ extends ComponentRef { this.instance = _component; } get location(): ElementRef { - return new ElementRef(asElementData(this._view, this._elDef.index).renderElement); + return new ElementRef(asElementData(this._view, this._elDef.nodeIndex).renderElement); } get injector(): Injector { return new Injector_(this._view, this._elDef); } get componentType(): Type { return this._component.constructor; } @@ -318,7 +318,7 @@ class TemplateRef_ extends TemplateRef implements TemplateData { } get elementRef(): ElementRef { - return new ElementRef(asElementData(this._parentView, this._def.index).renderElement); + return new ElementRef(asElementData(this._parentView, this._def.nodeIndex).renderElement); } } @@ -340,12 +340,12 @@ class Injector_ implements Injector { export function nodeValue(view: ViewData, index: number): any { const def = view.def.nodes[index]; if (def.flags & NodeFlags.TypeElement) { - const elData = asElementData(view, def.index); + const elData = asElementData(view, def.nodeIndex); return def.element !.template ? elData.template : elData.renderElement; } else if (def.flags & NodeFlags.TypeText) { - return asTextData(view, def.index).renderText; + return asTextData(view, def.nodeIndex).renderText; } else if (def.flags & (NodeFlags.CatProvider | NodeFlags.TypePipe)) { - return asProviderData(view, def.index).instance; + return asProviderData(view, def.nodeIndex).instance; } throw new Error(`Illegal state: read nodeValue for node index ${index}`); } diff --git a/packages/core/src/view/services.ts b/packages/core/src/view/services.ts index 61df5225a7..3006195802 100644 --- a/packages/core/src/view/services.ts +++ b/packages/core/src/view/services.ts @@ -194,7 +194,7 @@ function applyProviderOverridesToView(def: ViewDefinition): ViewDefinition { } if (lastElementDef && nodeDef.flags & NodeFlags.CatProviderNoDirective && providerOverrides.has(nodeDef.provider !.token)) { - elIndicesWithOverwrittenProviders.push(lastElementDef !.index); + elIndicesWithOverwrittenProviders.push(lastElementDef !.nodeIndex); lastElementDef = null; } } @@ -260,22 +260,22 @@ function applyProviderOverridesToNgModule(def: NgModuleDefinition): NgModuleDefi } function prodCheckAndUpdateNode( - view: ViewData, nodeIndex: number, argStyle: ArgumentType, v0?: any, v1?: any, v2?: any, + view: ViewData, checkIndex: number, argStyle: ArgumentType, v0?: any, v1?: any, v2?: any, v3?: any, v4?: any, v5?: any, v6?: any, v7?: any, v8?: any, v9?: any): any { - const nodeDef = view.def.nodes[nodeIndex]; + const nodeDef = view.def.nodes[checkIndex]; checkAndUpdateNode(view, nodeDef, argStyle, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9); return (nodeDef.flags & NodeFlags.CatPureExpression) ? - asPureExpressionData(view, nodeIndex).value : + asPureExpressionData(view, checkIndex).value : undefined; } function prodCheckNoChangesNode( - view: ViewData, nodeIndex: number, argStyle: ArgumentType, v0?: any, v1?: any, v2?: any, + view: ViewData, checkIndex: number, argStyle: ArgumentType, v0?: any, v1?: any, v2?: any, v3?: any, v4?: any, v5?: any, v6?: any, v7?: any, v8?: any, v9?: any): any { - const nodeDef = view.def.nodes[nodeIndex]; + const nodeDef = view.def.nodes[checkIndex]; checkNoChangesNode(view, nodeDef, argStyle, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9); return (nodeDef.flags & NodeFlags.CatPureExpression) ? - asPureExpressionData(view, nodeIndex).value : + asPureExpressionData(view, checkIndex).value : undefined; } @@ -333,7 +333,7 @@ function debugUpdateDirectives(view: ViewData, checkType: CheckType) { debugSetCurrentNode(view, nextDirectiveWithBinding(view, nodeIndex)); } return (nodeDef.flags & NodeFlags.CatPureExpression) ? - asPureExpressionData(view, nodeDef.index).value : + asPureExpressionData(view, nodeDef.nodeIndex).value : undefined; } } @@ -357,7 +357,7 @@ function debugUpdateRenderer(view: ViewData, checkType: CheckType) { debugSetCurrentNode(view, nextRenderNodeWithBinding(view, nodeIndex)); } return (nodeDef.flags & NodeFlags.CatPureExpression) ? - asPureExpressionData(view, nodeDef.index).value : + asPureExpressionData(view, nodeDef.nodeIndex).value : undefined; } } @@ -378,7 +378,7 @@ function debugCheckAndUpdateNode( } } const elDef = nodeDef.parent !; - const el = asElementData(view, elDef.index).renderElement; + const el = asElementData(view, elDef.nodeIndex).renderElement; if (!elDef.element !.name) { // a comment. view.renderer.setValue(el, `bindings=${JSON.stringify(bindingValues, null, 2)}`); @@ -468,7 +468,7 @@ class DebugContext_ implements DebugContext { } private get elOrCompView() { // Has to be done lazily as we use the DebugContext also during creation of elements... - return asElementData(this.elView, this.elDef.index).componentView || this.view; + return asElementData(this.elView, this.elDef.nodeIndex).componentView || this.view; } get injector(): Injector { return createInjector(this.elView, this.elDef); } get component(): any { return this.elOrCompView.component; } @@ -476,7 +476,8 @@ class DebugContext_ implements DebugContext { get providerTokens(): any[] { const tokens: any[] = []; if (this.elDef) { - for (let i = this.elDef.index + 1; i <= this.elDef.index + this.elDef.childCount; i++) { + for (let i = this.elDef.nodeIndex + 1; i <= this.elDef.nodeIndex + this.elDef.childCount; + i++) { const childDef = this.elView.def.nodes[i]; if (childDef.flags & NodeFlags.CatProvider) { tokens.push(childDef.provider !.token); @@ -491,7 +492,8 @@ class DebugContext_ implements DebugContext { if (this.elDef) { collectReferences(this.elView, this.elDef, references); - for (let i = this.elDef.index + 1; i <= this.elDef.index + this.elDef.childCount; i++) { + for (let i = this.elDef.nodeIndex + 1; i <= this.elDef.nodeIndex + this.elDef.childCount; + i++) { const childDef = this.elView.def.nodes[i]; if (childDef.flags & NodeFlags.CatProvider) { collectReferences(this.elView, childDef, references); @@ -514,10 +516,10 @@ class DebugContext_ implements DebugContext { let logNodeIndex: number; if (this.nodeDef.flags & NodeFlags.TypeText) { logViewDef = this.view.def; - logNodeIndex = this.nodeDef.index; + logNodeIndex = this.nodeDef.nodeIndex; } else { logViewDef = this.elView.def; - logNodeIndex = this.elDef.index; + logNodeIndex = this.elDef.nodeIndex; } // Note: we only generate a log function for text and element nodes // to make the generated code as small as possible. @@ -555,7 +557,7 @@ function findHostElement(view: ViewData): ElementData|null { view = view.parent !; } if (view.parent) { - return asElementData(view.parent, viewParentEl(view) !.index); + return asElementData(view.parent, viewParentEl(view) !.nodeIndex); } return null; } diff --git a/packages/core/src/view/text.ts b/packages/core/src/view/text.ts index fe206635b0..e5abed2a22 100644 --- a/packages/core/src/view/text.ts +++ b/packages/core/src/view/text.ts @@ -9,7 +9,8 @@ import {BindingDef, BindingFlags, NodeDef, NodeFlags, TextData, ViewData, asTextData} from './types'; import {checkAndUpdateBinding, getParentRenderElement} from './util'; -export function textDef(ngContentIndex: number, staticText: string[]): NodeDef { +export function textDef( + checkIndex: number, ngContentIndex: number | null, staticText: string[]): NodeDef { const bindings: BindingDef[] = new Array(staticText.length - 1); for (let i = 1; i < staticText.length; i++) { bindings[i - 1] = { @@ -24,12 +25,13 @@ export function textDef(ngContentIndex: number, staticText: string[]): NodeDef { return { // will bet set by the view definition - index: -1, + nodeIndex: -1, parent: null, renderParent: null, bindingIndex: -1, outputIndex: -1, // regular values + checkIndex, flags: NodeFlags.TypeText, childFlags: 0, directChildFlags: 0, @@ -88,7 +90,7 @@ export function checkAndUpdateTextInline( if (bindLen > 7) value += _addInterpolationPart(v7, bindings[7]); if (bindLen > 8) value += _addInterpolationPart(v8, bindings[8]); if (bindLen > 9) value += _addInterpolationPart(v9, bindings[9]); - const renderNode = asTextData(view, def.index).renderText; + const renderNode = asTextData(view, def.nodeIndex).renderText; view.renderer.setValue(renderNode, value); } return changed; @@ -110,7 +112,7 @@ export function checkAndUpdateTextDynamic(view: ViewData, def: NodeDef, values: value = value + _addInterpolationPart(values[i], bindings[i]); } value = def.text !.prefix + value; - const renderNode = asTextData(view, def.index).renderText; + const renderNode = asTextData(view, def.nodeIndex).renderText; view.renderer.setValue(renderNode, value); } return changed; diff --git a/packages/core/src/view/types.ts b/packages/core/src/view/types.ts index 081a49bfc3..011578a687 100644 --- a/packages/core/src/view/types.ts +++ b/packages/core/src/view/types.ts @@ -103,11 +103,15 @@ export const enum ViewFlags { */ export interface NodeDef { flags: NodeFlags; - index: number; + // Index of the node in view data and view definition (those are the same) + nodeIndex: number; + // Index of the node in the check functions + // Differ from nodeIndex when nodes are added or removed at runtime (ie after compilation) + checkIndex: number; parent: NodeDef|null; renderParent: NodeDef|null; /** this is checked against NgContentDef.index to find matched nodes */ - ngContentIndex: number; + ngContentIndex: number|null; /** number of transitive children */ childCount: number; /** aggregated NodeFlags for all transitive children (does not include self) **/ diff --git a/packages/core/src/view/util.ts b/packages/core/src/view/util.ts index 48016f29f4..a1b3219a9e 100644 --- a/packages/core/src/view/util.ts +++ b/packages/core/src/view/util.ts @@ -102,7 +102,7 @@ export function checkBindingNoChanges( const oldValue = view.oldValues[def.bindingIndex + bindingIdx]; if ((view.state & ViewState.BeforeFirstCheck) || !devModeEqual(oldValue, value)) { throw expressionChangedAfterItHasBeenCheckedError( - Services.createDebugContext(view, def.index), oldValue, value, + Services.createDebugContext(view, def.nodeIndex), oldValue, value, (view.state & ViewState.BeforeFirstCheck) !== 0); } } @@ -143,7 +143,7 @@ export function dispatchEvent( export function declaredViewContainer(view: ViewData): ElementData|null { if (view.parent) { const parentView = view.parent; - return asElementData(parentView, view.parentNodeDef !.index); + return asElementData(parentView, view.parentNodeDef !.nodeIndex); } return null; } @@ -165,9 +165,9 @@ export function viewParentEl(view: ViewData): NodeDef|null { export function renderNode(view: ViewData, def: NodeDef): any { switch (def.flags & NodeFlags.Types) { case NodeFlags.TypeElement: - return asElementData(view, def.index).renderElement; + return asElementData(view, def.nodeIndex).renderElement; case NodeFlags.TypeText: - return asTextData(view, def.index).renderText; + return asTextData(view, def.nodeIndex).renderText; } } @@ -233,7 +233,7 @@ export function getParentRenderElement(view: ViewData, renderHost: any, def: Nod ViewEncapsulation.Native)) { // only children of non components, or children of components with native encapsulation should // be attached. - return asElementData(view, def.renderParent !.index).renderElement; + return asElementData(view, def.renderParent !.nodeIndex).renderElement; } } else { return renderHost; @@ -292,8 +292,8 @@ export function visitProjectedRenderNodes( } const hostView = compView !.parent; const hostElDef = viewParentEl(compView !); - const startIndex = hostElDef !.index + 1; - const endIndex = hostElDef !.index + hostElDef !.childCount; + const startIndex = hostElDef !.nodeIndex + 1; + const endIndex = hostElDef !.nodeIndex + hostElDef !.childCount; for (let i = startIndex; i <= endIndex; i++) { const nodeDef = hostView !.def.nodes[i]; if (nodeDef.ngContentIndex === ngContentIndex) { @@ -328,21 +328,21 @@ function visitRenderNode( execRenderNodeAction(view, rn, action, parentNode, nextSibling, target); } if (nodeDef.bindingFlags & (BindingFlags.SyntheticHostProperty)) { - const compView = asElementData(view, nodeDef.index).componentView; + const compView = asElementData(view, nodeDef.nodeIndex).componentView; execRenderNodeAction(compView, rn, action, parentNode, nextSibling, target); } } else { execRenderNodeAction(view, rn, action, parentNode, nextSibling, target); } if (nodeDef.flags & NodeFlags.EmbeddedViews) { - const embeddedViews = asElementData(view, nodeDef.index).viewContainer !._embeddedViews; + const embeddedViews = asElementData(view, nodeDef.nodeIndex).viewContainer !._embeddedViews; for (let k = 0; k < embeddedViews.length; k++) { visitRootRenderNodes(embeddedViews[k], action, parentNode, nextSibling, target); } } if (nodeDef.flags & NodeFlags.TypeElement && !nodeDef.element !.name) { visitSiblingRenderNodes( - view, action, nodeDef.index + 1, nodeDef.index + nodeDef.childCount, parentNode, + view, action, nodeDef.nodeIndex + 1, nodeDef.nodeIndex + nodeDef.childCount, parentNode, nextSibling, target); } } diff --git a/packages/core/src/view/view.ts b/packages/core/src/view/view.ts index 54bc6abbec..ad86d558d8 100644 --- a/packages/core/src/view/view.ts +++ b/packages/core/src/view/view.ts @@ -21,8 +21,8 @@ import {NOOP, checkBindingNoChanges, isComponentView, markParentViewsForCheckPro import {detachProjectedView} from './view_attach'; export function viewDef( - flags: ViewFlags, nodes: NodeDef[], updateDirectives?: ViewUpdateFn, - updateRenderer?: ViewUpdateFn): ViewDefinition { + flags: ViewFlags, nodes: NodeDef[], updateDirectives?: null | ViewUpdateFn, + updateRenderer?: null | ViewUpdateFn): ViewDefinition { // clone nodes and set auto calculated values let viewBindingCount = 0; let viewDisposableCount = 0; @@ -36,7 +36,7 @@ export function viewDef( let lastRenderRootNode: NodeDef|null = null; for (let i = 0; i < nodes.length; i++) { const node = nodes[i]; - node.index = i; + node.nodeIndex = i; node.parent = currentParent; node.bindingIndex = viewBindingCount; node.outputIndex = viewDisposableCount; @@ -117,7 +117,7 @@ export function viewDef( // The loop is required because an element could be the last transitive children of several // elements. We loop to either the root or the highest opened element (= with remaining // children) - while (currentParent && i === currentParent.index + currentParent.childCount) { + while (currentParent && i === currentParent.nodeIndex + currentParent.childCount) { const newParent: NodeDef|null = currentParent.parent; if (newParent) { newParent.childFlags |= currentParent.childFlags; @@ -164,32 +164,32 @@ function validateNode(parent: NodeDef | null, node: NodeDef, nodeCount: number) if (template.lastRenderRootNode && template.lastRenderRootNode.flags & NodeFlags.EmbeddedViews) { throw new Error( - `Illegal State: Last root node of a template can't have embedded views, at index ${node.index}!`); + `Illegal State: Last root node of a template can't have embedded views, at index ${node.nodeIndex}!`); } } if (node.flags & NodeFlags.CatProvider) { const parentFlags = parent ? parent.flags : 0; if ((parentFlags & NodeFlags.TypeElement) === 0) { throw new Error( - `Illegal State: StaticProvider/Directive nodes need to be children of elements or anchors, at index ${node.index}!`); + `Illegal State: StaticProvider/Directive nodes need to be children of elements or anchors, at index ${node.nodeIndex}!`); } } if (node.query) { if (node.flags & NodeFlags.TypeContentQuery && (!parent || (parent.flags & NodeFlags.TypeDirective) === 0)) { throw new Error( - `Illegal State: Content Query nodes need to be children of directives, at index ${node.index}!`); + `Illegal State: Content Query nodes need to be children of directives, at index ${node.nodeIndex}!`); } if (node.flags & NodeFlags.TypeViewQuery && parent) { throw new Error( - `Illegal State: View Query nodes have to be top level nodes, at index ${node.index}!`); + `Illegal State: View Query nodes have to be top level nodes, at index ${node.nodeIndex}!`); } } if (node.childCount) { - const parentEnd = parent ? parent.index + parent.childCount : nodeCount - 1; - if (node.index <= parentEnd && node.index + node.childCount > parentEnd) { + const parentEnd = parent ? parent.nodeIndex + parent.childCount : nodeCount - 1; + if (node.nodeIndex <= parentEnd && node.nodeIndex + node.childCount > parentEnd) { throw new Error( - `Illegal State: childCount of node leads outside of parent, at index ${node.index}!`); + `Illegal State: childCount of node leads outside of parent, at index ${node.nodeIndex}!`); } } } @@ -250,7 +250,7 @@ function createViewNodes(view: ViewData) { let renderHost: any; if (isComponentView(view)) { const hostDef = view.parentNodeDef; - renderHost = asElementData(view.parent !, hostDef !.parent !.index).renderElement; + renderHost = asElementData(view.parent !, hostDef !.parent !.nodeIndex).renderElement; } const def = view.def; const nodes = view.nodes; @@ -297,7 +297,7 @@ function createViewNodes(view: ViewData) { const instance = createDirectiveInstance(view, nodeDef); nodeData = {instance}; if (nodeDef.flags & NodeFlags.Component) { - const compView = asElementData(view, nodeDef.parent !.index).componentView; + const compView = asElementData(view, nodeDef.parent !.nodeIndex).componentView; initView(compView, instance, instance); } break; @@ -410,47 +410,38 @@ function markProjectedViewsForCheck(view: ViewData) { function checkAndUpdateNodeInline( view: ViewData, nodeDef: NodeDef, v0?: any, v1?: any, v2?: any, v3?: any, v4?: any, v5?: any, v6?: any, v7?: any, v8?: any, v9?: any): boolean { - let changed = false; switch (nodeDef.flags & NodeFlags.Types) { case NodeFlags.TypeElement: - changed = checkAndUpdateElementInline(view, nodeDef, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9); - break; + return checkAndUpdateElementInline(view, nodeDef, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9); case NodeFlags.TypeText: - changed = checkAndUpdateTextInline(view, nodeDef, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9); - break; + return checkAndUpdateTextInline(view, nodeDef, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9); case NodeFlags.TypeDirective: - changed = - checkAndUpdateDirectiveInline(view, nodeDef, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9); - break; + return checkAndUpdateDirectiveInline(view, nodeDef, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9); case NodeFlags.TypePureArray: case NodeFlags.TypePureObject: case NodeFlags.TypePurePipe: - changed = - checkAndUpdatePureExpressionInline(view, nodeDef, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9); - break; + return checkAndUpdatePureExpressionInline( + view, nodeDef, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9); + default: + throw 'unreachable'; } - return changed; } function checkAndUpdateNodeDynamic(view: ViewData, nodeDef: NodeDef, values: any[]): boolean { - let changed = false; switch (nodeDef.flags & NodeFlags.Types) { case NodeFlags.TypeElement: - changed = checkAndUpdateElementDynamic(view, nodeDef, values); - break; + return checkAndUpdateElementDynamic(view, nodeDef, values); case NodeFlags.TypeText: - changed = checkAndUpdateTextDynamic(view, nodeDef, values); - break; + return checkAndUpdateTextDynamic(view, nodeDef, values); case NodeFlags.TypeDirective: - changed = checkAndUpdateDirectiveDynamic(view, nodeDef, values); - break; + return checkAndUpdateDirectiveDynamic(view, nodeDef, values); case NodeFlags.TypePureArray: case NodeFlags.TypePureObject: case NodeFlags.TypePurePipe: - changed = checkAndUpdatePureExpressionDynamic(view, nodeDef, values); - break; + return checkAndUpdatePureExpressionDynamic(view, nodeDef, values); + default: + throw 'unreachable'; } - return changed; } export function checkNoChangesNode( @@ -492,11 +483,12 @@ function checkNoChangesNodeDynamic(view: ViewData, nodeDef: NodeDef, values: any * @suppress {misplacedTypeAnnotation} */ function checkNoChangesQuery(view: ViewData, nodeDef: NodeDef) { - const queryList = asQueryList(view, nodeDef.index); + const queryList = asQueryList(view, nodeDef.nodeIndex); if (queryList.dirty) { throw expressionChangedAfterItHasBeenCheckedError( - Services.createDebugContext(view, nodeDef.index), `Query ${nodeDef.query!.id} not dirty`, - `Query ${nodeDef.query!.id} dirty`, (view.state & ViewState.BeforeFirstCheck) !== 0); + Services.createDebugContext(view, nodeDef.nodeIndex), + `Query ${nodeDef.query!.id} not dirty`, `Query ${nodeDef.query!.id} dirty`, + (view.state & ViewState.BeforeFirstCheck) !== 0); } } @@ -651,7 +643,7 @@ function execQueriesAction( for (let i = 0; i < nodeCount; i++) { const nodeDef = view.def.nodes[i]; if ((nodeDef.flags & queryFlags) && (nodeDef.flags & staticDynamicQueryFlag)) { - Services.setCurrentNode(view, nodeDef.index); + Services.setCurrentNode(view, nodeDef.nodeIndex); switch (checkType) { case CheckType.CheckAndUpdate: checkAndUpdateQuery(view, nodeDef); diff --git a/packages/core/test/view/anchor_spec.ts b/packages/core/test/view/anchor_spec.ts index 9525097c5f..c50b1e14cc 100644 --- a/packages/core/test/view/anchor_spec.ts +++ b/packages/core/test/view/anchor_spec.ts @@ -6,47 +6,35 @@ * found in the LICENSE file at https://angular.io/license */ -import {Injector, RenderComponentType, RootRenderer, Sanitizer, SecurityContext, ViewEncapsulation, getDebugNode} from '@angular/core'; -import {DebugContext, NodeDef, NodeFlags, RootData, Services, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, asElementData, elementDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index'; +import {getDebugNode} from '@angular/core'; +import {NodeFlags, anchorDef, asElementData, elementDef} from '@angular/core/src/view/index'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; -import {createRootView, isBrowser} from './helper'; +import {compViewDef, createAndGetRootNodes} from './helper'; export function main() { describe(`View Anchor`, () => { - function compViewDef( - nodes: NodeDef[], updateDirectives?: ViewUpdateFn, - updateRenderer?: ViewUpdateFn): ViewDefinition { - return viewDef(ViewFlags.None, nodes, updateDirectives, updateRenderer); - } - - function createAndGetRootNodes( - viewDef: ViewDefinition, ctx?: any): {rootNodes: any[], view: ViewData} { - const view = createRootView(viewDef, ctx); - const rootNodes = rootRenderNodes(view); - return {rootNodes, view}; - } describe('create', () => { it('should create anchor nodes without parents', () => { const rootNodes = createAndGetRootNodes(compViewDef([ - anchorDef(NodeFlags.None, null !, null !, 0) + anchorDef(NodeFlags.None, null, null, 0) ])).rootNodes; expect(rootNodes.length).toBe(1); }); it('should create views with multiple root anchor nodes', () => { - const rootNodes = createAndGetRootNodes(compViewDef([ - anchorDef(NodeFlags.None, null !, null !, 0), - anchorDef(NodeFlags.None, null !, null !, 0) - ])).rootNodes; + const rootNodes = + createAndGetRootNodes(compViewDef([ + anchorDef(NodeFlags.None, null, null, 0), anchorDef(NodeFlags.None, null, null, 0) + ])).rootNodes; expect(rootNodes.length).toBe(2); }); it('should create anchor nodes with parents', () => { const rootNodes = createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 1, 'div'), - anchorDef(NodeFlags.None, null !, null !, 0), + elementDef(0, NodeFlags.None, null, null, 1, 'div'), + anchorDef(NodeFlags.None, null, null, 0), ])).rootNodes; expect(getDOM().childNodes(rootNodes[0]).length).toBe(1); }); @@ -54,7 +42,7 @@ export function main() { it('should add debug information to the renderer', () => { const someContext = new Object(); const {view, rootNodes} = createAndGetRootNodes( - compViewDef([anchorDef(NodeFlags.None, null !, null !, 0)]), someContext); + compViewDef([anchorDef(NodeFlags.None, null, null, 0)]), someContext); expect(getDebugNode(rootNodes[0]) !.nativeNode).toBe(asElementData(view, 0).renderElement); }); }); diff --git a/packages/core/test/view/component_view_spec.ts b/packages/core/test/view/component_view_spec.ts index f6567ab09a..dee406acff 100644 --- a/packages/core/test/view/component_view_spec.ts +++ b/packages/core/test/view/component_view_spec.ts @@ -6,11 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ -import {Injector, RenderComponentType, RootRenderer, Sanitizer, SecurityContext, ViewEncapsulation} from '@angular/core'; -import {ArgumentType, BindingFlags, NodeCheckFn, NodeDef, NodeFlags, OutputType, RootData, Services, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewState, ViewUpdateFn, anchorDef, asElementData, asProviderData, directiveDef, elementDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index'; +import {SecurityContext} from '@angular/core'; +import {ArgumentType, BindingFlags, NodeCheckFn, NodeFlags, Services, ViewData, ViewFlags, ViewState, asElementData, directiveDef, elementDef, rootRenderNodes} from '@angular/core/src/view/index'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; -import {callMostRecentEventListenerHandler, createRootView, isBrowser, recordNodeToRemove} from './helper'; +import {callMostRecentEventListenerHandler, compViewDef, createAndGetRootNodes, createRootView, isBrowser, recordNodeToRemove} from './helper'; + /** @@ -21,18 +22,6 @@ const addEventListener = '__zone_symbol__addEventListener'; export function main() { describe(`Component Views`, () => { - function compViewDef( - nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn, - viewFlags: ViewFlags = ViewFlags.None): ViewDefinition { - return viewDef(viewFlags, nodes, updateDirectives, updateRenderer); - } - - function createAndGetRootNodes(viewDef: ViewDefinition): {rootNodes: any[], view: ViewData} { - const view = createRootView(viewDef); - const rootNodes = rootRenderNodes(view); - return {rootNodes, view}; - } - it('should create and attach component views', () => { let instance: AComp = undefined !; class AComp { @@ -41,11 +30,11 @@ export function main() { const {view, rootNodes} = createAndGetRootNodes(compViewDef([ elementDef( - NodeFlags.None, null !, null !, 1, 'div', null !, null !, null !, null !, + 0, NodeFlags.None, null, null, 1, 'div', null, null, null, null, () => compViewDef([ - elementDef(NodeFlags.None, null !, null !, 0, 'span'), + elementDef(0, NodeFlags.None, null, null, 0, 'span'), ])), - directiveDef(NodeFlags.Component, null !, 0, AComp, []), + directiveDef(1, NodeFlags.Component, null, 0, AComp, []), ])); const compView = asElementData(view, 0).componentView; @@ -69,7 +58,7 @@ export function main() { it('should select root elements based on a selector', () => { const view = createRootView( compViewDef([ - elementDef(NodeFlags.None, null !, null !, 0, 'div'), + elementDef(0, NodeFlags.None, null, null, 0, 'div'), ]), {}, [], 'root'); const rootNodes = rootRenderNodes(view); @@ -79,7 +68,7 @@ export function main() { it('should select root elements based on a node', () => { const view = createRootView( compViewDef([ - elementDef(NodeFlags.None, null !, null !, 0, 'div'), + elementDef(0, NodeFlags.None, null, null, 0, 'div'), ]), {}, [], rootNode); const rootNodes = rootRenderNodes(view); @@ -87,9 +76,9 @@ export function main() { }); it('should set attributes on the root node', () => { - const view = createRootView( + createRootView( compViewDef([ - elementDef(NodeFlags.None, null !, null !, 0, 'div', [['a', 'b']]), + elementDef(0, NodeFlags.None, null, null, 0, 'div', [['a', 'b']]), ]), {}, [], rootNode); expect(rootNode.getAttribute('a')).toBe('b'); @@ -97,9 +86,9 @@ export function main() { it('should clear the content of the root node', () => { rootNode.appendChild(document.createElement('div')); - const view = createRootView( + createRootView( compViewDef([ - elementDef(NodeFlags.None, null !, null !, 0, 'div', [['a', 'b']]), + elementDef(0, NodeFlags.None, null, null, 0, 'div', [['a', 'b']]), ]), {}, [], rootNode); expect(rootNode.childNodes.length).toBe(0); @@ -121,12 +110,12 @@ export function main() { const {view, rootNodes} = createAndGetRootNodes( compViewDef([ - elementDef(NodeFlags.None, null!, null!, 1, 'div', null!, null!, null!, null!, () => compViewDef( + elementDef(0, NodeFlags.None, null, null, 1, 'div', null, null, null, null, () => compViewDef( [ - elementDef(NodeFlags.None, null!, null!, 0, 'span', null!, [[BindingFlags.TypeElementAttribute, 'a', SecurityContext.NONE]]), - ], null!, update + elementDef(0, NodeFlags.None, null, null, 0, 'span', null, [[BindingFlags.TypeElementAttribute, 'a', SecurityContext.NONE]]), + ], null, update )), - directiveDef(NodeFlags.Component, null!, 0, AComp, []), + directiveDef(1, NodeFlags.Component, null, 0, AComp, []), ])); const compView = asElementData(view, 0).componentView; @@ -155,13 +144,13 @@ export function main() { const {view, rootNodes} = createAndGetRootNodes(compViewDef([ elementDef( - NodeFlags.None, null !, null !, 1, 'div', null !, null !, null !, null !, + 0, NodeFlags.None, null, null, 1, 'div', null, null, null, null, () => compViewDef( [ - elementDef(NodeFlags.None, null !, null !, 0, 'span'), + elementDef(0, NodeFlags.None, null, null, 0, 'span'), ], update)), - directiveDef(NodeFlags.Component, null !, 0, AComp, [], null !, null !), + directiveDef(1, NodeFlags.Component, null, 0, AComp, [], null, null), ])); const compView = asElementData(view, 0).componentView; @@ -192,17 +181,17 @@ export function main() { const {view} = createAndGetRootNodes(compViewDef( [ elementDef( - NodeFlags.None, null !, null !, 1, 'div', null !, null !, null !, null !, + 0, NodeFlags.None, null, null, 1, 'div', null, null, null, null, () => { return compViewDef( [ elementDef( - NodeFlags.None, null !, null !, 0, 'span', null !, null !, + 0, NodeFlags.None, null, null, 0, 'span', null, null, [[null !, 'click']]), ], - update, null !, ViewFlags.OnPush); + update, null, ViewFlags.OnPush); }), - directiveDef(NodeFlags.Component, null !, 0, AComp, [], {a: [0, 'a']}), + directiveDef(1, NodeFlags.Component, null, 0, AComp, [], {a: [0, 'a']}), ], (check, view) => { check(view, 1, ArgumentType.Inline, compInputValue); })); @@ -245,18 +234,16 @@ export function main() { const update = jasmine.createSpy('updater'); const {view, rootNodes} = createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null!, null!, 1, 'div', null!, null!, null!, null!, () => compViewDef( - [ - elementDef(NodeFlags.None, null!, null!, 0, 'span', null!, [[BindingFlags.TypeElementAttribute, 'a', SecurityContext.NONE]]), - ], - null!, update)), - directiveDef( - NodeFlags.Component, null!, 0, AComp, [], null!, null!, - ), + elementDef( + 0, NodeFlags.None, null, null, 1, 'div', null, null, null, null, + () => compViewDef( + [elementDef( + 0, NodeFlags.None, null, null, 0, 'span', null, + [[BindingFlags.TypeElementAttribute, 'a', SecurityContext.NONE]])], + null, update)), + directiveDef(1, NodeFlags.Component, null, 0, AComp, [], null, null, ), ])); - const compView = asElementData(view, 0).componentView; - update.and.callFake((check: NodeCheckFn, view: ViewData) => { throw new Error('Test'); }); expect(() => Services.checkAndUpdateView(view)).toThrowError('Test'); expect(update).toHaveBeenCalled(); @@ -280,12 +267,12 @@ export function main() { const {view, rootNodes} = createAndGetRootNodes(compViewDef([ elementDef( - NodeFlags.None, null !, null !, 1, 'div', null !, null !, null !, null !, + 0, NodeFlags.None, null, null, 1, 'div', null, null, null, null, () => compViewDef([ - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - directiveDef(NodeFlags.OnDestroy, null !, 0, ChildProvider, []) + elementDef(0, NodeFlags.None, null, null, 1, 'span'), + directiveDef(1, NodeFlags.OnDestroy, null, 0, ChildProvider, []) ])), - directiveDef(NodeFlags.Component, null !, 0, AComp, [], null !, null !, ), + directiveDef(1, NodeFlags.Component, null, 0, AComp, [], null, null, ), ])); Services.destroyView(view); @@ -294,11 +281,8 @@ export function main() { }); it('should throw on dirty checking destroyed views', () => { - const {view, rootNodes} = createAndGetRootNodes(compViewDef( - [ - elementDef(NodeFlags.None, null !, null !, 0, 'div'), - ], - (view) => {})); + const {view, rootNodes} = createAndGetRootNodes( + compViewDef([elementDef(0, NodeFlags.None, null, null, 0, 'div')])); Services.destroyView(view); diff --git a/packages/core/test/view/element_spec.ts b/packages/core/test/view/element_spec.ts index 88932b6bcb..21dba2e136 100644 --- a/packages/core/test/view/element_spec.ts +++ b/packages/core/test/view/element_spec.ts @@ -6,13 +6,14 @@ * found in the LICENSE file at https://angular.io/license */ -import {ErrorHandler, Injector, RenderComponentType, RootRenderer, Sanitizer, SecurityContext, ViewEncapsulation, WrappedValue, getDebugNode} from '@angular/core'; +import {ErrorHandler, SecurityContext, getDebugNode} from '@angular/core'; import {getDebugContext} from '@angular/core/src/errors'; -import {ArgumentType, BindingFlags, DebugContext, NodeDef, NodeFlags, OutputType, RootData, Services, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, asElementData, elementDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index'; +import {BindingFlags, NodeFlags, Services, ViewData, ViewDefinition, asElementData, elementDef} from '@angular/core/src/view/index'; import {TestBed} from '@angular/core/testing'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; -import {ARG_TYPE_VALUES, callMostRecentEventListenerHandler, checkNodeInlineOrDynamic, createRootView, isBrowser, recordNodeToRemove} from './helper'; +import {ARG_TYPE_VALUES, callMostRecentEventListenerHandler, checkNodeInlineOrDynamic, compViewDef, createAndGetRootNodes, isBrowser, recordNodeToRemove} from './helper'; + /** @@ -24,23 +25,11 @@ const removeEventListener = '__zone_symbol__removeEventListener'; export function main() { describe(`View Elements`, () => { - function compViewDef( - nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn, - viewFlags: ViewFlags = ViewFlags.None): ViewDefinition { - return viewDef(viewFlags, nodes, updateDirectives, updateRenderer); - } - - function createAndGetRootNodes( - viewDef: ViewDefinition, context?: any): {rootNodes: any[], view: ViewData} { - const view = createRootView(viewDef, context); - const rootNodes = rootRenderNodes(view); - return {rootNodes, view}; - } describe('create', () => { it('should create elements without parents', () => { const rootNodes = createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 0, 'span') + elementDef(0, NodeFlags.None, null, null, 0, 'span') ])).rootNodes; expect(rootNodes.length).toBe(1); expect(getDOM().nodeName(rootNodes[0]).toLowerCase()).toBe('span'); @@ -48,16 +37,16 @@ export function main() { it('should create views with multiple root elements', () => { const rootNodes = createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 0, 'span'), - elementDef(NodeFlags.None, null !, null !, 0, 'span') + elementDef(0, NodeFlags.None, null, null, 0, 'span'), + elementDef(1, NodeFlags.None, null, null, 0, 'span'), ])).rootNodes; expect(rootNodes.length).toBe(2); }); it('should create elements with parents', () => { const rootNodes = createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 1, 'div'), - elementDef(NodeFlags.None, null !, null !, 0, 'span'), + elementDef(0, NodeFlags.None, null, null, 1, 'div'), + elementDef(1, NodeFlags.None, null, null, 0, 'span'), ])).rootNodes; expect(rootNodes.length).toBe(1); const spanEl = getDOM().childNodes(rootNodes[0])[0]; @@ -66,7 +55,7 @@ export function main() { it('should set fixed attributes', () => { const rootNodes = createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 0, 'div', [['title', 'a']]), + elementDef(0, NodeFlags.None, null, null, 0, 'div', [['title', 'a']]), ])).rootNodes; expect(rootNodes.length).toBe(1); expect(getDOM().getAttribute(rootNodes[0], 'title')).toBe('a'); @@ -75,7 +64,7 @@ export function main() { it('should add debug information to the renderer', () => { const someContext = new Object(); const {view, rootNodes} = createAndGetRootNodes( - compViewDef([elementDef(NodeFlags.None, null !, null !, 0, 'div')]), someContext); + compViewDef([elementDef(0, NodeFlags.None, null, null, 0, 'div')]), someContext); expect(getDebugNode(rootNodes[0]) !.nativeNode).toBe(asElementData(view, 0).renderElement); }); }); @@ -87,13 +76,13 @@ export function main() { const {view, rootNodes} = createAndGetRootNodes(compViewDef( [ elementDef( - NodeFlags.None, null !, null !, 0, 'input', null !, + 0, NodeFlags.None, null, null, 0, 'input', null, [ [BindingFlags.TypeProperty, 'title', SecurityContext.NONE], - [BindingFlags.TypeProperty, 'value', SecurityContext.NONE] + [BindingFlags.TypeProperty, 'value', SecurityContext.NONE], ]), ], - null !, (check, view) => { + null, (check, view) => { checkNodeInlineOrDynamic(check, view, 0, inlineDynamic, ['v1', 'v2']); })); @@ -112,13 +101,13 @@ export function main() { const {view, rootNodes} = createAndGetRootNodes(compViewDef( [ elementDef( - NodeFlags.None, null !, null !, 0, 'div', null !, + 0, NodeFlags.None, null, null, 0, 'div', null, [ [BindingFlags.TypeElementAttribute, 'a1', SecurityContext.NONE], - [BindingFlags.TypeElementAttribute, 'a2', SecurityContext.NONE] + [BindingFlags.TypeElementAttribute, 'a2', SecurityContext.NONE], ]), ], - null !, (check, view) => { + null, (check, view) => { checkNodeInlineOrDynamic(check, view, 0, inlineDynamic, ['v1', 'v2']); })); @@ -137,10 +126,10 @@ export function main() { const {view, rootNodes} = createAndGetRootNodes(compViewDef( [ elementDef( - NodeFlags.None, null !, null !, 0, 'div', null !, + 0, NodeFlags.None, null, null, 0, 'div', null, [ - [BindingFlags.TypeElementClass, 'c1', null !], - [BindingFlags.TypeElementClass, 'c2', null !] + [BindingFlags.TypeElementClass, 'c1', null], + [BindingFlags.TypeElementClass, 'c2', null], ]), ], (check, view) => { @@ -162,13 +151,13 @@ export function main() { const {view, rootNodes} = createAndGetRootNodes(compViewDef( [ elementDef( - NodeFlags.None, null !, null !, 0, 'div', null !, + 0, NodeFlags.None, null, null, 0, 'div', null, [ [BindingFlags.TypeElementStyle, 'width', 'px'], - [BindingFlags.TypeElementStyle, 'color', null !] + [BindingFlags.TypeElementStyle, 'color', null], ]), ], - null !, (check, view) => { + null, (check, view) => { checkNodeInlineOrDynamic(check, view, 0, inlineDynamic, [10, 'red']); })); @@ -200,7 +189,7 @@ export function main() { const removeListenerSpy = spyOn(HTMLElement.prototype, removeEventListener).and.callThrough(); const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef([elementDef( - NodeFlags.None, null !, null !, 0, 'button', null !, null !, [[null !, 'click']], + 0, NodeFlags.None, null, null, 0, 'button', null, null, [[null !, 'click']], handleEventSpy)])); rootNodes[0].click(); @@ -221,8 +210,8 @@ export function main() { const addListenerSpy = spyOn(window, addEventListener); const removeListenerSpy = spyOn(window, removeEventListener); const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef([elementDef( - NodeFlags.None, null !, null !, 0, 'button', null !, null !, - [['window', 'windowClick']], handleEventSpy)])); + 0, NodeFlags.None, null, null, 0, 'button', null, null, [['window', 'windowClick']], + handleEventSpy)])); expect(addListenerSpy).toHaveBeenCalled(); expect(addListenerSpy.calls.mostRecent().args[0]).toBe('windowClick'); @@ -244,7 +233,7 @@ export function main() { const addListenerSpy = spyOn(document, addEventListener); const removeListenerSpy = spyOn(document, removeEventListener); const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef([elementDef( - NodeFlags.None, null !, null !, 0, 'button', null !, null !, + 0, NodeFlags.None, null, null, 0, 'button', null, null, [['document', 'documentClick']], handleEventSpy)])); expect(addListenerSpy).toHaveBeenCalled(); @@ -267,7 +256,7 @@ export function main() { let preventDefaultSpy: jasmine.Spy = undefined !; const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef([elementDef( - NodeFlags.None, null !, null !, 0, 'button', null !, null !, [[null !, 'click']], + 0, NodeFlags.None, null, null, 0, 'button', null, null, [[null !, 'click']], (view, eventName, event) => { preventDefaultSpy = spyOn(event, 'preventDefault').and.callThrough(); return eventHandlerResult; @@ -294,7 +283,7 @@ export function main() { const handleErrorSpy = spyOn(TestBed.get(ErrorHandler), 'handleError'); const addListenerSpy = spyOn(HTMLElement.prototype, addEventListener).and.callThrough(); const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef([elementDef( - NodeFlags.None, null !, null !, 0, 'button', null !, null !, [[null !, 'click']], + 0, NodeFlags.None, null, null, 0, 'button', null, null, [[null !, 'click']], () => { throw new Error('Test'); })])); callMostRecentEventListenerHandler(addListenerSpy, 'SomeEvent'); diff --git a/packages/core/test/view/embedded_view_spec.ts b/packages/core/test/view/embedded_view_spec.ts index c0fe6980d6..c67c080555 100644 --- a/packages/core/test/view/embedded_view_spec.ts +++ b/packages/core/test/view/embedded_view_spec.ts @@ -6,31 +6,14 @@ * found in the LICENSE file at https://angular.io/license */ -import {Injector, RenderComponentType, RootRenderer, Sanitizer, SecurityContext, ViewEncapsulation} from '@angular/core'; -import {ArgumentType, BindingFlags, NodeCheckFn, NodeDef, NodeFlags, RootData, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, asElementData, attachEmbeddedView, detachEmbeddedView, directiveDef, elementDef, moveEmbeddedView, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index'; -import {inject} from '@angular/core/testing'; +import {SecurityContext} from '@angular/core'; +import {ArgumentType, BindingFlags, NodeCheckFn, NodeFlags, Services, ViewData, anchorDef, asElementData, attachEmbeddedView, detachEmbeddedView, directiveDef, elementDef, moveEmbeddedView, rootRenderNodes} from '@angular/core/src/view/index'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; -import {createEmbeddedView, createRootView, isBrowser} from './helper'; +import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedView} from './helper'; export function main() { describe(`Embedded Views`, () => { - function compViewDef( - nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn, - viewFlags: ViewFlags = ViewFlags.None): ViewDefinition { - return viewDef(viewFlags, nodes, updateDirectives, updateRenderer); - } - - function embeddedViewDef(nodes: NodeDef[], update?: ViewUpdateFn): ViewDefinitionFactory { - return () => viewDef(ViewFlags.None, nodes, update); - } - - function createAndGetRootNodes( - viewDef: ViewDefinition, context: any = null): {rootNodes: any[], view: ViewData} { - const view = createRootView(viewDef, context); - const rootNodes = rootRenderNodes(view); - return {rootNodes, view}; - } it('should create embedded views with the right context', () => { const parentContext = new Object(); @@ -38,10 +21,10 @@ export function main() { const {view: parentView} = createAndGetRootNodes( compViewDef([ - elementDef(NodeFlags.None, null !, null !, 1, 'div'), + elementDef(0, NodeFlags.None, null, null, 1, 'div'), anchorDef( - NodeFlags.EmbeddedViews, null !, null !, 0, null !, - embeddedViewDef([elementDef(NodeFlags.None, null !, null !, 0, 'span')])), + NodeFlags.EmbeddedViews, null, null, 0, null, + compViewDefFactory([elementDef(0, NodeFlags.None, null, null, 0, 'span')])), ]), parentContext); @@ -52,14 +35,13 @@ export function main() { it('should attach and detach embedded views', () => { const {view: parentView, rootNodes} = createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 2, 'div'), - anchorDef(NodeFlags.EmbeddedViews, null !, null !, 0, null !, embeddedViewDef([ - elementDef(NodeFlags.None, null !, null !, 0, 'span', [['name', 'child0']]) + elementDef(0, NodeFlags.None, null, null, 2, 'div'), + anchorDef(NodeFlags.EmbeddedViews, null, null, 0, null, compViewDefFactory([ + elementDef(0, NodeFlags.None, null, null, 0, 'span', [['name', 'child0']]) ])), - anchorDef( - NodeFlags.None, null !, null !, 0, null !, - embeddedViewDef( - [elementDef(NodeFlags.None, null !, null !, 0, 'span', [['name', 'child1']])])) + anchorDef(NodeFlags.None, null, null, 0, null, compViewDefFactory([elementDef( + 0, NodeFlags.None, null, null, 0, 'span', + [['name', 'child1']])])) ])); const viewContainerData = asElementData(parentView, 1); const rf = parentView.root.rendererFactory; @@ -86,14 +68,13 @@ export function main() { it('should move embedded views', () => { const {view: parentView, rootNodes} = createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 2, 'div'), - anchorDef(NodeFlags.EmbeddedViews, null !, null !, 0, null !, embeddedViewDef([ - elementDef(NodeFlags.None, null !, null !, 0, 'span', [['name', 'child0']]) + elementDef(0, NodeFlags.None, null, null, 2, 'div'), + anchorDef(NodeFlags.EmbeddedViews, null, null, 0, null, compViewDefFactory([ + elementDef(0, NodeFlags.None, null, null, 0, 'span', [['name', 'child0']]) ])), - anchorDef( - NodeFlags.None, null !, null !, 0, null !, - embeddedViewDef( - [elementDef(NodeFlags.None, null !, null !, 0, 'span', [['name', 'child1']])])) + anchorDef(NodeFlags.None, null, null, 0, null, compViewDefFactory([elementDef( + 0, NodeFlags.None, null, null, 0, 'span', + [['name', 'child1']])])) ])); const viewContainerData = asElementData(parentView, 1); @@ -115,10 +96,10 @@ export function main() { it('should include embedded views in root nodes', () => { const {view: parentView} = createAndGetRootNodes(compViewDef([ - anchorDef(NodeFlags.EmbeddedViews, null !, null !, 0, null !, embeddedViewDef([ - elementDef(NodeFlags.None, null !, null !, 0, 'span', [['name', 'child0']]) + anchorDef(NodeFlags.EmbeddedViews, null, null, 0, null, compViewDefFactory([ + elementDef(0, NodeFlags.None, null, null, 0, 'span', [['name', 'child0']]) ])), - elementDef(NodeFlags.None, null !, null !, 0, 'span', [['name', 'after']]) + elementDef(1, NodeFlags.None, null, null, 0, 'span', [['name', 'after']]) ])); const childView0 = createEmbeddedView(parentView, parentView.def.nodes[0]); @@ -138,12 +119,12 @@ export function main() { }); const {view: parentView, rootNodes} = createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 1, 'div'), + elementDef(0, NodeFlags.None, null, null, 1, 'div'), anchorDef( - NodeFlags.EmbeddedViews, null !, null !, 0, null !, - embeddedViewDef( + NodeFlags.EmbeddedViews, null, null, 0, null, + compViewDefFactory( [elementDef( - NodeFlags.None, null !, null !, 0, 'span', null !, + 0, NodeFlags.None, null, null, 0, 'span', null, [[BindingFlags.TypeElementAttribute, 'name', SecurityContext.NONE]])], update)) ])); @@ -175,10 +156,10 @@ export function main() { } const {view: parentView} = createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 1, 'div'), - anchorDef(NodeFlags.EmbeddedViews, null !, null !, 0, null !, embeddedViewDef([ - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - directiveDef(NodeFlags.OnDestroy, null !, 0, ChildProvider, []) + elementDef(0, NodeFlags.None, null, null, 1, 'div'), + anchorDef(NodeFlags.EmbeddedViews, null, null, 0, null, compViewDefFactory([ + elementDef(0, NodeFlags.None, null, null, 1, 'span'), + directiveDef(1, NodeFlags.OnDestroy, null, 0, ChildProvider, []) ])) ])); diff --git a/packages/core/test/view/helper.ts b/packages/core/test/view/helper.ts index 0f26894f6d..b9b10f59f3 100644 --- a/packages/core/test/view/helper.ts +++ b/packages/core/test/view/helper.ts @@ -6,8 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {Injector, NgModuleRef, RootRenderer, Sanitizer} from '@angular/core'; -import {ArgumentType, NodeCheckFn, NodeDef, RootData, Services, ViewData, ViewDefinition, initServicesIfNeeded} from '@angular/core/src/view/index'; +import {Injector, NgModuleRef} from '@angular/core'; +import {ArgumentType, NodeCheckFn, NodeDef, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewUpdateFn, initServicesIfNeeded, rootRenderNodes, viewDef} from '@angular/core/src/view/index'; import {TestBed} from '@angular/core/testing'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; @@ -41,6 +41,39 @@ export function createEmbeddedView(parent: ViewData, anchorDef: NodeDef, context return Services.createEmbeddedView(parent, anchorDef, anchorDef.element !.template !, context); } +export function compViewDef( + nodes: NodeDef[], updateDirectives?: null | ViewUpdateFn, updateRenderer?: null | ViewUpdateFn, + viewFlags: ViewFlags = ViewFlags.None): ViewDefinition { + const def = viewDef(viewFlags, nodes, updateDirectives, updateRenderer); + + def.nodes.forEach((node, index) => { + if (node.nodeIndex !== index) { + throw new Error('nodeIndex should be the same as the index of the node'); + } + + // This check should be removed when we start reordering nodes at runtime + if (node.checkIndex > -1 && node.checkIndex !== node.nodeIndex) { + throw new Error( + `nodeIndex and checkIndex should be the same, got ${node.nodeIndex} !== ${node.checkIndex}`); + } + }); + + return def; +} + +export function compViewDefFactory( + nodes: NodeDef[], updateDirectives?: null | ViewUpdateFn, updateRenderer?: null | ViewUpdateFn, + viewFlags: ViewFlags = ViewFlags.None): ViewDefinitionFactory { + return () => compViewDef(nodes, updateDirectives, updateRenderer, viewFlags); +} + +export function createAndGetRootNodes( + viewDef: ViewDefinition, ctx?: any): {rootNodes: any[], view: ViewData} { + const view = createRootView(viewDef, ctx); + const rootNodes = rootRenderNodes(view); + return {rootNodes, view}; +} + let removeNodes: Node[]; beforeEach(() => { removeNodes = []; }); diff --git a/packages/core/test/view/ng_content_spec.ts b/packages/core/test/view/ng_content_spec.ts index b65b24668f..954ee66e93 100644 --- a/packages/core/test/view/ng_content_spec.ts +++ b/packages/core/test/view/ng_content_spec.ts @@ -10,30 +10,21 @@ import {Injector, RenderComponentType, RootRenderer, Sanitizer, SecurityContext, import {DebugContext, NodeDef, NodeFlags, RootData, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, asElementData, asProviderData, asTextData, attachEmbeddedView, detachEmbeddedView, directiveDef, elementDef, ngContentDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; -import {createEmbeddedView, createRootView, isBrowser} from './helper'; +import {compViewDef, compViewDefFactory, createEmbeddedView, createRootView, isBrowser} from './helper'; export function main() { describe(`View NgContent`, () => { - function compViewDef( - nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn, - viewFlags: ViewFlags = ViewFlags.None): ViewDefinition { - return viewDef(viewFlags, nodes, updateDirectives, updateRenderer); - } - - function embeddedViewDef(nodes: NodeDef[], update?: ViewUpdateFn): ViewDefinitionFactory { - return () => viewDef(ViewFlags.None, nodes, update); - } - - function hostElDef(contentNodes: NodeDef[], viewNodes: NodeDef[]): NodeDef[] { + function hostElDef( + checkIndex: number, contentNodes: NodeDef[], viewNodes: NodeDef[]): NodeDef[] { class AComp {} const aCompViewDef = compViewDef(viewNodes); return [ elementDef( - NodeFlags.None, null !, null !, 1 + contentNodes.length, 'acomp', null !, null !, - null !, null !, () => aCompViewDef), - directiveDef(NodeFlags.Component, null !, 0, AComp, []), ...contentNodes + checkIndex, NodeFlags.None, null, null, 1 + contentNodes.length, 'acomp', null, null, + null, null, () => aCompViewDef), + directiveDef(checkIndex + 1, NodeFlags.Component, null, 0, AComp, []), ...contentNodes ]; } @@ -46,15 +37,15 @@ export function main() { it('should create ng-content nodes without parents', () => { const {view, rootNodes} = createAndGetRootNodes( - compViewDef(hostElDef([textDef(0, ['a'])], [ngContentDef(null !, 0)]))); + compViewDef(hostElDef(0, [textDef(2, 0, ['a'])], [ngContentDef(null, 0)]))); expect(getDOM().firstChild(rootNodes[0])).toBe(asTextData(view, 2).renderText); }); it('should create views with multiple root ng-content nodes', () => { const {view, rootNodes} = createAndGetRootNodes(compViewDef(hostElDef( - [textDef(0, ['a']), textDef(1, ['b'])], - [ngContentDef(null !, 0), ngContentDef(null !, 1)]))); + 0, [textDef(2, 0, ['a']), textDef(3, 1, ['b'])], + [ngContentDef(null, 0), ngContentDef(null, 1)]))); expect(getDOM().childNodes(rootNodes[0])[0]).toBe(asTextData(view, 2).renderText); expect(getDOM().childNodes(rootNodes[0])[1]).toBe(asTextData(view, 3).renderText); @@ -62,8 +53,8 @@ export function main() { it('should create ng-content nodes with parents', () => { const {view, rootNodes} = createAndGetRootNodes(compViewDef(hostElDef( - [textDef(0, ['a'])], - [elementDef(NodeFlags.None, null !, null !, 1, 'div'), ngContentDef(null !, 0)]))); + 0, [textDef(2, 0, ['a'])], + [elementDef(0, NodeFlags.None, null, null, 1, 'div'), ngContentDef(null, 0)]))); expect(getDOM().firstChild(getDOM().firstChild(rootNodes[0]))) .toBe(asTextData(view, 2).renderText); @@ -71,8 +62,8 @@ export function main() { it('should reproject ng-content nodes', () => { const {view, rootNodes} = createAndGetRootNodes(compViewDef( - hostElDef([textDef(0, ['a'])], hostElDef([ngContentDef(0, 0)], [ - elementDef(NodeFlags.None, null !, null !, 1, 'span'), ngContentDef(null !, 0) + hostElDef(0, [textDef(2, 0, ['a'])], hostElDef(0, [ngContentDef(0, 0)], [ + elementDef(0, NodeFlags.None, null, null, 1, 'span'), ngContentDef(null, 0) ])))); expect(getDOM().firstChild(getDOM().firstChild(getDOM().firstChild(rootNodes[0])))) .toBe(asTextData(view, 2).renderText); @@ -88,18 +79,18 @@ export function main() { const {view, rootNodes} = createAndGetRootNodes( compViewDef( - hostElDef( + hostElDef(0, [ anchorDef( - NodeFlags.EmbeddedViews, null !, 0, 1, null !, - embeddedViewDef([textDef(null !, ['a'])])), - directiveDef( - NodeFlags.None, null !, 0, CreateViewService, - [TemplateRef, ViewContainerRef]) + NodeFlags.EmbeddedViews, null, 0, 1, null, + compViewDefFactory([textDef(0, null, ['a'])])), + directiveDef(3, + NodeFlags.None, null, 0, CreateViewService, + [TemplateRef, ViewContainerRef]), ], [ - elementDef(NodeFlags.None, null !, null !, 1, 'div'), - ngContentDef(null !, 0) + elementDef(0, NodeFlags.None, null, null, 1, 'div'), + ngContentDef(null, 0), ]))); const anchor = asElementData(view, 2); @@ -111,14 +102,15 @@ export function main() { }); it('should include projected nodes when attaching / detaching embedded views', () => { - const {view, rootNodes} = createAndGetRootNodes(compViewDef(hostElDef([textDef(0, ['a'])], [ - elementDef(NodeFlags.None, null !, null !, 1, 'div'), - anchorDef(NodeFlags.EmbeddedViews, null !, 0, 0, null !, embeddedViewDef([ - ngContentDef(null !, 0), - // The anchor would be added by the compiler after the ngContent - anchorDef(NodeFlags.None, null !, null !, 0), - ])), - ]))); + const {view, rootNodes} = + createAndGetRootNodes(compViewDef(hostElDef(0, [textDef(2, 0, ['a'])], [ + elementDef(0, NodeFlags.None, null, null, 1, 'div'), + anchorDef(NodeFlags.EmbeddedViews, null, 0, 0, null, compViewDefFactory([ + ngContentDef(null, 0), + // The anchor would be added by the compiler after the ngContent + anchorDef(NodeFlags.None, null, null, 0), + ])), + ]))); const componentView = asElementData(view, 0).componentView; const rf = componentView.root.rendererFactory; @@ -139,7 +131,7 @@ export function main() { it('should use root projectable nodes', () => { const projectableNodes = [[document.createTextNode('a')], [document.createTextNode('b')]]; const view = createRootView( - compViewDef(hostElDef([], [ngContentDef(null !, 0), ngContentDef(null !, 1)])), {}, + compViewDef(hostElDef(0, [], [ngContentDef(null, 0), ngContentDef(null, 1)])), {}, projectableNodes); const rootNodes = rootRenderNodes(view); diff --git a/packages/core/test/view/provider_spec.ts b/packages/core/test/view/provider_spec.ts index 7732af73ac..f1941e687e 100644 --- a/packages/core/test/view/provider_spec.ts +++ b/packages/core/test/view/provider_spec.ts @@ -6,31 +6,16 @@ * found in the LICENSE file at https://angular.io/license */ -import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, ChangeDetectorRef, DoCheck, ElementRef, ErrorHandler, EventEmitter, Injector, OnChanges, OnDestroy, OnInit, RenderComponentType, Renderer, Renderer2, RootRenderer, Sanitizer, SecurityContext, SimpleChange, TemplateRef, ViewContainerRef, ViewEncapsulation, WrappedValue, getDebugNode} from '@angular/core'; +import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, ChangeDetectorRef, DoCheck, ElementRef, ErrorHandler, EventEmitter, Injector, OnChanges, OnDestroy, OnInit, Renderer, Renderer2, SimpleChange, TemplateRef, ViewContainerRef,} from '@angular/core'; import {getDebugContext} from '@angular/core/src/errors'; -import {ArgumentType, BindingFlags, DebugContext, DepFlags, NodeDef, NodeFlags, RootData, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, asElementData, asProviderData, directiveDef, elementDef, providerDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index'; -import {TestBed, inject, withModule} from '@angular/core/testing'; +import {ArgumentType, DepFlags, NodeFlags, Services, anchorDef, asElementData, directiveDef, elementDef, providerDef, textDef} from '@angular/core/src/view/index'; +import {TestBed, withModule} from '@angular/core/testing'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; -import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, isBrowser} from './helper'; +import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetRootNodes, compViewDef, compViewDefFactory} from './helper'; export function main() { describe(`View Providers`, () => { - function compViewDef( - nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn, - viewFlags: ViewFlags = ViewFlags.None): ViewDefinition { - return viewDef(viewFlags, nodes, updateDirectives, updateRenderer); - } - - function embeddedViewDef(nodes: NodeDef[], update?: ViewUpdateFn): ViewDefinitionFactory { - return () => viewDef(ViewFlags.None, nodes, update); - } - - function createAndGetRootNodes(viewDef: ViewDefinition): {rootNodes: any[], view: ViewData} { - const view = createRootView(viewDef, {}); - const rootNodes = rootRenderNodes(view); - return {rootNodes, view}; - } describe('create', () => { let instance: SomeService; @@ -43,8 +28,8 @@ export function main() { it('should create providers eagerly', () => { createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - directiveDef(NodeFlags.None, null !, 0, SomeService, []) + elementDef(0, NodeFlags.None, null, null, 1, 'span'), + directiveDef(1, NodeFlags.None, null, 0, SomeService, []) ])); expect(instance instanceof SomeService).toBe(true); @@ -57,11 +42,11 @@ export function main() { } createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 2, 'span'), + elementDef(0, NodeFlags.None, null, null, 2, 'span'), providerDef( - NodeFlags.TypeClassProvider | NodeFlags.LazyProvider, null !, LazyService, - LazyService, []), - directiveDef(NodeFlags.None, null !, 0, SomeService, [Injector]) + NodeFlags.TypeClassProvider | NodeFlags.LazyProvider, null, LazyService, LazyService, + []), + directiveDef(2, NodeFlags.None, null, 0, SomeService, [Injector]) ])); expect(lazy).toBeUndefined(); @@ -71,9 +56,9 @@ export function main() { it('should create value providers', () => { createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 2, 'span'), - providerDef(NodeFlags.TypeValueProvider, null !, 'someToken', 'someValue', []), - directiveDef(NodeFlags.None, null !, 0, SomeService, ['someToken']), + elementDef(0, NodeFlags.None, null, null, 2, 'span'), + providerDef(NodeFlags.TypeValueProvider, null, 'someToken', 'someValue', []), + directiveDef(2, NodeFlags.None, null, 0, SomeService, ['someToken']), ])); expect(instance.dep).toBe('someValue'); @@ -83,9 +68,9 @@ export function main() { function someFactory() { return 'someValue'; } createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 2, 'span'), - providerDef(NodeFlags.TypeFactoryProvider, null !, 'someToken', someFactory, []), - directiveDef(NodeFlags.None, null !, 0, SomeService, ['someToken']), + elementDef(0, NodeFlags.None, null, null, 2, 'span'), + providerDef(NodeFlags.TypeFactoryProvider, null, 'someToken', someFactory, []), + directiveDef(2, NodeFlags.None, null, 0, SomeService, ['someToken']), ])); expect(instance.dep).toBe('someValue'); @@ -93,12 +78,11 @@ export function main() { it('should create useExisting providers', () => { createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 3, 'span'), - providerDef(NodeFlags.TypeValueProvider, null !, 'someExistingToken', 'someValue', []), + elementDef(0, NodeFlags.None, null, null, 3, 'span'), + providerDef(NodeFlags.TypeValueProvider, null, 'someExistingToken', 'someValue', []), providerDef( - NodeFlags.TypeUseExistingProvider, null !, 'someToken', null !, - ['someExistingToken']), - directiveDef(NodeFlags.None, null !, 0, SomeService, ['someToken']), + NodeFlags.TypeUseExistingProvider, null, 'someToken', null, ['someExistingToken']), + directiveDef(3, NodeFlags.None, null, 0, SomeService, ['someToken']), ])); expect(instance.dep).toBe('someValue'); @@ -114,9 +98,9 @@ export function main() { createRootView( compViewDef([ elementDef( - NodeFlags.None, null !, null !, 1, 'div', null !, null !, null !, null !, - () => compViewDef([textDef(null !, ['a'])])), - directiveDef(NodeFlags.Component, null !, 0, SomeService, []) + 0, NodeFlags.None, null, null, 1, 'div', null, null, null, null, + () => compViewDef([textDef(0, null, ['a'])])), + directiveDef(1, NodeFlags.Component, null, 0, SomeService, []) ]), TestBed.get(Injector), [], getDOM().createElement('div')); } catch (e) { @@ -134,9 +118,9 @@ export function main() { it('should inject deps from the same element', () => { createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 2, 'span'), - directiveDef(NodeFlags.None, null !, 0, Dep, []), - directiveDef(NodeFlags.None, null !, 0, SomeService, [Dep]) + elementDef(0, NodeFlags.None, null, null, 2, 'span'), + directiveDef(1, NodeFlags.None, null, 0, Dep, []), + directiveDef(2, NodeFlags.None, null, 0, SomeService, [Dep]) ])); expect(instance.dep instanceof Dep).toBeTruthy(); @@ -144,34 +128,38 @@ export function main() { it('should inject deps from a parent element', () => { createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 3, 'span'), - directiveDef(NodeFlags.None, null !, 0, Dep, []), - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - directiveDef(NodeFlags.None, null !, 0, SomeService, [Dep]) + elementDef(0, NodeFlags.None, null, null, 3, 'span'), + directiveDef(1, NodeFlags.None, null, 0, Dep, []), + elementDef(2, NodeFlags.None, null, null, 1, 'span'), + directiveDef(3, NodeFlags.None, null, 0, SomeService, [Dep]) ])); expect(instance.dep instanceof Dep).toBeTruthy(); }); it('should not inject deps from sibling root elements', () => { - const nodes = [ - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - directiveDef(NodeFlags.None, null !, 0, Dep, []), - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - directiveDef(NodeFlags.None, null !, 0, SomeService, [Dep]) + const rootElNodes = [ + elementDef(0, NodeFlags.None, null, null, 1, 'span'), + directiveDef(1, NodeFlags.None, null, 0, Dep, []), + elementDef(2, NodeFlags.None, null, null, 1, 'span'), + directiveDef(3, NodeFlags.None, null, 0, SomeService, [Dep]), ]; - // root elements - expect(() => createAndGetRootNodes(compViewDef(nodes))) + expect(() => createAndGetRootNodes(compViewDef(rootElNodes))) .toThrowError( 'StaticInjectorError[Dep]: \n' + ' StaticInjectorError[Dep]: \n' + ' NullInjectorError: No provider for Dep!'); - // non root elements - expect( - () => createAndGetRootNodes(compViewDef( - [elementDef(NodeFlags.None, null !, null !, 4, 'span')].concat(nodes)))) + const nonRootElNodes = [ + elementDef(0, NodeFlags.None, null, null, 4, 'span'), + elementDef(1, NodeFlags.None, null, null, 1, 'span'), + directiveDef(2, NodeFlags.None, null, 0, Dep, []), + elementDef(3, NodeFlags.None, null, null, 1, 'span'), + directiveDef(4, NodeFlags.None, null, 0, SomeService, [Dep]), + ]; + + expect(() => createAndGetRootNodes(compViewDef(nonRootElNodes))) .toThrowError( 'StaticInjectorError[Dep]: \n' + ' StaticInjectorError[Dep]: \n' + @@ -181,12 +169,12 @@ export function main() { it('should inject from a parent element in a parent view', () => { createAndGetRootNodes(compViewDef([ elementDef( - NodeFlags.None, null !, null !, 1, 'div', null !, null !, null !, null !, + 0, NodeFlags.None, null, null, 1, 'div', null, null, null, null, () => compViewDef([ - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - directiveDef(NodeFlags.None, null !, 0, SomeService, [Dep]) + elementDef(0, NodeFlags.None, null, null, 1, 'span'), + directiveDef(1, NodeFlags.None, null, 0, SomeService, [Dep]) ])), - directiveDef(NodeFlags.Component, null !, 0, Dep, []), + directiveDef(1, NodeFlags.Component, null, 0, Dep, []), ])); expect(instance.dep instanceof Dep).toBeTruthy(); @@ -194,8 +182,8 @@ export function main() { it('should throw for missing dependencies', () => { expect(() => createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - directiveDef(NodeFlags.None, null !, 0, SomeService, ['nonExistingDep']) + elementDef(0, NodeFlags.None, null, null, 1, 'span'), + directiveDef(1, NodeFlags.None, null, 0, SomeService, ['nonExistingDep']) ]))) .toThrowError( 'StaticInjectorError[nonExistingDep]: \n' + @@ -205,21 +193,22 @@ export function main() { it('should use null for optional missing dependencies', () => { createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 1, 'span'), + elementDef(0, NodeFlags.None, null, null, 1, 'span'), directiveDef( - NodeFlags.None, null !, 0, SomeService, [[DepFlags.Optional, 'nonExistingDep']]) + 1, NodeFlags.None, null, 0, SomeService, + [[DepFlags.Optional, 'nonExistingDep']]) ])); expect(instance.dep).toBe(null); }); it('should skip the current element when using SkipSelf', () => { createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 4, 'span'), - providerDef(NodeFlags.TypeValueProvider, null !, 'someToken', 'someParentValue', []), - elementDef(NodeFlags.None, null !, null !, 2, 'span'), - providerDef(NodeFlags.TypeValueProvider, null !, 'someToken', 'someValue', []), + elementDef(0, NodeFlags.None, null, null, 4, 'span'), + providerDef(NodeFlags.TypeValueProvider, null, 'someToken', 'someParentValue', []), + elementDef(2, NodeFlags.None, null, null, 2, 'span'), + providerDef(NodeFlags.TypeValueProvider, null, 'someToken', 'someValue', []), directiveDef( - NodeFlags.None, null !, 0, SomeService, [[DepFlags.SkipSelf, 'someToken']]) + 4, NodeFlags.None, null, 0, SomeService, [[DepFlags.SkipSelf, 'someToken']]) ])); expect(instance.dep).toBe('someParentValue'); }); @@ -227,8 +216,8 @@ export function main() { it('should ask the root injector', withModule({providers: [{provide: 'rootDep', useValue: 'rootValue'}]}, () => { createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - directiveDef(NodeFlags.None, null !, 0, SomeService, ['rootDep']) + elementDef(0, NodeFlags.None, null, null, 1, 'span'), + directiveDef(1, NodeFlags.None, null, 0, SomeService, ['rootDep']) ])); expect(instance.dep).toBe('rootValue'); @@ -237,8 +226,8 @@ export function main() { describe('builtin tokens', () => { it('should inject ViewContainerRef', () => { createAndGetRootNodes(compViewDef([ - anchorDef(NodeFlags.EmbeddedViews, null !, null !, 1), - directiveDef(NodeFlags.None, null !, 0, SomeService, [ViewContainerRef]) + anchorDef(NodeFlags.EmbeddedViews, null, null, 1), + directiveDef(1, NodeFlags.None, null, 0, SomeService, [ViewContainerRef]), ])); expect(instance.dep.createEmbeddedView).toBeTruthy(); @@ -246,10 +235,9 @@ export function main() { it('should inject TemplateRef', () => { createAndGetRootNodes(compViewDef([ - anchorDef( - NodeFlags.None, null !, null !, 1, null !, - embeddedViewDef([anchorDef(NodeFlags.None, null !, null !, 0)])), - directiveDef(NodeFlags.None, null !, 0, SomeService, [TemplateRef]) + anchorDef(NodeFlags.None, null, null, 1, null, compViewDefFactory([anchorDef( + NodeFlags.None, null, null, 0)])), + directiveDef(1, NodeFlags.None, null, 0, SomeService, [TemplateRef]), ])); expect(instance.dep.createEmbeddedView).toBeTruthy(); @@ -257,8 +245,8 @@ export function main() { it('should inject ElementRef', () => { const {view} = createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - directiveDef(NodeFlags.None, null !, 0, SomeService, [ElementRef]) + elementDef(0, NodeFlags.None, null, null, 1, 'span'), + directiveDef(1, NodeFlags.None, null, 0, SomeService, [ElementRef]), ])); expect(instance.dep.nativeElement).toBe(asElementData(view, 0).renderElement); @@ -266,8 +254,8 @@ export function main() { it('should inject Injector', () => { const {view} = createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - directiveDef(NodeFlags.None, null !, 0, SomeService, [Injector]) + elementDef(0, NodeFlags.None, null, null, 1, 'span'), + directiveDef(1, NodeFlags.None, null, 0, SomeService, [Injector]), ])); expect(instance.dep.get(SomeService)).toBe(instance); @@ -275,8 +263,8 @@ export function main() { it('should inject ChangeDetectorRef for non component providers', () => { const {view} = createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - directiveDef(NodeFlags.None, null !, 0, SomeService, [ChangeDetectorRef]) + elementDef(0, NodeFlags.None, null, null, 1, 'span'), + directiveDef(1, NodeFlags.None, null, 0, SomeService, [ChangeDetectorRef]) ])); expect(instance.dep._view).toBe(view); @@ -285,11 +273,11 @@ export function main() { it('should inject ChangeDetectorRef for component providers', () => { const {view, rootNodes} = createAndGetRootNodes(compViewDef([ elementDef( - NodeFlags.None, null !, null !, 1, 'div', null !, null !, null !, null !, + 0, NodeFlags.None, null, null, 1, 'div', null, null, null, null, () => compViewDef([ - elementDef(NodeFlags.None, null !, null !, 0, 'span'), + elementDef(0, NodeFlags.None, null, null, 0, 'span'), ])), - directiveDef(NodeFlags.Component, null !, 0, SomeService, [ChangeDetectorRef]), + directiveDef(1, NodeFlags.Component, null, 0, SomeService, [ChangeDetectorRef]), ])); const compView = asElementData(view, 0).componentView; @@ -299,9 +287,9 @@ export function main() { it('should inject RendererV1', () => { createAndGetRootNodes(compViewDef([ elementDef( - NodeFlags.None, null !, null !, 1, 'span', null !, null !, null !, null !, - () => compViewDef([anchorDef(NodeFlags.None, null !, null !, 0)])), - directiveDef(NodeFlags.Component, null !, 0, SomeService, [Renderer]) + 0, NodeFlags.None, null, null, 1, 'span', null, null, null, null, + () => compViewDef([anchorDef(NodeFlags.None, null, null, 0)])), + directiveDef(1, NodeFlags.Component, null, 0, SomeService, [Renderer]) ])); expect(instance.dep.createElement).toBeTruthy(); @@ -310,9 +298,9 @@ export function main() { it('should inject Renderer2', () => { createAndGetRootNodes(compViewDef([ elementDef( - NodeFlags.None, null !, null !, 1, 'span', null !, null !, null !, null !, - () => compViewDef([anchorDef(NodeFlags.None, null !, null !, 0)])), - directiveDef(NodeFlags.Component, null !, 0, SomeService, [Renderer2]) + 0, NodeFlags.None, null, null, 1, 'span', null, null, null, null, + () => compViewDef([anchorDef(NodeFlags.None, null, null, 0)])), + directiveDef(1, NodeFlags.Component, null, 0, SomeService, [Renderer2]) ])); expect(instance.dep.createElement).toBeTruthy(); @@ -337,9 +325,9 @@ export function main() { const {view, rootNodes} = createAndGetRootNodes(compViewDef( [ - elementDef(NodeFlags.None, null !, null !, 1, 'span'), + elementDef(0, NodeFlags.None, null, null, 1, 'span'), directiveDef( - NodeFlags.None, null !, 0, SomeService, [], {a: [0, 'a'], b: [1, 'b']}) + 1, NodeFlags.None, null, 0, SomeService, [], {a: [0, 'a'], b: [1, 'b']}) ], (check, view) => { checkNodeInlineOrDynamic(check, view, 1, inlineDynamic, ['v1', 'v2']); @@ -373,13 +361,11 @@ export function main() { } const handleEvent = jasmine.createSpy('handleEvent'); - const subscribe = spyOn(emitter, 'subscribe').and.callThrough(); const {view, rootNodes} = createAndGetRootNodes(compViewDef([ - elementDef( - NodeFlags.None, null !, null !, 1, 'span', null !, null !, null !, handleEvent), + elementDef(0, NodeFlags.None, null, null, 1, 'span', null, null, null, handleEvent), directiveDef( - NodeFlags.None, null !, 0, SomeService, [], null !, {emitter: 'someEventName'}) + 1, NodeFlags.None, null, 0, SomeService, [], null, {emitter: 'someEventName'}) ])); emitter.emit('someEventInstance'); @@ -399,10 +385,10 @@ export function main() { const {view, rootNodes} = createAndGetRootNodes(compViewDef([ elementDef( - NodeFlags.None, null !, null !, 1, 'span', null !, null !, null !, + 0, NodeFlags.None, null, null, 1, 'span', null, null, null, () => { throw new Error('Test'); }), directiveDef( - NodeFlags.None, null !, 0, SomeService, [], null !, {emitter: 'someEventName'}) + 1, NodeFlags.None, null, 0, SomeService, [], null, {emitter: 'someEventName'}) ])); emitter.emit('someEventInstance'); @@ -440,10 +426,10 @@ export function main() { NodeFlags.AfterViewChecked | NodeFlags.OnDestroy; const {view, rootNodes} = createAndGetRootNodes(compViewDef( [ - elementDef(NodeFlags.None, null !, null !, 3, 'span'), - directiveDef(allFlags, null !, 0, SomeService, [], {a: [0, 'a']}), - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - directiveDef(allFlags, null !, 0, SomeService, [], {a: [0, 'a']}) + elementDef(0, NodeFlags.None, null, null, 3, 'span'), + directiveDef(1, allFlags, null, 0, SomeService, [], {a: [0, 'a']}), + elementDef(2, NodeFlags.None, null, null, 1, 'span'), + directiveDef(3, allFlags, null, 0, SomeService, [], {a: [0, 'a']}) ], (check, view) => { check(view, 1, ArgumentType.Inline, 'someValue'); @@ -499,9 +485,9 @@ export function main() { const {view, rootNodes} = createAndGetRootNodes(compViewDef( [ - elementDef(NodeFlags.None, null !, null !, 1, 'span'), + elementDef(0, NodeFlags.None, null, null, 1, 'span'), directiveDef( - NodeFlags.OnChanges, null !, 0, SomeService, [], {a: [0, 'nonMinifiedA']}) + 1, NodeFlags.OnChanges, null, 0, SomeService, [], {a: [0, 'nonMinifiedA']}) ], (check, view) => { check(view, 1, ArgumentType.Inline, currValue); })); @@ -520,8 +506,8 @@ export function main() { } const {view, rootNodes} = createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - directiveDef(NodeFlags.AfterContentChecked, null !, 0, SomeService, [], {a: [0, 'a']}), + elementDef(0, NodeFlags.None, null, null, 1, 'span'), + directiveDef(1, NodeFlags.AfterContentChecked, null, 0, SomeService, [], {a: [0, 'a']}), ])); let err: any; @@ -543,8 +529,8 @@ export function main() { } const {view, rootNodes} = createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - directiveDef(NodeFlags.OnDestroy, null !, 0, SomeService, [], {a: [0, 'a']}), + elementDef(0, NodeFlags.None, null, null, 1, 'span'), + directiveDef(1, NodeFlags.OnDestroy, null, 0, SomeService, [], {a: [0, 'a']}), ])); let err: any; diff --git a/packages/core/test/view/pure_expression_spec.ts b/packages/core/test/view/pure_expression_spec.ts index 997a91c3cc..70bcc3628b 100644 --- a/packages/core/test/view/pure_expression_spec.ts +++ b/packages/core/test/view/pure_expression_spec.ts @@ -7,23 +7,12 @@ */ import {PipeTransform} from '@angular/core'; -import {NodeDef, NodeFlags, Services, ViewData, ViewDefinition, ViewFlags, ViewUpdateFn, asProviderData, directiveDef, elementDef, nodeValue, pipeDef, pureArrayDef, pureObjectDef, purePipeDef, rootRenderNodes, viewDef} from '@angular/core/src/view/index'; +import {NodeFlags, Services, asProviderData, directiveDef, elementDef, nodeValue, pipeDef, pureArrayDef, pureObjectDef, purePipeDef} from '@angular/core/src/view/index'; -import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView} from './helper'; +import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, compViewDef, createAndGetRootNodes} from './helper'; export function main() { describe(`View Pure Expressions`, () => { - function compViewDef( - nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn, - viewFlags: ViewFlags = ViewFlags.None): ViewDefinition { - return viewDef(viewFlags, nodes, updateDirectives, updateRenderer); - } - - function createAndGetRootNodes(viewDef: ViewDefinition): {rootNodes: any[], view: ViewData} { - const view = createRootView(viewDef); - const rootNodes = rootRenderNodes(view); - return {rootNodes, view}; - } class Service { data: any; @@ -37,9 +26,9 @@ export function main() { const {view, rootNodes} = createAndGetRootNodes(compViewDef( [ - elementDef(NodeFlags.None, null !, null !, 2, 'span'), - pureArrayDef(2), - directiveDef(NodeFlags.None, null !, 0, Service, [], {data: [0, 'data']}), + elementDef(0, NodeFlags.None, null, null, 2, 'span'), + pureArrayDef(1, 2), + directiveDef(2, NodeFlags.None, null, 0, Service, [], {data: [0, 'data']}), ], (check, view) => { const pureValue = checkNodeInlineOrDynamic(check, view, 1, inlineDynamic, values); @@ -75,8 +64,9 @@ export function main() { const {view, rootNodes} = createAndGetRootNodes(compViewDef( [ - elementDef(NodeFlags.None, null !, null !, 2, 'span'), pureObjectDef({a: 0, b: 1}), - directiveDef(NodeFlags.None, null !, 0, Service, [], {data: [0, 'data']}) + elementDef(0, NodeFlags.None, null, null, 2, 'span'), + pureObjectDef(1, {a: 0, b: 1}), + directiveDef(2, NodeFlags.None, null, 0, Service, [], {data: [0, 'data']}) ], (check, view) => { const pureValue = checkNodeInlineOrDynamic(check, view, 1, inlineDynamic, values); @@ -115,10 +105,10 @@ export function main() { const {view, rootNodes} = createAndGetRootNodes(compViewDef( [ - elementDef(NodeFlags.None, null !, null !, 3, 'span'), + elementDef(0, NodeFlags.None, null !, null !, 3, 'span'), pipeDef(NodeFlags.None, SomePipe, []), - purePipeDef(2), - directiveDef(NodeFlags.None, null !, 0, Service, [], {data: [0, 'data']}), + purePipeDef(2, 2), + directiveDef(3, NodeFlags.None, null, 0, Service, [], {data: [0, 'data']}), ], (check, view) => { const pureValue = checkNodeInlineOrDynamic( diff --git a/packages/core/test/view/query_spec.ts b/packages/core/test/view/query_spec.ts index 4a5db92503..8e01e713cf 100644 --- a/packages/core/test/view/query_spec.ts +++ b/packages/core/test/view/query_spec.ts @@ -6,32 +6,14 @@ * found in the LICENSE file at https://angular.io/license */ -import {ElementRef, Injector, QueryList, RenderComponentType, RootRenderer, Sanitizer, SecurityContext, TemplateRef, ViewContainerRef, ViewEncapsulation, getDebugNode} from '@angular/core'; +import {ElementRef, QueryList, TemplateRef, ViewContainerRef} from '@angular/core'; import {getDebugContext} from '@angular/core/src/errors'; -import {BindingFlags, DebugContext, NodeDef, NodeFlags, QueryBindingType, QueryValueType, RootData, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, asElementData, asProviderData, attachEmbeddedView, detachEmbeddedView, directiveDef, elementDef, queryDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index'; -import {inject} from '@angular/core/testing'; -import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; +import {NodeDef, NodeFlags, QueryBindingType, QueryValueType, Services, anchorDef, asElementData, asProviderData, attachEmbeddedView, detachEmbeddedView, directiveDef, elementDef, queryDef} from '@angular/core/src/view/index'; -import {createEmbeddedView, createRootView} from './helper'; +import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedView} from './helper'; export function main() { describe(`Query Views`, () => { - function compViewDef( - nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn, - viewFlags: ViewFlags = ViewFlags.None): ViewDefinition { - return viewDef(viewFlags, nodes, updateDirectives, updateRenderer); - } - - function embeddedViewDef(nodes: NodeDef[], update?: ViewUpdateFn): ViewDefinitionFactory { - return () => viewDef(ViewFlags.None, nodes, update); - } - - function createAndGetRootNodes( - viewDef: ViewDefinition, context: any = null): {rootNodes: any[], view: ViewData} { - const view = createRootView(viewDef, context); - const rootNodes = rootRenderNodes(view); - return {rootNodes, view}; - } const someQueryId = 1; @@ -41,43 +23,50 @@ export function main() { a: QueryList; } - function contentQueryProviders() { + function contentQueryProviders(checkIndex: number) { return [ - directiveDef(NodeFlags.None, null !, 1, QueryService, []), + directiveDef(checkIndex, NodeFlags.None, null, 1, QueryService, []), queryDef( NodeFlags.TypeContentQuery | NodeFlags.DynamicQuery, someQueryId, {'a': QueryBindingType.All}) ]; } - function compViewQueryProviders(extraChildCount: number, nodes: NodeDef[]) { + const cQPLength = contentQueryProviders(0).length; + + // nodes first checkIndex should be 1 (to account for the `queryDef` + function compViewQueryProviders(checkIndex: number, extraChildCount: number, nodes: NodeDef[]) { return [ elementDef( - NodeFlags.None, null !, null !, 1 + extraChildCount, 'div', null !, null !, null !, - null !, () => compViewDef([ - queryDef( - NodeFlags.TypeViewQuery | NodeFlags.DynamicQuery, someQueryId, - {'a': QueryBindingType.All}), - ...nodes - ])), - directiveDef(NodeFlags.Component, null !, 0, QueryService, [], null !, null !, ), + checkIndex, NodeFlags.None, null, null, 1 + extraChildCount, 'div', null, null, null, + null, () => compViewDef([ + queryDef( + NodeFlags.TypeViewQuery | NodeFlags.DynamicQuery, someQueryId, + {'a': QueryBindingType.All}), + ...nodes + ])), + directiveDef( + checkIndex + 1, NodeFlags.Component, null !, 0, QueryService, [], null !, null !, ), ]; } - function aServiceProvider() { + const cVQLength = compViewQueryProviders(0, 0, []).length; + + + function aServiceProvider(checkIndex: number) { return directiveDef( - NodeFlags.None, [[someQueryId, QueryValueType.Provider]], 0, AService, []); + checkIndex, NodeFlags.None, [[someQueryId, QueryValueType.Provider]], 0, AService, []); } describe('content queries', () => { it('should query providers on the same element and child elements', () => { const {view} = createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 5, 'div'), - ...contentQueryProviders(), - aServiceProvider(), - elementDef(NodeFlags.None, null !, null !, 1, 'div'), - aServiceProvider(), + elementDef(0, NodeFlags.None, null, null, 5, 'div'), + ...contentQueryProviders(1), + aServiceProvider(1 + cQPLength), + elementDef(2 + cQPLength, NodeFlags.None, null, null, 1, 'div'), + aServiceProvider(3 + cQPLength), ])); const qs: QueryService = asProviderData(view, 1).instance; @@ -92,13 +81,14 @@ export function main() { }); it('should not query providers on sibling or parent elements', () => { + const {view} = createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 6, 'div'), - aServiceProvider(), - elementDef(NodeFlags.None, null !, null !, 2, 'div'), - ...contentQueryProviders(), - elementDef(NodeFlags.None, null !, null !, 1, 'div'), - aServiceProvider(), + elementDef(0, NodeFlags.None, null, null, 6, 'div'), + aServiceProvider(1), + elementDef(2, NodeFlags.None, null, null, 2, 'div'), + ...contentQueryProviders(3), + elementDef(3 + cQPLength, NodeFlags.None, null, null, 1, 'div'), + aServiceProvider(4 + cQPLength), ])); Services.checkAndUpdateView(view); @@ -112,10 +102,10 @@ export function main() { it('should query providers in the view', () => { const {view} = createAndGetRootNodes(compViewDef([ ...compViewQueryProviders( - 0, + 0, 0, [ - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - aServiceProvider(), + elementDef(1, NodeFlags.None, null, null, 1, 'span'), + aServiceProvider(2), ]), ])); @@ -129,12 +119,8 @@ export function main() { it('should not query providers on the host element', () => { const {view} = createAndGetRootNodes(compViewDef([ - ...compViewQueryProviders( - 1, - [ - elementDef(NodeFlags.None, null !, null !, 0, 'span'), - ]), - aServiceProvider(), + ...compViewQueryProviders(0, 1, [elementDef(1, NodeFlags.None, null, null, 0, 'span')]), + aServiceProvider(cVQLength), ])); Services.checkAndUpdateView(view); @@ -146,13 +132,13 @@ export function main() { describe('embedded views', () => { it('should query providers in embedded views', () => { const {view} = createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 5, 'div'), - ...contentQueryProviders(), - anchorDef(NodeFlags.EmbeddedViews, null !, null !, 2, null !, embeddedViewDef([ - elementDef(NodeFlags.None, null !, null !, 1, 'div'), - aServiceProvider(), + elementDef(0, NodeFlags.None, null, null, 5, 'div'), + ...contentQueryProviders(1), + anchorDef(NodeFlags.EmbeddedViews, null, null, 2, null, compViewDefFactory([ + elementDef(0, NodeFlags.None, null, null, 1, 'div'), + aServiceProvider(1), ])), - ...contentQueryProviders(), + ...contentQueryProviders(2 + cQPLength), ])); const childView = createEmbeddedView(view, view.def.nodes[3]); @@ -172,15 +158,15 @@ export function main() { it('should query providers in embedded views only at the template declaration', () => { const {view} = createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 3, 'div'), - ...contentQueryProviders(), - anchorDef(NodeFlags.EmbeddedViews, null !, null !, 0, null !, embeddedViewDef([ - elementDef(NodeFlags.None, null !, null !, 1, 'div'), - aServiceProvider(), + elementDef(0, NodeFlags.None, null, null, 3, 'div'), + ...contentQueryProviders(1), + anchorDef(NodeFlags.EmbeddedViews, null, null, 0, null, compViewDefFactory([ + elementDef(0, NodeFlags.None, null, null, 1, 'div'), + aServiceProvider(1), ])), - elementDef(NodeFlags.None, null !, null !, 3, 'div'), - ...contentQueryProviders(), - anchorDef(NodeFlags.EmbeddedViews, null !, null !, 0), + elementDef(2 + cQPLength, NodeFlags.None, null, null, 3, 'div'), + ...contentQueryProviders(3 + cQPLength), + anchorDef(NodeFlags.EmbeddedViews, null, null, 0), ])); const childView = createEmbeddedView(view, view.def.nodes[3]); @@ -201,11 +187,11 @@ export function main() { it('should update content queries if embedded views are added or removed', () => { const {view} = createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 3, 'div'), - ...contentQueryProviders(), - anchorDef(NodeFlags.EmbeddedViews, null !, null !, 0, null !, embeddedViewDef([ - elementDef(NodeFlags.None, null !, null !, 1, 'div'), - aServiceProvider(), + elementDef(0, NodeFlags.None, null, null, 3, 'div'), + ...contentQueryProviders(1), + anchorDef(NodeFlags.EmbeddedViews, null, null, 0, null, compViewDefFactory([ + elementDef(0, NodeFlags.None, null, null, 1, 'div'), + aServiceProvider(1), ])), ])); @@ -230,11 +216,11 @@ export function main() { it('should update view queries if embedded views are added or removed', () => { const {view} = createAndGetRootNodes(compViewDef([ ...compViewQueryProviders( - 0, + 0, 0, [ - anchorDef(NodeFlags.EmbeddedViews, null !, null !, 0, null !, embeddedViewDef([ - elementDef(NodeFlags.None, null !, null !, 1, 'div'), - aServiceProvider(), + anchorDef(NodeFlags.EmbeddedViews, null, null, 0, null, compViewDefFactory([ + elementDef(0, NodeFlags.None, null, null, 1, 'div'), + aServiceProvider(1), ])), ]), ])); @@ -265,13 +251,13 @@ export function main() { } const {view} = createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 4, 'div'), - directiveDef(NodeFlags.None, null !, 1, QueryService, []), + elementDef(0, NodeFlags.None, null, null, 4, 'div'), + directiveDef(1, NodeFlags.None, null, 1, QueryService, []), queryDef( NodeFlags.TypeContentQuery | NodeFlags.DynamicQuery, someQueryId, {'a': QueryBindingType.All}), - aServiceProvider(), - aServiceProvider(), + aServiceProvider(3), + aServiceProvider(4), ])); Services.checkAndUpdateView(view); @@ -290,13 +276,13 @@ export function main() { } const {view} = createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 4, 'div'), - directiveDef(NodeFlags.None, null !, 1, QueryService, []), + elementDef(0, NodeFlags.None, null, null, 4, 'div'), + directiveDef(1, NodeFlags.None, null, 1, QueryService, []), queryDef( NodeFlags.TypeContentQuery | NodeFlags.DynamicQuery, someQueryId, {'a': QueryBindingType.First}), - aServiceProvider(), - aServiceProvider(), + aServiceProvider(3), + aServiceProvider(4), ])); Services.checkAndUpdateView(view); @@ -313,8 +299,8 @@ export function main() { } const {view} = createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, [[someQueryId, QueryValueType.ElementRef]], null !, 2, 'div'), - directiveDef(NodeFlags.None, null !, 1, QueryService, []), + elementDef(0, NodeFlags.None, [[someQueryId, QueryValueType.ElementRef]], null, 2, 'div'), + directiveDef(1, NodeFlags.None, null, 1, QueryService, []), queryDef( NodeFlags.TypeContentQuery | NodeFlags.DynamicQuery, someQueryId, {'a': QueryBindingType.First}), @@ -333,9 +319,9 @@ export function main() { const {view} = createAndGetRootNodes(compViewDef([ anchorDef( - NodeFlags.None, [[someQueryId, QueryValueType.TemplateRef]], null !, 2, null !, - embeddedViewDef([anchorDef(NodeFlags.None, null !, null !, 0)])), - directiveDef(NodeFlags.None, null !, 1, QueryService, []), + NodeFlags.None, [[someQueryId, QueryValueType.TemplateRef]], null, 2, null, + compViewDefFactory([anchorDef(NodeFlags.None, null, null, 0)])), + directiveDef(1, NodeFlags.None, null, 1, QueryService, []), queryDef( NodeFlags.TypeContentQuery | NodeFlags.DynamicQuery, someQueryId, {'a': QueryBindingType.First}), @@ -354,8 +340,8 @@ export function main() { const {view} = createAndGetRootNodes(compViewDef([ anchorDef( - NodeFlags.EmbeddedViews, [[someQueryId, QueryValueType.ViewContainerRef]], null !, 2), - directiveDef(NodeFlags.None, null !, 1, QueryService, []), + NodeFlags.EmbeddedViews, [[someQueryId, QueryValueType.ViewContainerRef]], null, 2), + directiveDef(1, NodeFlags.None, null, 1, QueryService, []), queryDef( NodeFlags.TypeContentQuery | NodeFlags.DynamicQuery, someQueryId, {'a': QueryBindingType.First}), @@ -375,12 +361,12 @@ export function main() { } const {view} = createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 3, 'div'), - directiveDef(NodeFlags.None, null !, 1, QueryService, []), + elementDef(0, NodeFlags.None, null, null, 3, 'div'), + directiveDef(1, NodeFlags.None, null, 1, QueryService, []), queryDef( NodeFlags.TypeContentQuery | NodeFlags.DynamicQuery, someQueryId, {'a': QueryBindingType.All}), - aServiceProvider(), + aServiceProvider(3), ])); diff --git a/packages/core/test/view/services_spec.ts b/packages/core/test/view/services_spec.ts index 071973ccbb..decfb59862 100644 --- a/packages/core/test/view/services_spec.ts +++ b/packages/core/test/view/services_spec.ts @@ -6,27 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ -import {Injector, RenderComponentType, RootRenderer, Sanitizer, SecurityContext, ViewEncapsulation, getDebugNode} from '@angular/core'; -import {DebugContext, NodeDef, NodeFlags, QueryValueType, RootData, Services, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, asElementData, asProviderData, asTextData, directiveDef, elementDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index'; -import {inject} from '@angular/core/testing'; -import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; +import {DebugContext, NodeFlags, QueryValueType, Services, asElementData, asTextData, directiveDef, elementDef, textDef} from '@angular/core/src/view/index'; -import {createRootView, isBrowser} from './helper'; +import {compViewDef, createAndGetRootNodes} from './helper'; export function main() { describe('View Services', () => { - function compViewDef( - nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn, - viewFlags: ViewFlags = ViewFlags.None): ViewDefinition { - return viewDef(viewFlags, nodes, updateDirectives, updateRenderer); - } - - function createAndGetRootNodes( - viewDef: ViewDefinition, context: any = null): {rootNodes: any[], view: ViewData} { - const view = createRootView(viewDef, context); - const rootNodes = rootRenderNodes(view); - return {rootNodes, view}; - } describe('DebugContext', () => { class AComp {} @@ -36,12 +21,13 @@ export function main() { function createViewWithData() { const {view} = createAndGetRootNodes(compViewDef([ elementDef( - NodeFlags.None, null !, null !, 1, 'div', null !, null !, null !, null !, + 0, NodeFlags.None, null, null, 1, 'div', null, null, null, null, () => compViewDef([ - elementDef(NodeFlags.None, [['ref', QueryValueType.ElementRef]], null !, 2, 'span'), - directiveDef(NodeFlags.None, null !, 0, AService, []), textDef(null !, ['a']) + elementDef( + 0, NodeFlags.None, [['ref', QueryValueType.ElementRef]], null, 2, 'span'), + directiveDef(1, NodeFlags.None, null, 0, AService, []), textDef(2, null, ['a']) ])), - directiveDef(NodeFlags.Component, null !, 0, AComp, []), + directiveDef(1, NodeFlags.Component, null, 0, AComp, []), ])); return view; } diff --git a/packages/core/test/view/text_spec.ts b/packages/core/test/view/text_spec.ts index 967dd814f1..14bad7a892 100644 --- a/packages/core/test/view/text_spec.ts +++ b/packages/core/test/view/text_spec.ts @@ -6,46 +6,34 @@ * found in the LICENSE file at https://angular.io/license */ -import {Injector, RenderComponentType, RootRenderer, Sanitizer, SecurityContext, ViewEncapsulation, WrappedValue, getDebugNode} from '@angular/core'; -import {ArgumentType, DebugContext, NodeDef, NodeFlags, RootData, Services, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, asTextData, elementDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index'; -import {inject} from '@angular/core/testing'; +import {getDebugNode} from '@angular/core'; +import {NodeFlags, Services, asTextData, elementDef, textDef} from '@angular/core/src/view/index'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; -import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, isBrowser} from './helper'; +import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, compViewDef, createAndGetRootNodes} from './helper'; export function main() { describe(`View Text`, () => { - function compViewDef( - nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn, - viewFlags: ViewFlags = ViewFlags.None): ViewDefinition { - return viewDef(viewFlags, nodes, updateDirectives, updateRenderer); - } - - function createAndGetRootNodes( - viewDef: ViewDefinition, context?: any): {rootNodes: any[], view: ViewData} { - const view = createRootView(viewDef, context); - const rootNodes = rootRenderNodes(view); - return {rootNodes, view}; - } describe('create', () => { it('should create text nodes without parents', () => { - const rootNodes = createAndGetRootNodes(compViewDef([textDef(null !, ['a'])])).rootNodes; + const rootNodes = createAndGetRootNodes(compViewDef([textDef(0, null, ['a'])])).rootNodes; expect(rootNodes.length).toBe(1); expect(getDOM().getText(rootNodes[0])).toBe('a'); }); it('should create views with multiple root text nodes', () => { const rootNodes = createAndGetRootNodes(compViewDef([ - textDef(null !, ['a']), textDef(null !, ['b']) + textDef(0, null, ['a']), + textDef(1, null, ['b']), ])).rootNodes; expect(rootNodes.length).toBe(2); }); it('should create text nodes with parents', () => { const rootNodes = createAndGetRootNodes(compViewDef([ - elementDef(NodeFlags.None, null !, null !, 1, 'div'), - textDef(null !, ['a']), + elementDef(0, NodeFlags.None, null, null, 1, 'div'), + textDef(1, null, ['a']), ])).rootNodes; expect(rootNodes.length).toBe(1); const textNode = getDOM().firstChild(rootNodes[0]); @@ -55,7 +43,7 @@ export function main() { it('should add debug information to the renderer', () => { const someContext = new Object(); const {view, rootNodes} = - createAndGetRootNodes(compViewDef([textDef(null !, ['a'])]), someContext); + createAndGetRootNodes(compViewDef([textDef(0, null, ['a'])]), someContext); expect(getDebugNode(rootNodes[0]) !.nativeNode).toBe(asTextData(view, 0).renderText); }); }); @@ -65,7 +53,7 @@ export function main() { it(`should update via strategy ${inlineDynamic}`, () => { const {view, rootNodes} = createAndGetRootNodes(compViewDef( [ - textDef(null !, ['0', '1', '2']), + textDef(0, null, ['0', '1', '2']), ], null !, (check, view) => { checkNodeInlineOrDynamic(check, view, 0, inlineDynamic, ['a', 'b']); @@ -73,7 +61,6 @@ export function main() { Services.checkAndUpdateView(view); - const node = rootNodes[0]; expect(getDOM().getText(rootNodes[0])).toBe('0a1b2'); }); diff --git a/packages/core/test/view/view_def_spec.ts b/packages/core/test/view/view_def_spec.ts index a4527e6ae6..d1182bb479 100644 --- a/packages/core/test/view/view_def_spec.ts +++ b/packages/core/test/view/view_def_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {NodeFlags, QueryValueType, ViewData, ViewDefinition, ViewFlags, anchorDef, directiveDef, elementDef, textDef, viewDef} from '@angular/core/src/view/index'; +import {NodeFlags, QueryValueType, ViewDefinition, ViewFlags, anchorDef, directiveDef, elementDef, textDef, viewDef} from '@angular/core/src/view/index'; import {filterQueryId} from '@angular/core/src/view/util'; export function main() { @@ -14,14 +14,14 @@ export function main() { describe('parent', () => { function parents(viewDef: ViewDefinition): (number | null)[] { - return viewDef.nodes.map(node => node.parent ? node.parent.index : null); + return viewDef.nodes.map(node => node.parent ? node.parent.nodeIndex : null); } it('should calculate parents for one level', () => { const vd = viewDef(ViewFlags.None, [ - elementDef(NodeFlags.None, null !, null !, 2, 'span'), - textDef(null !, ['a']), - textDef(null !, ['a']), + elementDef(0, NodeFlags.None, null, null, 2, 'span'), + textDef(1, null, ['a']), + textDef(2, null, ['a']), ]); expect(parents(vd)).toEqual([null, 0, 0]); @@ -29,11 +29,11 @@ export function main() { it('should calculate parents for one level, multiple roots', () => { const vd = viewDef(ViewFlags.None, [ - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - textDef(null !, ['a']), - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - textDef(null !, ['a']), - textDef(null !, ['a']), + elementDef(0, NodeFlags.None, null, null, 1, 'span'), + textDef(1, null, ['a']), + elementDef(2, NodeFlags.None, null, null, 1, 'span'), + textDef(3, null, ['a']), + textDef(4, null, ['a']), ]); expect(parents(vd)).toEqual([null, 0, null, 2, null]); @@ -41,12 +41,12 @@ export function main() { it('should calculate parents for multiple levels', () => { const vd = viewDef(ViewFlags.None, [ - elementDef(NodeFlags.None, null !, null !, 2, 'span'), - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - textDef(null !, ['a']), - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - textDef(null !, ['a']), - textDef(null !, ['a']), + elementDef(0, NodeFlags.None, null, null, 2, 'span'), + elementDef(1, NodeFlags.None, null, null, 1, 'span'), + textDef(2, null, ['a']), + elementDef(3, NodeFlags.None, null, null, 1, 'span'), + textDef(4, null, ['a']), + textDef(5, null, ['a']), ]); expect(parents(vd)).toEqual([null, 0, 1, null, 3, null]); @@ -65,8 +65,8 @@ export function main() { it('should calculate childFlags for one level', () => { const vd = viewDef(ViewFlags.None, [ - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - directiveDef(NodeFlags.AfterContentChecked, null !, 0, AService, []) + elementDef(0, NodeFlags.None, null, null, 1, 'span'), + directiveDef(1, NodeFlags.AfterContentChecked, null, 0, AService, []) ]); expect(childFlags(vd)).toEqual([ @@ -80,9 +80,9 @@ export function main() { it('should calculate childFlags for two levels', () => { const vd = viewDef(ViewFlags.None, [ - elementDef(NodeFlags.None, null !, null !, 2, 'span'), - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - directiveDef(NodeFlags.AfterContentChecked, null !, 0, AService, []) + elementDef(0, NodeFlags.None, null, null, 2, 'span'), + elementDef(1, NodeFlags.None, null, null, 1, 'span'), + directiveDef(2, NodeFlags.AfterContentChecked, null, 0, AService, []) ]); expect(childFlags(vd)).toEqual([ @@ -98,11 +98,11 @@ export function main() { it('should calculate childFlags for one level, multiple roots', () => { const vd = viewDef(ViewFlags.None, [ - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - directiveDef(NodeFlags.AfterContentChecked, null !, 0, AService, []), - elementDef(NodeFlags.None, null !, null !, 2, 'span'), - directiveDef(NodeFlags.AfterContentInit, null !, 0, AService, []), - directiveDef(NodeFlags.AfterViewChecked, null !, 0, AService, []), + elementDef(0, NodeFlags.None, null, null, 1, 'span'), + directiveDef(1, NodeFlags.AfterContentChecked, null, 0, AService, []), + elementDef(2, NodeFlags.None, null, null, 2, 'span'), + directiveDef(3, NodeFlags.AfterContentInit, null, 0, AService, []), + directiveDef(4, NodeFlags.AfterViewChecked, null, 0, AService, []), ]); expect(childFlags(vd)).toEqual([ @@ -120,12 +120,12 @@ export function main() { it('should calculate childFlags for multiple levels', () => { const vd = viewDef(ViewFlags.None, [ - elementDef(NodeFlags.None, null !, null !, 2, 'span'), - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - directiveDef(NodeFlags.AfterContentChecked, null !, 0, AService, []), - elementDef(NodeFlags.None, null !, null !, 2, 'span'), - directiveDef(NodeFlags.AfterContentInit, null !, 0, AService, []), - directiveDef(NodeFlags.AfterViewInit, null !, 0, AService, []), + elementDef(0, NodeFlags.None, null, null, 2, 'span'), + elementDef(1, NodeFlags.None, null, null, 1, 'span'), + directiveDef(2, NodeFlags.AfterContentChecked, null !, 0, AService, []), + elementDef(3, NodeFlags.None, null, null, 2, 'span'), + directiveDef(4, NodeFlags.AfterContentInit, null, 0, AService, []), + directiveDef(5, NodeFlags.AfterViewInit, null, 0, AService, []), ]); expect(childFlags(vd)).toEqual([ @@ -151,8 +151,8 @@ export function main() { it('should calculate childMatchedQueries for one level', () => { const vd = viewDef(ViewFlags.None, [ - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - directiveDef(NodeFlags.None, [[1, QueryValueType.Provider]], 0, AService, []) + elementDef(0, NodeFlags.None, null, null, 1, 'span'), + directiveDef(1, NodeFlags.None, [[1, QueryValueType.Provider]], 0, AService, []) ]); expect(childMatchedQueries(vd)).toEqual([filterQueryId(1), 0]); @@ -160,9 +160,9 @@ export function main() { it('should calculate childMatchedQueries for two levels', () => { const vd = viewDef(ViewFlags.None, [ - elementDef(NodeFlags.None, null !, null !, 2, 'span'), - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - directiveDef(NodeFlags.None, [[1, QueryValueType.Provider]], 0, AService, []) + elementDef(0, NodeFlags.None, null, null, 2, 'span'), + elementDef(1, NodeFlags.None, null, null, 1, 'span'), + directiveDef(2, NodeFlags.None, [[1, QueryValueType.Provider]], 0, AService, []) ]); expect(childMatchedQueries(vd)).toEqual([filterQueryId(1), filterQueryId(1), 0]); @@ -170,11 +170,11 @@ export function main() { it('should calculate childMatchedQueries for one level, multiple roots', () => { const vd = viewDef(ViewFlags.None, [ - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - directiveDef(NodeFlags.None, [[1, QueryValueType.Provider]], 0, AService, []), - elementDef(NodeFlags.None, null !, null !, 2, 'span'), - directiveDef(NodeFlags.None, [[2, QueryValueType.Provider]], 0, AService, []), - directiveDef(NodeFlags.None, [[3, QueryValueType.Provider]], 0, AService, []), + elementDef(0, NodeFlags.None, null, null, 1, 'span'), + directiveDef(1, NodeFlags.None, [[1, QueryValueType.Provider]], 0, AService, []), + elementDef(2, NodeFlags.None, null, null, 2, 'span'), + directiveDef(3, NodeFlags.None, [[2, QueryValueType.Provider]], 0, AService, []), + directiveDef(4, NodeFlags.None, [[3, QueryValueType.Provider]], 0, AService, []), ]); expect(childMatchedQueries(vd)).toEqual([ @@ -184,12 +184,12 @@ export function main() { it('should calculate childMatchedQueries for multiple levels', () => { const vd = viewDef(ViewFlags.None, [ - elementDef(NodeFlags.None, null !, null !, 2, 'span'), - elementDef(NodeFlags.None, null !, null !, 1, 'span'), - directiveDef(NodeFlags.None, [[1, QueryValueType.Provider]], 0, AService, []), - elementDef(NodeFlags.None, null !, null !, 2, 'span'), - directiveDef(NodeFlags.None, [[2, QueryValueType.Provider]], 0, AService, []), - directiveDef(NodeFlags.None, [[3, QueryValueType.Provider]], 0, AService, []), + elementDef(0, NodeFlags.None, null, null, 2, 'span'), + elementDef(1, NodeFlags.None, null, null, 1, 'span'), + directiveDef(2, NodeFlags.None, [[1, QueryValueType.Provider]], 0, AService, []), + elementDef(3, NodeFlags.None, null, null, 2, 'span'), + directiveDef(4, NodeFlags.None, [[2, QueryValueType.Provider]], 0, AService, []), + directiveDef(5, NodeFlags.None, [[3, QueryValueType.Provider]], 0, AService, []), ]); expect(childMatchedQueries(vd)).toEqual([ @@ -199,13 +199,13 @@ export function main() { it('should included embedded views into childMatchedQueries', () => { const vd = viewDef(ViewFlags.None, [ - elementDef(NodeFlags.None, null !, null !, 1, 'span'), + elementDef(0, NodeFlags.None, null, null, 1, 'span'), anchorDef( - NodeFlags.None, null !, null !, 0, null !, + NodeFlags.None, null, null, 0, null, () => viewDef( ViewFlags.None, [ - elementDef(NodeFlags.None, [[1, QueryValueType.Provider]], null !, 0, 'span'), + elementDef(0, NodeFlags.None, [[1, QueryValueType.Provider]], null, 0, 'span'), ])) ]);