Skip to content

Commit e5720ed

Browse files
cexbrayatpkozlowski-opensource
authored andcommitted
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
1 parent eaf735d commit e5720ed

File tree

2 files changed

+90
-3
lines changed

2 files changed

+90
-3
lines changed

packages/core/schematics/ng-generate/control-flow-migration/util.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,9 @@ function migrateNgIf(
252252

253253
function buildIfBlock(
254254
etm: ElementToMigrate, tmpl: string, offset: number): {tmpl: string, offset: number} {
255-
const condition = etm.attr.value;
255+
// includes the mandatory semicolon before as
256+
const condition = etm.attr.value.replace(' as ', '; as ');
257+
256258
const startBlock = `@if (${condition}) {`;
257259

258260
const ifBlock = startBlock + getMainBlock(etm, tmpl, offset) + `}`;
@@ -266,7 +268,8 @@ function buildIfBlock(
266268
function buildIfElseBlock(
267269
etm: ElementToMigrate, ngTemplates: Map<string, Template>, tmpl: string, elseString: string,
268270
offset: number): {tmpl: string, offset: number} {
269-
const condition = etm.getCondition(elseString);
271+
// includes the mandatory semicolon before as
272+
const condition = etm.getCondition(elseString).replace(' as ', '; as ');
270273

271274
const elseTmpl = ngTemplates.get(`#${etm.getTemplateName(elseString)}`)!;
272275
const startBlock = `@if (${condition}) {`;
@@ -291,7 +294,7 @@ function buildIfElseBlock(
291294
function buildIfThenElseBlock(
292295
etm: ElementToMigrate, ngTemplates: Map<string, Template>, tmpl: string, thenString: string,
293296
elseString: string, offset: number): {tmpl: string, offset: number} {
294-
const condition = etm.getCondition(thenString);
297+
const condition = etm.getCondition(thenString).replace(' as ', '; as ');
295298

296299
const startBlock = `@if (${condition}) {`;
297300
const elseBlock = `} @else {`;

packages/core/schematics/test/control_flow_migration_spec.ts

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,90 @@ describe('control flow migration', () => {
363363
`<ng-container *ngTemplateOutlet="blockUsedElsewhere"></ng-container>`,
364364
].join('\n'));
365365
});
366+
367+
it('should migrate if with alias', async () => {
368+
writeFile('/comp.ts', `
369+
import {Component} from '@angular/core';
370+
import {NgIf} from '@angular/common';
371+
372+
@Component({
373+
templateUrl: './comp.html'
374+
})
375+
class Comp {
376+
user$ = of({ name: 'Jane' }})
377+
}
378+
`);
379+
380+
writeFile(
381+
'/comp.html', [`<div *ngIf="user$ | async as user">{{ user.name }}</div>`].join('\n'));
382+
383+
await runMigration();
384+
const content = tree.readContent('/comp.html');
385+
386+
expect(content).toBe(
387+
[`@if (user$ | async; as user) {<div>{{ user.name }}</div>}`].join('\n'));
388+
});
389+
390+
it('should migrate if/else with alias', async () => {
391+
writeFile('/comp.ts', `
392+
import {Component} from '@angular/core';
393+
import {NgIf} from '@angular/common';
394+
395+
@Component({
396+
templateUrl: './comp.html'
397+
})
398+
class Comp {
399+
user$ = of({ name: 'Jane' }})
400+
}
401+
`);
402+
403+
writeFile('/comp.html', [
404+
`<div>`,
405+
`<div *ngIf="user$ | async as user; else noUserBlock">{{ user.name }}</div>`,
406+
`<ng-template #noUserBlock>No user</ng-template>`,
407+
`</div>`,
408+
].join('\n'));
409+
410+
await runMigration();
411+
const content = tree.readContent('/comp.html');
412+
413+
expect(content).toBe([
414+
`<div>`,
415+
`@if (user$ | async; as user) {<div>{{ user.name }}</div>} @else {No user}`,
416+
`</div>`,
417+
].join('\n'));
418+
});
419+
420+
it('should migrate if/then/else with alias', async () => {
421+
writeFile('/comp.ts', `
422+
import {Component} from '@angular/core';
423+
import {NgIf} from '@angular/common';
424+
425+
@Component({
426+
templateUrl: './comp.html'
427+
})
428+
class Comp {
429+
user$ = of({ name: 'Jane' }})
430+
}
431+
`);
432+
433+
writeFile('/comp.html', [
434+
`<div>`,
435+
`<ng-container *ngIf="user$ | async as user; then userBlock; else noUserBlock">Ignored</ng-container>`,
436+
`<ng-template #userBlock>User</ng-template>`,
437+
`<ng-template #noUserBlock>No user</ng-template>`,
438+
`</div>`,
439+
].join('\n'));
440+
441+
await runMigration();
442+
const content = tree.readContent('/comp.html');
443+
444+
expect(content).toBe([
445+
`<div>`,
446+
`@if (user$ | async; as user) {User} @else {No user}`,
447+
`</div>`,
448+
].join('\n'));
449+
});
366450
});
367451

368452
describe('ngFor', () => {

0 commit comments

Comments
 (0)