feat(ivy): add element instruction (#23899)
Adds a simplified element instruction that can be used if an element has no children. PR Close #23899
This commit is contained in:
@ -17,10 +17,12 @@ export class Identifiers {
|
||||
static PATCH_DEPS = 'patchedDeps';
|
||||
|
||||
/* Instructions */
|
||||
static createElement: o.ExternalReference = {name: 'ɵE', moduleName: CORE};
|
||||
static elementStart: o.ExternalReference = {name: 'ɵE', moduleName: CORE};
|
||||
|
||||
static elementEnd: o.ExternalReference = {name: 'ɵe', moduleName: CORE};
|
||||
|
||||
static element: o.ExternalReference = {name: 'ɵEe', moduleName: CORE};
|
||||
|
||||
static elementProperty: o.ExternalReference = {name: 'ɵp', moduleName: CORE};
|
||||
|
||||
static elementAttribute: o.ExternalReference = {name: 'ɵa', moduleName: CORE};
|
||||
|
@ -314,32 +314,42 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||
if (i18nMessages.length > 0) {
|
||||
this._creationCode.push(...i18nMessages);
|
||||
}
|
||||
this.instruction(
|
||||
this._creationCode, element.sourceSpan, R3.createElement, ...trimTrailingNulls(parameters));
|
||||
|
||||
let isSelfClosingElement = element.outputs.length === 0 && element.children.length === 0;
|
||||
|
||||
|
||||
const implicit = o.variable(CONTEXT_NAME);
|
||||
|
||||
// Generate Listeners (outputs)
|
||||
element.outputs.forEach((outputAst: t.BoundEvent) => {
|
||||
const elName = sanitizeIdentifier(element.name);
|
||||
const evName = sanitizeIdentifier(outputAst.name);
|
||||
const functionName = `${this.templateName}_${elName}_${evName}_listener`;
|
||||
const localVars: o.Statement[] = [];
|
||||
const bindingScope =
|
||||
this._bindingScope.nestedScope((lhsVar: o.ReadVarExpr, rhsExpression: o.Expression) => {
|
||||
localVars.push(
|
||||
lhsVar.set(rhsExpression).toDeclStmt(o.INFERRED_TYPE, [o.StmtModifier.Final]));
|
||||
});
|
||||
const bindingExpr = convertActionBinding(
|
||||
bindingScope, implicit, outputAst.handler, 'b', () => error('Unexpected interpolation'));
|
||||
const handler = o.fn(
|
||||
[new o.FnParam('$event', o.DYNAMIC_TYPE)], [...localVars, ...bindingExpr.render3Stmts],
|
||||
o.INFERRED_TYPE, null, functionName);
|
||||
if (isSelfClosingElement) {
|
||||
this.instruction(
|
||||
this._creationCode, outputAst.sourceSpan, R3.listener, o.literal(outputAst.name),
|
||||
handler);
|
||||
});
|
||||
this._creationCode, element.sourceSpan, R3.element, ...trimTrailingNulls(parameters));
|
||||
} else {
|
||||
this.instruction(
|
||||
this._creationCode, element.sourceSpan, R3.elementStart,
|
||||
...trimTrailingNulls(parameters));
|
||||
|
||||
// Generate Listeners (outputs)
|
||||
element.outputs.forEach((outputAst: t.BoundEvent) => {
|
||||
const elName = sanitizeIdentifier(element.name);
|
||||
const evName = sanitizeIdentifier(outputAst.name);
|
||||
const functionName = `${this.templateName}_${elName}_${evName}_listener`;
|
||||
const localVars: o.Statement[] = [];
|
||||
const bindingScope =
|
||||
this._bindingScope.nestedScope((lhsVar: o.ReadVarExpr, rhsExpression: o.Expression) => {
|
||||
localVars.push(
|
||||
lhsVar.set(rhsExpression).toDeclStmt(o.INFERRED_TYPE, [o.StmtModifier.Final]));
|
||||
});
|
||||
const bindingExpr = convertActionBinding(
|
||||
bindingScope, implicit, outputAst.handler, 'b',
|
||||
() => error('Unexpected interpolation'));
|
||||
const handler = o.fn(
|
||||
[new o.FnParam('$event', o.DYNAMIC_TYPE)], [...localVars, ...bindingExpr.render3Stmts],
|
||||
o.INFERRED_TYPE, null, functionName);
|
||||
this.instruction(
|
||||
this._creationCode, outputAst.sourceSpan, R3.listener, o.literal(outputAst.name),
|
||||
handler);
|
||||
});
|
||||
}
|
||||
|
||||
// Generate element input bindings
|
||||
element.inputs.forEach((input: t.BoundAttribute) => {
|
||||
@ -367,10 +377,11 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||
t.visitAll(this, element.children);
|
||||
}
|
||||
|
||||
// Finish element construction mode.
|
||||
this.instruction(
|
||||
this._creationCode, element.endSourceSpan || element.sourceSpan, R3.elementEnd);
|
||||
|
||||
if (!isSelfClosingElement) {
|
||||
// Finish element construction mode.
|
||||
this.instruction(
|
||||
this._creationCode, element.endSourceSpan || element.sourceSpan, R3.elementEnd);
|
||||
}
|
||||
// Restore the state before exiting this node
|
||||
this._inI18nSection = wasInI18nSection;
|
||||
}
|
||||
|
@ -90,8 +90,7 @@ describe('compiler compliance', () => {
|
||||
const template = `
|
||||
template: function MyComponent_Template(rf: IDENT, ctx: IDENT) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵE(0, 'div');
|
||||
$r3$.ɵe();
|
||||
$r3$.ɵEe(0, 'div');
|
||||
}
|
||||
if (rf & 2) {
|
||||
$r3$.ɵp(0, 'id', $r3$.ɵb(ctx.id));
|
||||
@ -135,9 +134,8 @@ describe('compiler compliance', () => {
|
||||
const template = `
|
||||
template: function MyComponent_Template(rf: IDENT, ctx: IDENT) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵE(0, 'div');
|
||||
$r3$.ɵEe(0, 'div');
|
||||
$r3$.ɵPp(1,'pipe');
|
||||
$r3$.ɵe();
|
||||
$r3$.ɵrS(10);
|
||||
}
|
||||
if (rf & 2) {
|
||||
@ -181,8 +179,7 @@ describe('compiler compliance', () => {
|
||||
const template = `
|
||||
template: function MyComponent_Template(rf: IDENT, ctx: IDENT) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵE(0, 'div');
|
||||
$r3$.ɵe();
|
||||
$r3$.ɵEe(0, 'div');
|
||||
}
|
||||
if (rf & 2) {
|
||||
$r3$.ɵkn(0, 'error', $r3$.ɵb(ctx.error));
|
||||
@ -254,8 +251,7 @@ describe('compiler compliance', () => {
|
||||
factory: function MyComponent_Factory() { return new MyComponent(); },
|
||||
template: function MyComponent_Template(rf: IDENT, ctx: IDENT) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵE(0, 'child', $c1$);
|
||||
$r3$.ɵe();
|
||||
$r3$.ɵEe(0, 'child', $c1$);
|
||||
$r3$.ɵT(1, '!');
|
||||
}
|
||||
},
|
||||
@ -461,8 +457,7 @@ describe('compiler compliance', () => {
|
||||
factory: function MyApp_Factory() { return new MyApp(); },
|
||||
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵE(0, 'my-comp');
|
||||
$r3$.ɵe();
|
||||
$r3$.ɵEe(0, 'my-comp');
|
||||
$r3$.ɵrS(2);
|
||||
}
|
||||
if (rf & 2) {
|
||||
@ -541,8 +536,7 @@ describe('compiler compliance', () => {
|
||||
factory: function MyApp_Factory() { return new MyApp(); },
|
||||
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵE(0, 'my-comp');
|
||||
$r3$.ɵe();
|
||||
$r3$.ɵEe(0, 'my-comp');
|
||||
$r3$.ɵrS(10);
|
||||
}
|
||||
if (rf & 2) {
|
||||
@ -603,8 +597,7 @@ describe('compiler compliance', () => {
|
||||
factory: function MyApp_Factory() { return new MyApp(); },
|
||||
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵE(0, 'object-comp');
|
||||
$r3$.ɵe();
|
||||
$r3$.ɵEe(0, 'object-comp');
|
||||
$r3$.ɵrS(2);
|
||||
}
|
||||
if (rf & 2) {
|
||||
@ -669,8 +662,7 @@ describe('compiler compliance', () => {
|
||||
factory: function MyApp_Factory() { return new MyApp(); },
|
||||
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵE(0, 'nested-comp');
|
||||
$r3$.ɵe();
|
||||
$r3$.ɵEe(0, 'nested-comp');
|
||||
$r3$.ɵrS(7);
|
||||
}
|
||||
if (rf & 2) {
|
||||
@ -814,8 +806,7 @@ describe('compiler compliance', () => {
|
||||
var $tmp$: $any$;
|
||||
if (rf & 1) {
|
||||
$r3$.ɵQ(0, SomeDirective, true);
|
||||
$r3$.ɵE(1, 'div', $e0_attrs$);
|
||||
$r3$.ɵe();
|
||||
$r3$.ɵEe(1, 'div', $e0_attrs$);
|
||||
}
|
||||
if (rf & 2) {
|
||||
($r3$.ɵqR(($tmp$ = $r3$.ɵld(0))) && (ctx.someDir = $tmp$.first));
|
||||
@ -1009,8 +1000,7 @@ describe('compiler compliance', () => {
|
||||
factory: function MyComponent_Factory() { return new MyComponent(); },
|
||||
template: function MyComponent_Template(rf: IDENT, ctx: IDENT) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵE(0, 'input', null, $c1$);
|
||||
$r3$.ɵe();
|
||||
$r3$.ɵEe(0, 'input', null, $c1$);
|
||||
$r3$.ɵT(2);
|
||||
}
|
||||
const $user$ = $r3$.ɵld(1);
|
||||
@ -1089,10 +1079,8 @@ describe('compiler compliance', () => {
|
||||
factory: function SimpleLayout_Factory() { return new SimpleLayout(); },
|
||||
template: function SimpleLayout_Template(rf: IDENT, ctx: IDENT) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵE(0, 'lifecycle-comp');
|
||||
$r3$.ɵe();
|
||||
$r3$.ɵE(1, 'lifecycle-comp');
|
||||
$r3$.ɵe();
|
||||
$r3$.ɵEe(0, 'lifecycle-comp');
|
||||
$r3$.ɵEe(1, 'lifecycle-comp');
|
||||
}
|
||||
if (rf & 2) {
|
||||
$r3$.ɵp(0, 'name', $r3$.ɵb(ctx.name1));
|
||||
|
@ -75,8 +75,7 @@ describe('compiler compliance: bindings', () => {
|
||||
const template = `
|
||||
template:function MyComponent_Template(rf: IDENT, $ctx$: IDENT){
|
||||
if (rf & 1) {
|
||||
$i0$.ɵE(0, 'a');
|
||||
$i0$.ɵe();
|
||||
$i0$.ɵEe(0, 'a');
|
||||
}
|
||||
if (rf & 2) {
|
||||
$i0$.ɵp(0, 'title', $i0$.ɵb($ctx$.title));
|
||||
@ -108,8 +107,7 @@ describe('compiler compliance: bindings', () => {
|
||||
const template = `
|
||||
template:function MyComponent_Template(rf: IDENT, $ctx$: IDENT){
|
||||
if (rf & 1) {
|
||||
$i0$.ɵE(0, 'a');
|
||||
$i0$.ɵe();
|
||||
$i0$.ɵEe(0, 'a');
|
||||
}
|
||||
if (rf & 2) {
|
||||
$i0$.ɵp(0, 'title', $i0$.ɵi1('Hello ', $ctx$.name, ''));
|
||||
|
@ -148,8 +148,7 @@ describe('i18n support in the view compiler', () => {
|
||||
…
|
||||
template: function MyComponent_Template(rf: IDENT, ctx: IDENT) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵE(0, 'div', $c1$);
|
||||
$r3$.ɵe();
|
||||
$r3$.ɵEe(0, 'div', $c1$);
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
@ -109,4 +109,43 @@ describe('compiler compliance: template', () => {
|
||||
expectEmit(result.source, template, 'Incorrect template');
|
||||
});
|
||||
|
||||
// tslint:disable-next-line:ban
|
||||
describe('element with no children', () => {
|
||||
it('should just use the element instruction', () => {
|
||||
const files = {
|
||||
app: {
|
||||
'spec.ts': `
|
||||
import {Component, NgModule} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: \`
|
||||
<div></div>\`
|
||||
})
|
||||
export class MyComponent {
|
||||
}
|
||||
|
||||
@NgModule({declarations: [MyComponent], imports: [CommonModule]})
|
||||
export class MyModule {}
|
||||
`
|
||||
}
|
||||
};
|
||||
|
||||
const template = `
|
||||
// ...
|
||||
template:function MyComponent_Template(rf: IDENT, $ctx$: IDENT){
|
||||
if (rf & 1) {
|
||||
$i0$.ɵEe(0,'div');
|
||||
}
|
||||
}`;
|
||||
|
||||
debugger;
|
||||
|
||||
const result = compile(files, angularFiles);
|
||||
|
||||
expectEmit(result.source, template, 'Incorrect template');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
Reference in New Issue
Block a user