diff --git a/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts b/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts index 96b45b9bbd50b..f2c3344fbfad4 100644 --- a/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts @@ -796,7 +796,6 @@ describe('compiler compliance', () => { `IfDirective.ɵfac = function IfDirective_Factory(t) { return new (t || IfDirective)($r3$.ɵɵdirectiveInject($i$.TemplateRef)); };`; const MyComponentDefinition = ` - const $c1$ = ["foo", ""]; function MyComponent_li_2_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵelementStart(0, "li"); @@ -816,16 +815,16 @@ describe('compiler compliance', () => { selectors: [["my-component"]], decls: 3, vars: 0, - consts: [[${AttributeMarker.Template}, "if"]], + consts: [["foo", ""], [${AttributeMarker.Template}, "if"]], template: function MyComponent_Template(rf, ctx) { if (rf & 1) { - $r3$.ɵɵelementStart(0, "ul", null, $c1$); - $r3$.ɵɵtemplate(2, MyComponent_li_2_Template, 2, 2, "li", 0); + $r3$.ɵɵelementStart(0, "ul", null, 0); + $r3$.ɵɵtemplate(2, MyComponent_li_2_Template, 2, 2, "li", 1); $r3$.ɵɵelementEnd(); } }, - directives:[IfDirective], - encapsulation: 2 + directives: [IfDirective], + encapsulation: 2 });`; const MyComponentFactory = @@ -2231,16 +2230,16 @@ describe('compiler compliance', () => { }; const MyComponentDefinition = ` - const $c1$ = ["user", ""]; … MyComponent.ɵcmp = $r3$.ɵɵdefineComponent({ type: MyComponent, selectors: [["my-component"]], decls: 3, vars: 1, + consts: [["user", ""]], template: function MyComponent_Template(rf, ctx) { if (rf & 1) { - $r3$.ɵɵelement(0, "input", null, $c1$); + $r3$.ɵɵelement(0, "input", null, 0); $r3$.ɵɵtext(2); } if (rf & 2) { @@ -2292,9 +2291,6 @@ describe('compiler compliance', () => { }; const MyComponentDefinition = ` - const $c1$ = ["foo", ""]; - const $c3$ = ["baz", ""]; - const $c4$ = ["bar", ""]; function MyComponent_div_3_span_2_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵelementStart(0, "span"); @@ -2315,8 +2311,8 @@ describe('compiler compliance', () => { if (rf & 1) { $r3$.ɵɵelementStart(0, "div"); $r3$.ɵɵtext(1); - $r3$.ɵɵtemplate(2, MyComponent_div_3_span_2_Template, 2, 3, "span", 0); - $r3$.ɵɵelement(3, "span", null, $c4$); + $r3$.ɵɵtemplate(2, MyComponent_div_3_span_2_Template, 2, 3, "span", 1); + $r3$.ɵɵelement(3, "span", null, 3); $r3$.ɵɵelementEnd(); } if (rf & 2) { @@ -2333,13 +2329,13 @@ describe('compiler compliance', () => { selectors: [["my-component"]], decls: 6, vars: 1, - consts: [[${AttributeMarker.Template}, "if"]], + consts: [["foo", ""], [${AttributeMarker.Template}, "if"], ["baz", ""], ["bar", ""]], template: function MyComponent_Template(rf, ctx) { if (rf & 1) { - $r3$.ɵɵelement(0, "div", null, $c1$); + $r3$.ɵɵelement(0, "div", null, 0); $r3$.ɵɵtext(2); - $r3$.ɵɵtemplate(3, MyComponent_div_3_Template, 5, 2, "div", 0); - $r3$.ɵɵelement(4, "div", null, $c3$); + $r3$.ɵɵtemplate(3, MyComponent_div_3_Template, 5, 2, "div", 1); + $r3$.ɵɵelement(4, "div", null, 2); } if (rf & 2) { const $foo$ = $r3$.ɵɵreference(1); @@ -2381,8 +2377,6 @@ describe('compiler compliance', () => { }; const template = ` - const $c1$ = ["foo", ""]; - function MyComponent_div_0_span_3_Template(rf, ctx) { if (rf & 1) { $i0$.ɵɵelementStart(0, "span"); @@ -2400,8 +2394,8 @@ describe('compiler compliance', () => { function MyComponent_div_0_Template(rf, ctx) { if (rf & 1) { $i0$.ɵɵelementStart(0, "div"); - $i0$.ɵɵelement(1, "div", null, $c1$); - $i0$.ɵɵtemplate(3, MyComponent_div_0_span_3_Template, 2, 2, "span", 1); + $i0$.ɵɵelement(1, "div", null, 1); + $i0$.ɵɵtemplate(3, MyComponent_div_0_span_3_Template, 2, 2, "span", 2); $i0$.ɵɵelementEnd(); } if (rf & 2) { @@ -2412,7 +2406,7 @@ describe('compiler compliance', () => { } // ... - consts: [[${AttributeMarker.Template}, "ngFor", "ngForOf"], [${AttributeMarker.Template}, "ngIf"]], + consts: [[${AttributeMarker.Template}, "ngFor", "ngForOf"], ["foo", ""], [${AttributeMarker.Template}, "ngIf"]], template:function MyComponent_Template(rf, ctx){ if (rf & 1) { $i0$.ɵɵtemplate(0, MyComponent_div_0_Template, 4, 1, "div", 0); diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_binding_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_binding_spec.ts index f24dc919821a7..28f48f6ba634b 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_binding_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_binding_spec.ts @@ -1251,12 +1251,11 @@ describe('compiler compliance: bindings', () => { `); const template = ` - const $_c1$ = ["myRef", ""]; … - consts: [["id", "my-id"]], + consts: [["id", "my-id"], ["myRef", ""]], template:function MyComponent_Template(rf, $ctx$){ if (rf & 1) { - $i0$.ɵɵelementStart(0, "b", 0, $_c1$); + $i0$.ɵɵelementStart(0, "b", 0, 1); $i0$.ɵɵdisableBindings(); $i0$.ɵɵelementStart(2, "i"); $i0$.ɵɵtext(3, "Hello {{ name }}!"); diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_listener_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_listener_spec.ts index abbb6a0fc0d6f..088b881e03252 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_listener_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_listener_spec.ts @@ -193,14 +193,13 @@ describe('compiler compliance: listen()', () => { }; const MyComponentDefinition = ` - const $e2_refs$ = ["user", ""]; … MyComponent.ɵcmp = $r3$.ɵɵdefineComponent({ type: MyComponent, selectors: [["my-component"]], decls: 4, vars: 0, - consts: [[${AttributeMarker.Bindings}, "click"]], + consts: [[${AttributeMarker.Bindings}, "click"], ["user", ""]], template: function MyComponent_Template(rf, ctx) { if (rf & 1) { const $s$ = $r3$.ɵɵgetCurrentView(); @@ -212,7 +211,7 @@ describe('compiler compliance: listen()', () => { }); $r3$.ɵɵtext(1, "Save"); $r3$.ɵɵelementEnd(); - $r3$.ɵɵelement(2, "input", null, $e2_refs$); + $r3$.ɵɵelement(2, "input", null, 1); } }, encapsulation: 2 diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_template_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_template_spec.ts index 7ea9a3e0e96a5..dc8ac26d34476 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_template_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_template_spec.ts @@ -491,8 +491,6 @@ describe('compiler compliance: template', () => { }; const template = ` - const $t0_refs$ = ["foo", ""]; - function MyComponent_ng_template_0_Template(rf, ctx) { if (rf & 1) { $i0$.ɵɵtext(0, "some-content"); @@ -500,10 +498,10 @@ describe('compiler compliance: template', () => { } // ... - + consts: [["foo", ""]], template: function MyComponent_Template(rf, ctx) { if (rf & 1) { - $i0$.ɵɵtemplate(0, MyComponent_ng_template_0_Template, 1, 0, "ng-template", null, $t0_refs$, $i0$.ɵɵtemplateRefExtractor); + $i0$.ɵɵtemplate(0, MyComponent_ng_template_0_Template, 1, 0, "ng-template", null, 0, $i0$.ɵɵtemplateRefExtractor); } }`; diff --git a/packages/compiler/src/render3/view/template.ts b/packages/compiler/src/render3/view/template.ts index 6d2e0d6c6a283..da3eb85fc9b5b 100644 --- a/packages/compiler/src/render3/view/template.ts +++ b/packages/compiler/src/render3/view/template.ts @@ -606,10 +606,11 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver // add attributes for directive and projection matching purposes attributes.push(...this.prepareNonRenderAttrs( allOtherInputs, element.outputs, stylingBuilder, [], i18nAttrs, ngProjectAsAttr)); - parameters.push(this.addConstants(attributes)); + parameters.push(this.addAttrsToConsts(attributes)); // local refs (ex.:
) - parameters.push(this.prepareRefsParameter(element.references)); + const refs = this.prepareRefsArray(element.references); + parameters.push(this.addToConsts(refs)); const wasInNamespace = this._namespace; const currentNamespace = this.getNamespaceInstruction(namespaceKey); @@ -869,11 +870,12 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver (a: t.TextAttribute) => { attrsExprs.push(asLiteral(a.name), asLiteral(a.value)); }); attrsExprs.push(...this.prepareNonRenderAttrs( template.inputs, template.outputs, undefined, template.templateAttrs)); - parameters.push(this.addConstants(attrsExprs)); + parameters.push(this.addAttrsToConsts(attrsExprs)); // local refs (ex.: ) if (template.references && template.references.length) { - parameters.push(this.prepareRefsParameter(template.references)); + const refs = this.prepareRefsArray(template.references); + parameters.push(this.addToConsts(refs)); parameters.push(o.importExpr(R3.templateRefExtractor)); } @@ -1294,24 +1296,26 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver return attrExprs; } - private addConstants(constExprs: o.Expression[]): o.LiteralExpr { - if (constExprs.length > 0) { - const literal = o.literalArr(constExprs); + private addToConsts(expression: o.Expression): o.LiteralExpr { + if (o.isNull(expression)) { + return o.TYPED_NULL_EXPR; + } - // Try to reuse a literal that's already in the array, if possible. - for (let i = 0; i < this._constants.length; i++) { - if (this._constants[i].isEquivalent(literal)) { - return o.literal(i); - } + // Try to reuse a literal that's already in the array, if possible. + for (let i = 0; i < this._constants.length; i++) { + if (this._constants[i].isEquivalent(expression)) { + return o.literal(i); } - - return o.literal(this._constants.push(literal) - 1); } - return o.TYPED_NULL_EXPR; + return o.literal(this._constants.push(expression) - 1); + } + + private addAttrsToConsts(attrs: o.Expression[]): o.LiteralExpr { + return attrs.length > 0 ? this.addToConsts(o.literalArr(attrs)) : o.TYPED_NULL_EXPR; } - private prepareRefsParameter(references: t.Reference[]): o.Expression { + private prepareRefsArray(references: t.Reference[]): o.Expression { if (!references || references.length === 0) { return o.TYPED_NULL_EXPR; } @@ -1336,7 +1340,7 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver return [reference.name, reference.value]; })); - return this.constantPool.getConstLiteral(asLiteral(refsParam), true); + return asLiteral(refsParam); } private prepareListenerParameter(tagName: string, outputAst: t.BoundEvent, index: number): diff --git a/packages/core/src/render3/definition.ts b/packages/core/src/render3/definition.ts index 228ac7599c3d1..94a413bd77042 100644 --- a/packages/core/src/render3/definition.ts +++ b/packages/core/src/render3/definition.ts @@ -18,7 +18,7 @@ import {stringify} from '../util/stringify'; import {EMPTY_ARRAY, EMPTY_OBJ} from './empty'; import {NG_COMP_DEF, NG_DIR_DEF, NG_FACTORY_DEF, NG_LOC_ID_DEF, NG_MOD_DEF, NG_PIPE_DEF} from './fields'; import {ComponentDef, ComponentDefFeature, ComponentTemplate, ComponentType, ContentQueriesFunction, DirectiveDef, DirectiveDefFeature, DirectiveTypesOrFactory, FactoryFn, HostBindingsFunction, PipeDef, PipeType, PipeTypesOrFactory, ViewQueriesFunction} from './interfaces/definition'; -import {TAttributes} from './interfaces/node'; +import {TConstants} from './interfaces/node'; // while SelectorFlags is unused here, it's required so that types don't get resolved lazily // see: https://github.com/Microsoft/web-build-tools/issues/1050 import {CssSelectorList, SelectorFlags} from './interfaces/projection'; @@ -172,8 +172,11 @@ export function ɵɵdefineComponent(componentDefinition: { */ template: ComponentTemplate; - /** Constants for the nodes in the component's view. */ - consts?: TAttributes[]; + /** + * Constants for the nodes in the component's view. + * Includes attribute arrays, local definition arrays etc. + */ + consts?: TConstants; /** * An array of `ngContent[selector]` values that were found in the template. diff --git a/packages/core/src/render3/instructions/container.ts b/packages/core/src/render3/instructions/container.ts index e0a27e59d097c..90b02b18f0b29 100644 --- a/packages/core/src/render3/instructions/container.ts +++ b/packages/core/src/render3/instructions/container.ts @@ -17,7 +17,7 @@ import {FLAGS, HEADER_OFFSET, InitPhaseState, LView, LViewFlags, RENDERER, TVIEW import {assertNodeType} from '../node_assert'; import {appendChild, removeView} from '../node_manipulation'; import {getBindingIndex, getCheckNoChangesMode, getIsParent, getLView, getPreviousOrParentTNode, setIsNotParent, setPreviousOrParentTNode} from '../state'; -import {load} from '../util/view_utils'; +import {getConstant, load} from '../util/view_utils'; import {addToViewTree, createDirectivesInstances, createLContainer, createTNode, createTView, getOrCreateTNode, resolveDirectives, saveResolvedLocalsInData} from './shared'; @@ -56,8 +56,8 @@ export function ɵɵcontainer(index: number): void { * @param decls The number of nodes, local refs, and pipes for this template * @param vars The number of bindings for this template * @param tagName The name of the container element, if applicable - * @param constsIndex Index of template in the `consts` array. - * @param localRefs A set of local reference bindings on the element. + * @param attrsIndex Index of template attributes in the `consts` array. + * @param localRefs Index of the local references in the `consts` array. * @param localRefExtractor A function which extracts local-refs values from the template. * Defaults to the current element associated with the local-ref. * @@ -65,7 +65,7 @@ export function ɵɵcontainer(index: number): void { */ export function ɵɵtemplate( index: number, templateFn: ComponentTemplate| null, decls: number, vars: number, - tagName?: string | null, constsIndex?: number | null, localRefs?: string[] | null, + tagName?: string | null, attrsIndex?: number | null, localRefsIndex?: number | null, localRefExtractor?: LocalRefExtractor) { const lView = getLView(); const tView = lView[TVIEW]; @@ -73,11 +73,11 @@ export function ɵɵtemplate( // TODO: consider a separate node type for templates const tContainerNode = containerInternal( - lView, index, tagName || null, - tViewConsts === null || constsIndex == null ? null : tViewConsts[constsIndex]); + lView, index, tagName || null, getConstant(tViewConsts, attrsIndex) as TAttributes); + const localRefs = getConstant(tViewConsts, localRefsIndex) as string[]; if (tView.firstTemplatePass) { ngDevMode && ngDevMode.firstTemplatePass++; - resolveDirectives(tView, lView, tContainerNode, localRefs || null); + resolveDirectives(tView, lView, tContainerNode, localRefs); registerPostOrderHooks(tView, tContainerNode); const embeddedTView = tContainerNode.tViews = createTView( diff --git a/packages/core/src/render3/instructions/element.ts b/packages/core/src/render3/instructions/element.ts index b8be8c4e60064..735bd14677f87 100644 --- a/packages/core/src/render3/instructions/element.ts +++ b/packages/core/src/render3/instructions/element.ts @@ -20,7 +20,7 @@ import {appendChild} from '../node_manipulation'; import {decreaseElementDepthCount, getBindingIndex, getElementDepthCount, getIsParent, getLView, getNamespace, getPreviousOrParentTNode, getSelectedIndex, increaseElementDepthCount, setIsNotParent, setPreviousOrParentTNode} from '../state'; import {setUpAttributes} from '../util/attrs_utils'; import {getInitialStylingValue, hasClassInput, hasStyleInput, selectClassBasedInputName} from '../util/styling_utils'; -import {getNativeByTNode, getTNode} from '../util/view_utils'; +import {getConstant, getNativeByTNode, getTNode} from '../util/view_utils'; import {createDirectivesInstances, elementCreate, executeContentQueries, getOrCreateTNode, matchingSchemas, renderInitialStyling, resolveDirectives, saveResolvedLocalsInData, setInputsForProperty} from './shared'; import {registerInitialStylingOnTNode} from './styling'; @@ -32,8 +32,8 @@ import {registerInitialStylingOnTNode} from './styling'; * * @param index Index of the element in the LView array * @param name Name of the DOM Node - * @param constsIndex Index of the element in the `consts` array. - * @param localRefs A set of local reference bindings on the element. + * @param attrsIndex Index of the element's attributes in the `consts` array. + * @param localRefsIndex Index of the element's local references in the `consts` array. * * Attributes and localRefs are passed as an array of strings where elements with an even index * hold an attribute name and elements with an odd index hold an attribute value, ex.: @@ -42,25 +42,25 @@ import {registerInitialStylingOnTNode} from './styling'; * @codeGenApi */ export function ɵɵelementStart( - index: number, name: string, constsIndex?: number | null, localRefs?: string[] | null): void { + index: number, name: string, attrsIndex?: number | null, localRefsIndex?: number): void { const lView = getLView(); const tView = lView[TVIEW]; const tViewConsts = tView.consts; - const consts = tViewConsts === null || constsIndex == null ? null : tViewConsts[constsIndex]; + const attrs = getConstant(tViewConsts, attrsIndex) as TAttributes; + const localRefs = getConstant(tViewConsts, localRefsIndex) as string[]; ngDevMode && assertEqual( getBindingIndex(), tView.bindingStartIndex, 'elements should be created before any bindings'); - ngDevMode && ngDevMode.rendererCreateElement++; ngDevMode && assertDataInRange(lView, index + HEADER_OFFSET); const renderer = lView[RENDERER]; const native = lView[index + HEADER_OFFSET] = elementCreate(name, renderer, getNamespace()); - const tNode = getOrCreateTNode(tView, lView[T_HOST], index, TNodeType.Element, name, consts); + const tNode = getOrCreateTNode(tView, lView[T_HOST], index, TNodeType.Element, name, attrs); - if (consts != null) { - const lastAttrIndex = setUpAttributes(renderer, native, consts); + if (attrs != null) { + const lastAttrIndex = setUpAttributes(renderer, native, attrs); if (tView.firstTemplatePass) { - registerInitialStylingOnTNode(tNode, consts, lastAttrIndex); + registerInitialStylingOnTNode(tNode, attrs, lastAttrIndex); } } @@ -84,7 +84,7 @@ export function ɵɵelementStart( // and `[class]` bindings work for multiple directives.) if (tView.firstTemplatePass) { ngDevMode && ngDevMode.firstTemplatePass++; - const hasDirectives = resolveDirectives(tView, lView, tNode, localRefs || null); + const hasDirectives = resolveDirectives(tView, lView, tNode, localRefs); ngDevMode && validateElement(lView, native, tNode, hasDirectives); if (tView.queries !== null) { @@ -148,14 +148,14 @@ export function ɵɵelementEnd(): void { * * @param index Index of the element in the data array * @param name Name of the DOM Node - * @param constsIndex Index of the element in the `consts` array. - * @param localRefs A set of local reference bindings on the element. + * @param attrsIndex Index of the element's attributes in the `consts` array. + * @param localRefsIndex Index of the element's local references in the `consts` array. * * @codeGenApi */ export function ɵɵelement( - index: number, name: string, constsIndex?: number | null, localRefs?: string[] | null): void { - ɵɵelementStart(index, name, constsIndex, localRefs); + index: number, name: string, attrsIndex?: number | null, localRefsIndex?: number): void { + ɵɵelementStart(index, name, attrsIndex, localRefsIndex); ɵɵelementEnd(); } diff --git a/packages/core/src/render3/instructions/element_container.ts b/packages/core/src/render3/instructions/element_container.ts index 1882da2c7684a..10f6b3cc6f335 100644 --- a/packages/core/src/render3/instructions/element_container.ts +++ b/packages/core/src/render3/instructions/element_container.ts @@ -15,6 +15,7 @@ import {HEADER_OFFSET, RENDERER, TVIEW, T_HOST} from '../interfaces/view'; import {assertNodeType} from '../node_assert'; import {appendChild} from '../node_manipulation'; import {getBindingIndex, getIsParent, getLView, getPreviousOrParentTNode, setIsNotParent, setPreviousOrParentTNode} from '../state'; +import {getConstant} from '../util/view_utils'; import {createDirectivesInstances, executeContentQueries, getOrCreateTNode, resolveDirectives, saveResolvedLocalsInData} from './shared'; import {registerInitialStylingOnTNode} from './styling'; @@ -26,8 +27,8 @@ import {registerInitialStylingOnTNode} from './styling'; * The instruction must later be followed by `elementContainerEnd()` call. * * @param index Index of the element in the LView array - * @param constsIndex Index of the container in the `consts` array. - * @param localRefs A set of local reference bindings on the element. + * @param attrsIndex Index of the container attributes in the `consts` array. + * @param localRefsIndex Index of the container's local references in the `consts` array. * * Even if this instruction accepts a set of attributes no actual attribute values are propagated to * the DOM (as a comment node can't have attributes). Attributes are here only for directive @@ -36,13 +37,14 @@ import {registerInitialStylingOnTNode} from './styling'; * @codeGenApi */ export function ɵɵelementContainerStart( - index: number, constsIndex?: number | null, localRefs?: string[] | null): void { + index: number, attrsIndex?: number | null, localRefsIndex?: number): void { const lView = getLView(); const tView = lView[TVIEW]; const renderer = lView[RENDERER]; const tagName = 'ng-container'; const tViewConsts = tView.consts; - const consts = tViewConsts === null || constsIndex == null ? null : tViewConsts[constsIndex]; + const attrs = getConstant(tViewConsts, attrsIndex) as TAttributes; + const localRefs = getConstant(tViewConsts, localRefsIndex) as string[]; ngDevMode && assertEqual( getBindingIndex(), tView.bindingStartIndex, 'element containers should be created before any bindings'); @@ -53,12 +55,12 @@ export function ɵɵelementContainerStart( ngDevMode && assertDataInRange(lView, index - 1); const tNode = - getOrCreateTNode(tView, lView[T_HOST], index, TNodeType.ElementContainer, tagName, consts); + getOrCreateTNode(tView, lView[T_HOST], index, TNodeType.ElementContainer, tagName, attrs); - if (consts && tView.firstTemplatePass) { + if (attrs && tView.firstTemplatePass) { // While ng-container doesn't necessarily support styling, we use the style context to identify // and execute directives on the ng-container. - registerInitialStylingOnTNode(tNode, consts as TAttributes, 0); + registerInitialStylingOnTNode(tNode, attrs, 0); } appendChild(native, tNode, lView); @@ -66,7 +68,7 @@ export function ɵɵelementContainerStart( if (tView.firstTemplatePass) { ngDevMode && ngDevMode.firstTemplatePass++; - resolveDirectives(tView, lView, tNode, localRefs || null); + resolveDirectives(tView, lView, tNode, localRefs); if (tView.queries) { tView.queries.elementStart(tView, tNode); } @@ -114,13 +116,13 @@ export function ɵɵelementContainerEnd(): void { * and {@link elementContainerEnd} * * @param index Index of the element in the LView array - * @param constsIndex Index of the container in the `consts` array. - * @param localRefs A set of local reference bindings on the element. + * @param attrsIndex Index of the container attributes in the `consts` array. + * @param localRefsIndex Index of the container's local references in the `consts` array. * * @codeGenApi */ export function ɵɵelementContainer( - index: number, constsIndex?: number | null, localRefs?: string[] | null): void { - ɵɵelementContainerStart(index, constsIndex, localRefs); + index: number, attrsIndex?: number | null, localRefsIndex?: number): void { + ɵɵelementContainerStart(index, attrsIndex, localRefsIndex); ɵɵelementContainerEnd(); } diff --git a/packages/core/src/render3/instructions/lview_debug.ts b/packages/core/src/render3/instructions/lview_debug.ts index 41375298a9106..a51bcb9befde8 100644 --- a/packages/core/src/render3/instructions/lview_debug.ts +++ b/packages/core/src/render3/instructions/lview_debug.ts @@ -14,7 +14,7 @@ import {initNgDevMode} from '../../util/ng_dev_mode'; import {ACTIVE_INDEX, CONTAINER_HEADER_OFFSET, LContainer, MOVED_VIEWS, NATIVE} from '../interfaces/container'; import {DirectiveDefList, PipeDefList, ViewQueriesFunction} from '../interfaces/definition'; import {COMMENT_MARKER, ELEMENT_MARKER, I18nMutateOpCode, I18nMutateOpCodes, I18nUpdateOpCode, I18nUpdateOpCodes, TIcu} from '../interfaces/i18n'; -import {PropertyAliases, TAttributes, TContainerNode, TElementNode, TNode as ITNode, TNode, TNodeFlags, TNodeProviderIndexes, TNodeType, TViewNode} from '../interfaces/node'; +import {PropertyAliases, TConstants, TContainerNode, TElementNode, TNode as ITNode, TNode, TNodeFlags, TNodeProviderIndexes, TNodeType, TViewNode} from '../interfaces/node'; import {SelectorFlags} from '../interfaces/projection'; import {TQueries} from '../interfaces/query'; import {RComment, RElement, RNode} from '../interfaces/renderer'; @@ -102,7 +102,7 @@ export const TViewConstructor = class TView implements ITView { public pipeRegistry: PipeDefList|null, // public firstChild: TNode|null, // public schemas: SchemaMetadata[]|null, // - public consts: TAttributes[]|null, // + public consts: TConstants|null, // ) {} get template_(): string { diff --git a/packages/core/src/render3/instructions/shared.ts b/packages/core/src/render3/instructions/shared.ts index 078f353235bbf..052915456d27c 100644 --- a/packages/core/src/render3/instructions/shared.ts +++ b/packages/core/src/render3/instructions/shared.ts @@ -23,7 +23,7 @@ import {executeCheckHooks, executeInitAndCheckHooks, incrementInitPhaseFlags, re import {ACTIVE_INDEX, CONTAINER_HEADER_OFFSET, LContainer} from '../interfaces/container'; import {ComponentDef, ComponentTemplate, DirectiveDef, DirectiveDefListOrFactory, PipeDefListOrFactory, RenderFlags, ViewQueriesFunction} from '../interfaces/definition'; import {INJECTOR_BLOOM_PARENT_SIZE, NodeInjectorFactory} from '../interfaces/injector'; -import {AttributeMarker, InitialInputData, InitialInputs, LocalRefExtractor, PropertyAliasValue, PropertyAliases, TAttributes, TContainerNode, TDirectiveHostNode, TElementContainerNode, TElementNode, TIcuContainerNode, TNode, TNodeFlags, TNodeProviderIndexes, TNodeType, TProjectionNode, TViewNode} from '../interfaces/node'; +import {AttributeMarker, InitialInputData, InitialInputs, LocalRefExtractor, PropertyAliasValue, PropertyAliases, TAttributes, TConstants, TContainerNode, TDirectiveHostNode, TElementContainerNode, TElementNode, TIcuContainerNode, TNode, TNodeFlags, TNodeProviderIndexes, TNodeType, TProjectionNode, TViewNode} from '../interfaces/node'; import {RComment, RElement, RNode, RText, Renderer3, RendererFactory3, isProceduralRenderer} from '../interfaces/renderer'; import {SanitizerFn} from '../interfaces/sanitization'; import {isComponentDef, isComponentHost, isContentQueryHost, isLContainer, isRootView} from '../interfaces/type_checks'; @@ -588,7 +588,7 @@ export function createTView( viewIndex: number, templateFn: ComponentTemplate| null, decls: number, vars: number, directives: DirectiveDefListOrFactory | null, pipes: PipeDefListOrFactory | null, viewQuery: ViewQueriesFunction| null, schemas: SchemaMetadata[] | null, - consts: TAttributes[] | null): TView { + consts: TConstants | null): TView { ngDevMode && ngDevMode.tView++; const bindingStartIndex = HEADER_OFFSET + decls; // This length does not yet contain host bindings from child directives because at this point, @@ -627,7 +627,7 @@ export function createTView( typeof pipes === 'function' ? pipes() : pipes, // pipeRegistry: PipeDefList|null, null, // firstChild: TNode|null, schemas, // schemas: SchemaMetadata[]|null, - consts) : // consts: TAttributes[] + consts) : // consts: TConstants|null { id: viewIndex, blueprint: blueprint, @@ -1048,7 +1048,7 @@ export function resolveDirectives( if (!getBindingsEnabled()) return false; const directives: DirectiveDef[]|null = findDirectiveMatches(tView, lView, tNode); - const exportsMap: ({[key: string]: number} | null) = localRefs ? {'': -1} : null; + const exportsMap: ({[key: string]: number} | null) = localRefs === null ? null : {'': -1}; let hasDirectives = false; if (directives !== null) { diff --git a/packages/core/src/render3/interfaces/definition.ts b/packages/core/src/render3/interfaces/definition.ts index 89f0633eab5f5..6b49420f87662 100644 --- a/packages/core/src/render3/interfaces/definition.ts +++ b/packages/core/src/render3/interfaces/definition.ts @@ -10,7 +10,7 @@ import {SchemaMetadata, ViewEncapsulation} from '../../core'; import {ProcessProvidersFunction} from '../../di/interface/provider'; import {Type} from '../../interface/type'; -import {TAttributes} from './node'; +import {TConstants} from './node'; import {CssSelectorList} from './projection'; import {TView} from './view'; @@ -227,7 +227,7 @@ export interface ComponentDef extends DirectiveDef { readonly template: ComponentTemplate; /** Constants associated with the component's view. */ - readonly consts: TAttributes[]|null; + readonly consts: TConstants|null; /** * An array of `ngContent[selector]` values that were found in the template. diff --git a/packages/core/src/render3/interfaces/node.ts b/packages/core/src/render3/interfaces/node.ts index 1b095bcddd636..3fa02886e0684 100644 --- a/packages/core/src/render3/interfaces/node.ts +++ b/packages/core/src/render3/interfaces/node.ts @@ -224,6 +224,13 @@ export const enum AttributeMarker { */ export type TAttributes = (string | AttributeMarker | CssSelector)[]; +/** + * Constants that are associated with a view. Includes: + * - Attribute arrays. + * - Local definition arrays. + */ +export type TConstants = (TAttributes | string)[]; + /** * Binding data (flyweight) for a particular node that is shared between all templates * of a specific type. diff --git a/packages/core/src/render3/interfaces/view.ts b/packages/core/src/render3/interfaces/view.ts index 96cb52487f8f4..93ba5fabda459 100644 --- a/packages/core/src/render3/interfaces/view.ts +++ b/packages/core/src/render3/interfaces/view.ts @@ -15,7 +15,7 @@ import {Sanitizer} from '../../sanitization/sanitizer'; import {LContainer} from './container'; import {ComponentDef, ComponentTemplate, DirectiveDef, DirectiveDefList, HostBindingsFunction, PipeDef, PipeDefList, ViewQueriesFunction} from './definition'; import {I18nUpdateOpCodes, TI18n} from './i18n'; -import {TAttributes, TElementNode, TNode, TViewNode} from './node'; +import {TAttributes, TConstants, TElementNode, TNode, TViewNode} from './node'; import {PlayerHandler} from './player'; import {LQueries, TQueries} from './query'; import {RElement, Renderer3, RendererFactory3} from './renderer'; @@ -555,10 +555,10 @@ export interface TView { schemas: SchemaMetadata[]|null; /** - * Array of attributes for all of the elements in the view. Used - * for directive matching and attribute bindings. + * Array of constants for the view. Includes attribute arrays, local definition arrays etc. + * Used for directive matching, attribute bindings, local definitions and more. */ - consts: TAttributes[]|null; + consts: TConstants|null; } export const enum RootContextFlags {Empty = 0b00, DetectChanges = 0b01, FlushPlayers = 0b10} diff --git a/packages/core/src/render3/util/view_utils.ts b/packages/core/src/render3/util/view_utils.ts index a9aa460d26cca..c9250b25f5b5c 100644 --- a/packages/core/src/render3/util/view_utils.ts +++ b/packages/core/src/render3/util/view_utils.ts @@ -10,7 +10,7 @@ import {assertDataInRange, assertDefined, assertDomNode, assertGreaterThan, asse import {assertTNodeForLView} from '../assert'; import {LContainer, TYPE} from '../interfaces/container'; import {LContext, MONKEY_PATCH_KEY_NAME} from '../interfaces/context'; -import {TNode} from '../interfaces/node'; +import {TConstants, TNode} from '../interfaces/node'; import {RNode, isProceduralRenderer} from '../interfaces/renderer'; import {isLContainer, isLView} from '../interfaces/type_checks'; import {FLAGS, HEADER_OFFSET, HOST, LView, LViewFlags, PARENT, PREORDER_HOOK_FLAGS, RENDERER, TData, TVIEW} from '../interfaces/view'; @@ -175,6 +175,11 @@ export function viewAttachedToContainer(view: LView): boolean { return isLContainer(view[PARENT]); } +/** Returns a constant from `TConstants` instance. */ +export function getConstant(consts: TConstants | null, index: number | null | undefined) { + return consts === null || index == null ? null : consts[index]; +} + /** * Resets the pre-order hook flags of the view. * @param lView the LView on which the flags are reset diff --git a/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json b/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json index 897f619d3421f..186fbeae2716f 100644 --- a/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json +++ b/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json @@ -296,6 +296,9 @@ { "name": "getComponentLViewByIndex" }, + { + "name": "getConstant" + }, { "name": "getContainerRenderParent" }, diff --git a/packages/core/test/bundling/todo/bundle.golden_symbols.json b/packages/core/test/bundling/todo/bundle.golden_symbols.json index 90a2e991ee749..c1258133124fd 100644 --- a/packages/core/test/bundling/todo/bundle.golden_symbols.json +++ b/packages/core/test/bundling/todo/bundle.golden_symbols.json @@ -314,12 +314,6 @@ { "name": "_activeStylingMapApplyFn" }, - { - "name": "_c0" - }, - { - "name": "_c1" - }, { "name": "_currentInjector" }, @@ -641,6 +635,9 @@ { "name": "getConfig" }, + { + "name": "getConstant" + }, { "name": "getContainerRenderParent" }, diff --git a/packages/core/test/render3/listeners_spec.ts b/packages/core/test/render3/listeners_spec.ts index e54d26cda587e..1537fedbc30b6 100644 --- a/packages/core/test/render3/listeners_spec.ts +++ b/packages/core/test/render3/listeners_spec.ts @@ -917,10 +917,11 @@ describe('event listeners', () => { selectors: [['app']], decls: 3, vars: 0, + consts: [['comp', '']], template: (rf: RenderFlags, ctx: App) => { if (rf & RenderFlags.Create) { const state = ɵɵgetCurrentView(); - ɵɵelement(0, 'comp', null, ['comp', '']); + ɵɵelement(0, 'comp', null, 0); ɵɵelementStart(2, 'button'); { ɵɵlistener('click', function() { diff --git a/packages/core/test/render3/query_spec.ts b/packages/core/test/render3/query_spec.ts index 71c2a0fb5190e..01458a7982776 100644 --- a/packages/core/test/render3/query_spec.ts +++ b/packages/core/test/render3/query_spec.ts @@ -341,7 +341,7 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - ɵɵelement(0, 'div', null, ['foo', '']); + ɵɵelement(0, 'div', null, 0); elToQuery = getNativeByIndex(0, getLView()); ɵɵelement(2, 'div'); } @@ -356,7 +356,8 @@ describe('query', () => { ɵɵqueryRefresh(tmp = ɵɵloadQuery>()) && (ctx.query = tmp as QueryList); } - }); + }, + [], [], undefined, [['foo', '']]); const cmptInstance = renderComponent(Cmpt); const qList = (cmptInstance.query as QueryList); @@ -379,7 +380,7 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - ɵɵelement(0, 'div', null, ['foo', '', 'bar', '']); + ɵɵelement(0, 'div', null, 0); elToQuery = getNativeByIndex(0, getLView()); ɵɵelement(3, 'div'); } @@ -397,7 +398,8 @@ describe('query', () => { ɵɵqueryRefresh(tmp = ɵɵloadQuery>()) && (ctx.barQuery = tmp as QueryList); } - }); + }, + [], [], undefined, [['foo', '', 'bar', '']]); const cmptInstance = renderComponent(Cmpt); @@ -426,10 +428,10 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - ɵɵelement(0, 'div', null, ['foo', '']); + ɵɵelement(0, 'div', null, 0); el1ToQuery = getNativeByIndex(0, getLView()); ɵɵelement(2, 'div'); - ɵɵelement(3, 'div', null, ['bar', '']); + ɵɵelement(3, 'div', null, 1); el2ToQuery = getNativeByIndex(3, getLView()); } }, @@ -443,7 +445,8 @@ describe('query', () => { ɵɵqueryRefresh(tmp = ɵɵloadQuery>()) && (ctx.query = tmp as QueryList); } - }); + }, + [], [], undefined, [['foo', ''], ['bar', '']]); const cmptInstance = renderComponent(Cmpt); const qList = (cmptInstance.query as QueryList); @@ -466,7 +469,7 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - ɵɵelement(0, 'div', null, ['foo', '']); + ɵɵelement(0, 'div', null, 0); elToQuery = getNativeByIndex(0, getLView()); ɵɵelement(2, 'div'); } @@ -481,7 +484,8 @@ describe('query', () => { ɵɵqueryRefresh(tmp = ɵɵloadQuery>()) && (ctx.query = tmp as QueryList); } - }); + }, + [], [], undefined, [['foo', '']]); const cmptInstance = renderComponent(Cmpt); const qList = (cmptInstance.query as QueryList); @@ -503,7 +507,7 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - ɵɵelementContainerStart(0, null, ['foo', '']); + ɵɵelementContainerStart(0, null, 0); elToQuery = getNativeByIndex(0, getLView()); ɵɵelementContainerEnd(); } @@ -518,7 +522,8 @@ describe('query', () => { ɵɵqueryRefresh(tmp = ɵɵloadQuery>()) && (ctx.query = tmp as QueryList); } - }); + }, + [], [], undefined, [['foo', '']]); const cmptInstance = renderComponent(Cmpt); const qList = (cmptInstance.query as QueryList); @@ -539,7 +544,7 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - ɵɵelementContainerStart(0, null, ['foo', '']); + ɵɵelementContainerStart(0, null, 0); elToQuery = getNativeByIndex(0, getLView()); ɵɵelementContainerEnd(); } @@ -554,7 +559,8 @@ describe('query', () => { ɵɵqueryRefresh(tmp = ɵɵloadQuery>()) && (ctx.query = tmp as QueryList); } - }); + }, + [], [], undefined, [['foo', '']]); const cmptInstance = renderComponent(Cmpt); const qList = (cmptInstance.query as QueryList); @@ -603,7 +609,7 @@ describe('query', () => { if (rf & RenderFlags.Create) { ɵɵelementContainerStart(0); { - ɵɵelement(1, 'div', null, ['foo', '']); + ɵɵelement(1, 'div', null, 0); elToQuery = getNativeByIndex(3, getLView()); } ɵɵelementContainerEnd(); @@ -622,7 +628,8 @@ describe('query', () => { ɵɵqueryRefresh(tmp = ɵɵloadQuery>()) && (ctx.shallow = tmp as QueryList); } - }); + }, + [], [], undefined, [['foo', '']]); const fixture = new ComponentFixture(Cmpt); const deepQList = fixture.component.deep; @@ -642,7 +649,7 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - ɵɵelement(0, 'div', null, ['foo', '']); + ɵɵelement(0, 'div', null, 0); } }, 2, 0, [], [], @@ -655,7 +662,8 @@ describe('query', () => { ɵɵqueryRefresh(tmp = ɵɵloadQuery>()) && (ctx.query = tmp as QueryList); } - }); + }, + [], [], undefined, [['foo', '']]); const cmptInstance = renderComponent(Cmpt); const qList = (cmptInstance.query as QueryList); @@ -674,7 +682,7 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - ɵɵtemplate(0, null, 0, 0, 'ng-template', null, ['foo', '']); + ɵɵtemplate(0, null, 0, 0, 'ng-template', null, 0); } }, 2, 0, [], [], @@ -687,7 +695,8 @@ describe('query', () => { ɵɵqueryRefresh(tmp = ɵɵloadQuery>()) && (ctx.query = tmp as QueryList); } - }); + }, + [], [], undefined, [['foo', '']]); const cmptInstance = renderComponent(Cmpt); const qList = (cmptInstance.query as QueryList); @@ -707,7 +716,7 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - ɵɵtemplate(0, null, 0, 0, 'ng-template', null, ['foo', '']); + ɵɵtemplate(0, null, 0, 0, 'ng-template', null, 0); } }, 2, 0, [], [], @@ -721,7 +730,8 @@ describe('query', () => { ɵɵqueryRefresh(tmp = ɵɵloadQuery>()) && (ctx.query = tmp as QueryList); } - }); + }, + [], [], undefined, [['foo', '']]); const cmptInstance = renderComponent(Cmpt); const qList = (cmptInstance.query as QueryList); @@ -742,7 +752,7 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - ɵɵtemplate(0, null, 0, 0, 'ng-template', null, ['foo', '']); + ɵɵtemplate(0, null, 0, 0, 'ng-template', null, 0); } }, 2, 0, [], [], @@ -755,7 +765,8 @@ describe('query', () => { ɵɵqueryRefresh(tmp = ɵɵloadQuery>()) && (ctx.query = tmp as QueryList); } - }); + }, + [], [], undefined, [['foo', '']]); const cmptInstance = renderComponent(Cmpt); const qList = (cmptInstance.query as QueryList); @@ -775,7 +786,7 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - ɵɵtemplate(0, null, 0, 0, 'ng-template', null, ['foo', '']); + ɵɵtemplate(0, null, 0, 0, 'ng-template', null, 0); } }, 2, 0, [], [], @@ -788,7 +799,8 @@ describe('query', () => { ɵɵqueryRefresh(tmp = ɵɵloadQuery>()) && (ctx.query = tmp as QueryList); } - }); + }, + [], [], undefined, [['foo', '']]); const cmptInstance = renderComponent(Cmpt); const qList = (cmptInstance.query as QueryList); @@ -810,7 +822,7 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - ɵɵelement(0, 'child', null, ['foo', '']); + ɵɵelement(0, 'child', null, 0); } if (rf & RenderFlags.Update) { childInstance = getDirectiveOnNode(0); @@ -826,7 +838,8 @@ describe('query', () => { ɵɵqueryRefresh(tmp = ɵɵloadQuery>()) && (ctx.query = tmp as QueryList); } - }); + }, + [], [], undefined, [['foo', '']]); const cmptInstance = renderComponent(Cmpt); const qList = (cmptInstance.query as QueryList); @@ -859,7 +872,7 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - ɵɵelement(0, 'child', null, ['foo', 'child']); + ɵɵelement(0, 'child', null, 0); } }, 2, 0, [Child], [], @@ -872,7 +885,8 @@ describe('query', () => { ɵɵqueryRefresh(tmp = ɵɵloadQuery>()) && (ctx.query = tmp as QueryList); } - }); + }, + [], [], undefined, [['foo', 'child']]); const cmptInstance = renderComponent(Cmpt); const qList = (cmptInstance.query as QueryList); @@ -895,7 +909,7 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - ɵɵelement(0, 'div', 0, ['foo', 'child']); + ɵɵelement(0, 'div', 0, 1); } if (rf & RenderFlags.Update) { childInstance = getDirectiveOnNode(0); @@ -912,7 +926,7 @@ describe('query', () => { (ctx.query = tmp as QueryList); } }, - [], [], undefined, [['child', '']]); + [], [], undefined, [['child', ''], ['foo', 'child']]); const cmptInstance = renderComponent(Cmpt); const qList = (cmptInstance.query as QueryList); @@ -935,7 +949,7 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - ɵɵelement(0, 'div', 0, ['foo', 'child1', 'bar', 'child2']); + ɵɵelement(0, 'div', 0, 1); } if (rf & RenderFlags.Update) { child1Instance = getDirectiveOnNode(0, 0); @@ -953,7 +967,7 @@ describe('query', () => { (ctx.query = tmp as QueryList); } }, - [], [], undefined, [['child1', '', 'child2', '']]); + [], [], undefined, [['child1', '', 'child2', ''], ['foo', 'child1', 'bar', 'child2']]); const cmptInstance = renderComponent(Cmpt); const qList = (cmptInstance.query as QueryList); @@ -977,7 +991,7 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - ɵɵelement(0, 'div', 0, ['foo', 'child', 'bar', 'child']); + ɵɵelement(0, 'div', 0, 1); } if (rf & RenderFlags.Update) { childInstance = getDirectiveOnNode(0); @@ -997,7 +1011,7 @@ describe('query', () => { (ctx.barQuery = tmp as QueryList); } }, - [], [], undefined, [['child', '']]); + [], [], undefined, [['child', ''], ['foo', 'child', 'bar', 'child']]); const cmptInstance = renderComponent(Cmpt); @@ -1024,7 +1038,7 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - ɵɵelement(0, 'div', 0, ['foo', 'child']); + ɵɵelement(0, 'div', 0, 1); div = getNativeByIndex(0, getLView()); } }, @@ -1039,7 +1053,7 @@ describe('query', () => { (ctx.query = tmp as QueryList); } }, - [], [], undefined, [['child', '']]); + [], [], undefined, [['child', ''], ['foo', 'child']]); const cmptInstance = renderComponent(Cmpt); const qList = (cmptInstance.query as QueryList); @@ -1061,7 +1075,7 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - ɵɵelement(0, 'div', 0, ['foo', '', 'bar', 'child']); + ɵɵelement(0, 'div', 0, 1); div = getNativeByIndex(0, getLView()); } if (rf & RenderFlags.Update) { @@ -1079,7 +1093,7 @@ describe('query', () => { (ctx.query = tmp as QueryList); } }, - [], [], undefined, [['child', '']]); + [], [], undefined, [['child', ''], ['foo', '', 'bar', 'child']]); const cmptInstance = renderComponent(Cmpt); const qList = (cmptInstance.query as QueryList); @@ -1236,7 +1250,7 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - ɵɵelement(0, 'div', 0, ['foo', '']); + ɵɵelement(0, 'div', 0, 1); } }, 2, 0, [Child], [], @@ -1250,7 +1264,7 @@ describe('query', () => { (ctx.query = tmp as QueryList); } }, - [], [], undefined, [['child', '']]); + [], [], undefined, [['child', ''], ['foo', '']]); const {component} = new ComponentFixture(Cmpt); const qList = component.query; @@ -1314,14 +1328,11 @@ describe('query', () => { function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { ɵɵtemplate( - 0, Cmpt_Template_1, 2, 0, 'ng-template', null, ['foo', ''], - ɵɵtemplateRefExtractor); + 0, Cmpt_Template_1, 2, 0, 'ng-template', null, 0, ɵɵtemplateRefExtractor); ɵɵtemplate( - 2, Cmpt_Template_1, 2, 0, 'ng-template', null, ['bar', ''], - ɵɵtemplateRefExtractor); + 2, Cmpt_Template_1, 2, 0, 'ng-template', null, 1, ɵɵtemplateRefExtractor); ɵɵtemplate( - 4, Cmpt_Template_1, 2, 0, 'ng-template', null, ['baz', ''], - ɵɵtemplateRefExtractor); + 4, Cmpt_Template_1, 2, 0, 'ng-template', null, 2, ɵɵtemplateRefExtractor); } }, 6, 0, [], [], @@ -1337,7 +1348,8 @@ describe('query', () => { ɵɵqueryRefresh(tmp = ɵɵloadQuery>()) && (ctx.elemQuery = tmp as QueryList); } - }); + }, + [], [], undefined, [['foo', ''], ['bar', ''], ['baz', '']]); const {component} = new ComponentFixture(Cmpt); @@ -1363,7 +1375,7 @@ describe('query', () => { 'some-component-with-query', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - ɵɵelement(0, 'div', null, ['foo', '']); + ɵɵelement(0, 'div', null, 0); } }, 2, 0, [], [], @@ -1376,7 +1388,8 @@ describe('query', () => { ɵɵqueryRefresh(tmp = ɵɵloadQuery>()) && (ctx.query = queryInstance = tmp as QueryList); } - }); + }, + [], [], undefined, [['foo', '']]); function createTemplate() { ɵɵcontainer(0); } @@ -1444,7 +1457,7 @@ describe('query', () => { function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { ɵɵtemplate(0, AppComponent_Template_1, 1, 0, 'div', 0); - ɵɵelement(1, 'div', null, ['foo', '']); + ɵɵelement(1, 'div', null, 1); } }, 3, 0, [SomeDir], [], @@ -1458,7 +1471,7 @@ describe('query', () => { (ctx.query = tmp as QueryList); } }, - [], [], undefined, [[AttributeMarker.Template, 'someDir']]); + [], [], undefined, [[AttributeMarker.Template, 'someDir'], ['foo', '']]); const fixture = new ComponentFixture(AppComponent); expect(fixture.component.query.length).toBe(1); @@ -1508,12 +1521,12 @@ describe('query', () => { function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { ɵɵelementStart(0, 'div', 0); - { ɵɵelement(1, 'span', null, ['foo', '']); } + { ɵɵelement(1, 'span', null, 1); } ɵɵelementEnd(); } }, 3, 0, [WithContentDirective], [], null, [], [], undefined, - [[AttributeMarker.Bindings, 'with-content']]); + [[AttributeMarker.Bindings, 'with-content'], ['foo', '']]); const fixture = new ComponentFixture(AppComponent); expect(withContentInstance !.foos.length) @@ -1551,7 +1564,7 @@ describe('query', () => { let rf = ɵɵembeddedViewStart(1, 3, 0); if (rf & RenderFlags.Create) { ɵɵelementStart(0, 'div', 0); - { ɵɵelement(1, 'span', null, ['foo', '']); } + { ɵɵelement(1, 'span', null, 1); } ɵɵelementEnd(); } ɵɵembeddedViewEnd(); @@ -1562,7 +1575,7 @@ describe('query', () => { } }, 1, 0, [WithContentDirective], [], null, [], [], undefined, - [[AttributeMarker.Bindings, 'with-content']]); + [[AttributeMarker.Bindings, 'with-content'], ['foo', '']]); const fixture = new ComponentFixture(AppComponent); expect(withContentInstance !.foos.length) @@ -1584,11 +1597,15 @@ describe('query', () => { *
*
*/ - const AppComponent = createComponent('app-component', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'div', 0, ['foo', '']); - } - }, 2, 0, [WithContentDirective], [], null, [], [], undefined, [['with-content', '']]); + const AppComponent = createComponent( + 'app-component', + function(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + ɵɵelement(0, 'div', 0, 1); + } + }, + 2, 0, [WithContentDirective], [], null, [], [], undefined, + [['with-content', ''], ['foo', '']]); const fixture = new ComponentFixture(AppComponent); expect(withContentInstance !.foos.length) @@ -1611,9 +1628,9 @@ describe('query', () => { function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { ɵɵelementStart(0, 'div', 0); - { ɵɵelement(1, 'div', null, ['foo', '']); } + { ɵɵelement(1, 'div', null, 2); } ɵɵelementEnd(); - ɵɵelement(3, 'div', 1, ['bar', '']); + ɵɵelement(3, 'div', 1, 3); } }, 5, 0, [WithContentDirective], [], @@ -1627,7 +1644,7 @@ describe('query', () => { (ctx.foos = tmp as QueryList); } }, - [], [], undefined, [['with-content', ''], ['id', 'after']]); + [], [], undefined, [['with-content', ''], ['id', 'after'], ['foo', ''], ['bar', '']]); const fixture = new ComponentFixture(AppComponent); const viewQList = fixture.component.foos; @@ -1653,9 +1670,9 @@ describe('query', () => { function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { ɵɵelementStart(0, 'div', 0); - { ɵɵelement(1, 'div', 1, ['foo', '']); } + { ɵɵelement(1, 'div', 1, 2); } ɵɵelementEnd(); - ɵɵelement(3, 'div', null, ['foo', '']); + ɵɵelement(3, 'div', null, 2); } }, 5, 0, [WithContentDirective], [], @@ -1669,7 +1686,7 @@ describe('query', () => { (ctx.bars = tmp as QueryList); } }, - [], [], undefined, [['with-content', ''], ['id', 'yes']]); + [], [], undefined, [['with-content', ''], ['id', 'yes'], ['foo', '']]); const fixture = new ComponentFixture(AppComponent); expect(withContentInstance !.foos.length).toBe(1); @@ -1714,13 +1731,13 @@ describe('query', () => { */ function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'div', 0, ['out', 'query']); + ɵɵelementStart(0, 'div', 0, 4); { - ɵɵelement(2, 'span', 1, ['foo', '']); - ɵɵelementStart(4, 'div', 0, ['in', 'query']); - { ɵɵelement(6, 'span', 2, ['bar', '']); } + ɵɵelement(2, 'span', 1, 5); + ɵɵelementStart(4, 'div', 0, 6); + { ɵɵelement(6, 'span', 2, 7); } ɵɵelementEnd(); - ɵɵelement(8, 'span', 3, ['baz', '']); + ɵɵelement(8, 'span', 3, 8); } ɵɵelementEnd(); } @@ -1730,8 +1747,10 @@ describe('query', () => { inInstance = load(lView, 5); } }, - 10, 0, [QueryDirective], [], null, [], [], undefined, - [[AttributeMarker.Bindings, 'query'], ['id', 'foo'], ['id', 'bar'], ['id', 'baz']]); + 10, 0, [QueryDirective], [], null, [], [], undefined, [ + [AttributeMarker.Bindings, 'query'], ['id', 'foo'], ['id', 'bar'], ['id', 'baz'], + ['out', 'query'], ['foo', ''], ['in', 'query'], ['bar', ''], ['baz', ''] + ]); const fixture = new ComponentFixture(AppComponent); expect(outInstance !.fooBars.length).toBe(3); @@ -1775,10 +1794,10 @@ describe('query', () => { */ function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'div', 0, ['out', 'query']); + ɵɵelementStart(0, 'div', 0, 2); { - ɵɵelementStart(2, 'div', 0, ['in', 'query', 'foo', '']); - { ɵɵelement(5, 'span', 1, ['foo', '']); } + ɵɵelementStart(2, 'div', 0, 3); + { ɵɵelement(5, 'span', 1, 4); } ɵɵelementEnd(); } ɵɵelementEnd(); @@ -1789,7 +1808,10 @@ describe('query', () => { inInstance = load(lView, 3); } }, - 7, 0, [QueryDirective], [], null, [], [], undefined, [['query', ''], ['id', 'bar']]); + 7, 0, [QueryDirective], [], null, [], [], undefined, [ + ['query', ''], ['id', 'bar'], ['out', 'query'], ['in', 'query', 'foo', ''], + ['foo', ''] + ]); const fixture = new ComponentFixture(AppComponent); expect(outInstance !.fooBars.length).toBe(1); @@ -1832,10 +1854,10 @@ describe('query', () => { */ function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'div', 0, ['out', 'query']); + ɵɵelementStart(0, 'div', 0, 2); { - ɵɵelementStart(2, 'div', 0, ['in', 'query', 'foo', '']); - { ɵɵelement(5, 'span', 1, ['foo', '']); } + ɵɵelementStart(2, 'div', 0, 3); + { ɵɵelement(5, 'span', 1, 4); } ɵɵelementEnd(); } ɵɵelementEnd(); @@ -1846,7 +1868,10 @@ describe('query', () => { inInstance = load(lView, 3); } }, - 7, 0, [QueryDirective], [], null, [], [], undefined, [['query', ''], ['id', 'bar']]); + 7, 0, [QueryDirective], [], null, [], [], undefined, [ + ['query', ''], ['id', 'bar'], ['out', 'query'], ['in', 'query', 'foo', ''], + ['foo', ''] + ]); const fixture1 = new ComponentFixture(AppComponent); expect(outInstance !.fooBars.length).toBe(1); @@ -1918,11 +1943,11 @@ describe('query', () => { */ function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'div', 0, ['shallow', 'shallow-query', 'deep', 'deep-query']); + ɵɵelementStart(0, 'div', 0, 1); { - ɵɵelement(3, 'span', null, ['foo', '']); + ɵɵelement(3, 'span', null, 2); ɵɵelementStart(5, 'div'); - { ɵɵelement(6, 'span', null, ['foo', '']); } + { ɵɵelement(6, 'span', null, 2); } ɵɵelementEnd(); } ɵɵelementEnd(); @@ -1933,8 +1958,10 @@ describe('query', () => { deepInstance = load(lView, 2); } }, - 8, 0, [ShallowQueryDirective, DeepQueryDirective], [], null, [], [], undefined, - [[AttributeMarker.Bindings, 'shallow-query', 'deep-query']]); + 8, 0, [ShallowQueryDirective, DeepQueryDirective], [], null, [], [], undefined, [ + [AttributeMarker.Bindings, 'shallow-query', 'deep-query'], + ['shallow', 'shallow-query', 'deep', 'deep-query'], ['foo', ''] + ]); const fixture = new ComponentFixture(AppComponent); expect(shallowInstance !.foos.length).toBe(1); diff --git a/packages/core/test/render3/render_util.ts b/packages/core/test/render3/render_util.ts index 6f34eb2b46e65..3cc290343c2d8 100644 --- a/packages/core/test/render3/render_util.ts +++ b/packages/core/test/render3/render_util.ts @@ -13,7 +13,7 @@ import {TemplateRef} from '@angular/core/src/linker/template_ref'; import {ViewContainerRef} from '@angular/core/src/linker/view_container_ref'; import {Renderer2} from '@angular/core/src/render/api'; import {createLView, createTView, getOrCreateTNode, getOrCreateTView, renderComponentOrTemplate} from '@angular/core/src/render3/instructions/shared'; -import {TAttributes, TNodeType} from '@angular/core/src/render3/interfaces/node'; +import {TAttributes, TConstants, TNodeType} from '@angular/core/src/render3/interfaces/node'; import {enterView, getLView} from '@angular/core/src/render3/state'; import {stringifyElement} from '@angular/platform-browser/testing/src/browser_util'; @@ -103,7 +103,7 @@ export class TemplateFixture extends BaseFixture { private createBlock: () => void, private updateBlock: () => void = noop, decls: number = 0, private vars: number = 0, directives?: DirectiveTypesOrFactory|null, pipes?: PipeTypesOrFactory|null, sanitizer?: Sanitizer|null, - rendererFactory?: RendererFactory3, private _consts?: TAttributes[]) { + rendererFactory?: RendererFactory3, private _consts?: TConstants) { super(); this._directiveDefs = toDefs(directives, extractDirectiveDef); this._pipeDefs = toDefs(pipes, extractPipeDef); @@ -249,7 +249,7 @@ export function renderTemplate( hostNode: RElement, templateFn: ComponentTemplate, decls: number, vars: number, context: T, providedRendererFactory: RendererFactory3, componentView: LView | null, directives?: DirectiveDefListOrFactory | null, pipes?: PipeDefListOrFactory | null, - sanitizer?: Sanitizer | null, consts?: TAttributes[]): LView { + sanitizer?: Sanitizer | null, consts?: TConstants): LView { if (componentView === null) { const renderer = providedRendererFactory.createRenderer(null, null); @@ -288,8 +288,7 @@ export function renderTemplate( export function renderToHtml( template: ComponentTemplate, ctx: any, decls: number = 0, vars: number = 0, directives?: DirectiveTypesOrFactory | null, pipes?: PipeTypesOrFactory | null, - providedRendererFactory?: RendererFactory3 | null, keepNgReflect = false, - consts?: TAttributes[]) { + providedRendererFactory?: RendererFactory3 | null, keepNgReflect = false, consts?: TConstants) { hostView = renderTemplate( containerEl, template, decls, vars, ctx, providedRendererFactory || testRendererFactory, hostView, toDefs(directives, extractDirectiveDef), toDefs(pipes, extractPipeDef), null, @@ -369,7 +368,7 @@ export function createComponent( directives: DirectiveTypesOrFactory = [], pipes: PipeTypesOrFactory = [], viewQuery: ComponentTemplate| null = null, providers: Provider[] = [], viewProviders: Provider[] = [], hostBindings?: HostBindingsFunction, - consts: TAttributes[] = []): ComponentType { + consts: TConstants = []): ComponentType { return class Component { value: any; static ɵfac = () => new Component; diff --git a/packages/core/test/render3/view_container_ref_spec.ts b/packages/core/test/render3/view_container_ref_spec.ts index cec46e00c68ff..27ab15e59ab66 100644 --- a/packages/core/test/render3/view_container_ref_spec.ts +++ b/packages/core/test/render3/view_container_ref_spec.ts @@ -441,10 +441,10 @@ describe('ViewContainerRef', () => { selectors: [['dynamic-cmpt-with-view-queries']], decls: 2, vars: 0, - consts: [['bar', '']], + consts: [['foo', ''], ['bar', '']], template: (rf: RenderFlags, ctx: DynamicCompWithViewQueries) => { if (rf & RenderFlags.Create) { - ɵɵelement(0, 'div', 0, ['foo', '']); + ɵɵelement(0, 'div', 1, 0); } // testing only fooEl = getNativeByIndex(0, getLView()) as RElement; diff --git a/tools/public_api_guard/core/core.d.ts b/tools/public_api_guard/core/core.d.ts index fe70ea1d1230f..a538b26944984 100644 --- a/tools/public_api_guard/core/core.d.ts +++ b/tools/public_api_guard/core/core.d.ts @@ -760,7 +760,7 @@ export declare function ɵɵdefineComponent(componentDefinition: { contentQueries?: ContentQueriesFunction; exportAs?: string[]; template: ComponentTemplate; - consts?: TAttributes[]; + consts?: TConstants; ngContentSelectors?: string[]; viewQuery?: ViewQueriesFunction | null; features?: ComponentDefFeature[]; @@ -826,19 +826,19 @@ export declare function ɵɵdirectiveInject(token: Type | InjectionToken | null, decls: number, vars: number, tagName?: string | null, constsIndex?: number | null, localRefs?: string[] | null, localRefExtractor?: LocalRefExtractor): void; +export declare function ɵɵtemplate(index: number, templateFn: ComponentTemplate | null, decls: number, vars: number, tagName?: string | null, attrsIndex?: number | null, localRefsIndex?: number | null, localRefExtractor?: LocalRefExtractor): void; export declare function ɵɵtemplateRefExtractor(tNode: TNode, currentView: LView): ViewEngine_TemplateRef | null;