fix(core): handle if alias in control flow migration (#52181)

This adds the support of `if ` conditions with `as` clause when migrating to the control flow syntax.
It now adds the required semicolon before the `as` when migrating the template.

Before: `@if (user$ | async as user) {`
After: `@if (user$ | async; as user) {`

PR Close #52181
This commit is contained in:
cexbrayat 2023-10-12 14:48:22 +02:00 committed by Pawel Kozlowski
parent 0881daf690
commit 2003caf4b7
2 changed files with 90 additions and 3 deletions

View file

@ -252,7 +252,9 @@ function migrateNgIf(
function buildIfBlock(
etm: ElementToMigrate, tmpl: string, offset: number): {tmpl: string, offset: number} {
const condition = etm.attr.value;
// includes the mandatory semicolon before as
const condition = etm.attr.value.replace(' as ', '; as ');
const startBlock = `@if (${condition}) {`;
const ifBlock = startBlock + getMainBlock(etm, tmpl, offset) + `}`;
@ -266,7 +268,8 @@ function buildIfBlock(
function buildIfElseBlock(
etm: ElementToMigrate, ngTemplates: Map<string, Template>, tmpl: string, elseString: string,
offset: number): {tmpl: string, offset: number} {
const condition = etm.getCondition(elseString);
// includes the mandatory semicolon before as
const condition = etm.getCondition(elseString).replace(' as ', '; as ');
const elseTmpl = ngTemplates.get(`#${etm.getTemplateName(elseString)}`)!;
const startBlock = `@if (${condition}) {`;
@ -291,7 +294,7 @@ function buildIfElseBlock(
function buildIfThenElseBlock(
etm: ElementToMigrate, ngTemplates: Map<string, Template>, tmpl: string, thenString: string,
elseString: string, offset: number): {tmpl: string, offset: number} {
const condition = etm.getCondition(thenString);
const condition = etm.getCondition(thenString).replace(' as ', '; as ');
const startBlock = `@if (${condition}) {`;
const elseBlock = `} @else {`;

View file

@ -363,6 +363,90 @@ describe('control flow migration', () => {
`<ng-container *ngTemplateOutlet="blockUsedElsewhere"></ng-container>`,
].join('\n'));
});
it('should migrate if with alias', async () => {
writeFile('/comp.ts', `
import {Component} from '@angular/core';
import {NgIf} from '@angular/common';
@Component({
templateUrl: './comp.html'
})
class Comp {
user$ = of({ name: 'Jane' }})
}
`);
writeFile(
'/comp.html', [`<div *ngIf="user$ | async as user">{{ user.name }}</div>`].join('\n'));
await runMigration();
const content = tree.readContent('/comp.html');
expect(content).toBe(
[`@if (user$ | async; as user) {<div>{{ user.name }}</div>}`].join('\n'));
});
it('should migrate if/else with alias', async () => {
writeFile('/comp.ts', `
import {Component} from '@angular/core';
import {NgIf} from '@angular/common';
@Component({
templateUrl: './comp.html'
})
class Comp {
user$ = of({ name: 'Jane' }})
}
`);
writeFile('/comp.html', [
`<div>`,
`<div *ngIf="user$ | async as user; else noUserBlock">{{ user.name }}</div>`,
`<ng-template #noUserBlock>No user</ng-template>`,
`</div>`,
].join('\n'));
await runMigration();
const content = tree.readContent('/comp.html');
expect(content).toBe([
`<div>`,
`@if (user$ | async; as user) {<div>{{ user.name }}</div>} @else {No user}`,
`</div>`,
].join('\n'));
});
it('should migrate if/then/else with alias', async () => {
writeFile('/comp.ts', `
import {Component} from '@angular/core';
import {NgIf} from '@angular/common';
@Component({
templateUrl: './comp.html'
})
class Comp {
user$ = of({ name: 'Jane' }})
}
`);
writeFile('/comp.html', [
`<div>`,
`<ng-container *ngIf="user$ | async as user; then userBlock; else noUserBlock">Ignored</ng-container>`,
`<ng-template #userBlock>User</ng-template>`,
`<ng-template #noUserBlock>No user</ng-template>`,
`</div>`,
].join('\n'));
await runMigration();
const content = tree.readContent('/comp.html');
expect(content).toBe([
`<div>`,
`@if (user$ | async; as user) {User} @else {No user}`,
`</div>`,
].join('\n'));
});
});
describe('ngFor', () => {