refactor(compiler): Allow collapsing i18n start/end ops that contain a pipe (#51876)

Moves the empty element phase earlier, to before pipe creation. This
ensures that adjacent i18nStart/i18nEnd ops will be collapsed into a
isingle i18n op, rather than remaining uncollapsed if a pipe is inserted
between them.

PR Close #51876
This commit is contained in:
Miles Malerba 2023-09-20 09:16:03 -07:00 committed by Alex Rickabaugh
parent 5ba9093c45
commit e79fc02a2a
6 changed files with 17 additions and 9 deletions

View file

@ -80,10 +80,11 @@ const phases: Phase[] = [
{kind: Kind.Tmpl, fn: phaseRemoveEmptyBindings},
{kind: Kind.Tmpl, fn: phaseConditionals},
{kind: Kind.Tmpl, fn: phaseNoListenersOnTemplates},
{kind: Kind.Tmpl, fn: phaseGenerateProjectionDef},
{kind: Kind.Tmpl, fn: phaseEmptyElements},
{kind: Kind.Tmpl, fn: phasePipeCreation},
{kind: Kind.Tmpl, fn: phasePipeVariadic},
{kind: Kind.Both, fn: phasePureLiteralStructures},
{kind: Kind.Tmpl, fn: phaseGenerateProjectionDef},
{kind: Kind.Tmpl, fn: phaseGenerateVariables},
{kind: Kind.Tmpl, fn: phaseSaveRestoreView},
{kind: Kind.Tmpl, fn: phaseFindAnyCasts},
@ -106,7 +107,6 @@ const phases: Phase[] = [
{kind: Kind.Both, fn: phaseNaming},
{kind: Kind.Tmpl, fn: phaseMergeNextContext},
{kind: Kind.Tmpl, fn: phaseNgContainer},
{kind: Kind.Tmpl, fn: phaseEmptyElements},
{kind: Kind.Tmpl, fn: phaseNonbindable},
{kind: Kind.Both, fn: phasePureFunctionExtraction},
{kind: Kind.Tmpl, fn: phaseAlignPipeVariadicVarOffset},

View file

@ -203,8 +203,8 @@ export function i18nStart(slot: number, constIndex: number): ir.CreateOp {
return call(Identifiers.i18nStart, [o.literal(slot), o.literal(constIndex)], null);
}
export function i18n(slot: number): ir.CreateOp {
return call(Identifiers.i18n, [o.literal(slot)], null);
export function i18n(slot: number, constIndex: number): ir.CreateOp {
return call(Identifiers.i18n, [o.literal(slot), o.literal(constIndex)], null);
}
export function i18nEnd(): ir.CreateOp {

View file

@ -7,7 +7,7 @@
*/
import * as ir from '../../ir';
import {type CompilationJob, ComponentCompilationJob} from '../compilation';
import {ComponentCompilationJob} from '../compilation';
/**
* Lifts i18n properties into the consts array.
@ -28,7 +28,8 @@ export function phaseI18nConstCollection(job: ComponentCompilationJob): void {
// Assign const index to i18n ops that messages were extracted from.
for (const unit of job.units) {
for (const op of unit.create) {
if (op.kind === ir.OpKind.I18nStart && messageConstIndices[op.xref] !== undefined) {
if ((op.kind === ir.OpKind.I18nStart || op.kind === ir.OpKind.I18n) &&
messageConstIndices[op.xref] !== undefined) {
op.messageIndex = messageConstIndices[op.xref];
}
}

View file

@ -33,7 +33,8 @@ export function phaseI18nMessageExtraction(job: ComponentCompilationJob): void {
job.relativeContextFilePath.replace(/[^A-Za-z0-9]/g, '_').toUpperCase() + '_';
for (const unit of job.units) {
for (const op of unit.create) {
if (op.kind === ir.OpKind.I18nStart && op.i18n instanceof i18n.Message) {
if ((op.kind === ir.OpKind.I18nStart || op.kind === ir.OpKind.I18n) &&
op.i18n instanceof i18n.Message) {
// Sort the params map to match the ordering in TemplateDefinitionBuilder.
const params = Object.fromEntries(Object.entries(getParams(op)).sort());
@ -134,7 +135,7 @@ function i18nGenerateClosureVar(
/**
* Gets the placeholder values for an i18n block.
*/
function getParams(op: ir.I18nStartOp): {[placeholder: string]: o.Expression} {
function getParams(op: ir.I18nStartOp|ir.I18nOp): {[placeholder: string]: o.Expression} {
const params = op.tagNameParams;
for (const placeholder in (op.i18n as i18n.Message).placeholders) {
if (params[placeholder] === undefined) {

View file

@ -18,6 +18,12 @@ export function phaseNgContainer(job: CompilationJob): void {
for (const unit of job.units) {
const updatedElementXrefs = new Set<ir.XrefId>();
for (const op of unit.create) {
if (op.kind === ir.OpKind.Element && op.tag === CONTAINER_TAG) {
// Transmute the `Element` instruction to `Container`.
(op as ir.Op<ir.CreateOp>).kind = ir.OpKind.Container;
updatedElementXrefs.add(op.xref);
}
if (op.kind === ir.OpKind.ElementStart && op.tag === CONTAINER_TAG) {
// Transmute the `ElementStart` instruction to `ContainerStart`.
(op as ir.Op<ir.CreateOp>).kind = ir.OpKind.ContainerStart;

View file

@ -87,7 +87,7 @@ function reifyCreateOperations(unit: CompilationUnit, ops: ir.OpList<ir.CreateOp
ir.OpList.replace(op, ng.i18nEnd());
break;
case ir.OpKind.I18n:
ir.OpList.replace(op, ng.i18n(op.slot as number));
ir.OpList.replace(op, ng.i18n(op.slot as number, op.messageIndex!));
break;
case ir.OpKind.Template:
if (!(unit instanceof ViewCompilationUnit)) {