Skip to content

Commit db6b4a6

Browse files
thePunderWomanatscott
authored andcommitted
fix(migrations): Fix cf migration bug with parsing for loop conditions properly (#53558)
The order of operations for getting for loop parts was inverted resulting in the StringStack to never be reduced. fixes: #53555 PR Close #53558
1 parent 606de51 commit db6b4a6

File tree

2 files changed

+61
-4
lines changed

2 files changed

+61
-4
lines changed

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,6 @@ function getNgForParts(expression: string): string[] {
219219
const char = expression[i];
220220
const isInString = stringStack.length === 0;
221221
const isInCommaSeparated = commaSeparatedStack.length === 0;
222-
223222
// Any semicolon is a delimiter, as well as any comma outside
224223
// of comma-separated syntax, as long as they're outside of a string.
225224
if (isInString && current.length > 0 &&
@@ -229,10 +228,10 @@ function getNgForParts(expression: string): string[] {
229228
continue;
230229
}
231230

232-
if (stringPairs.has(char)) {
233-
stringStack.push(stringPairs.get(char)!);
234-
} else if (stringStack.length > 0 && stringStack[stringStack.length - 1] === char) {
231+
if (stringStack.length > 0 && stringStack[stringStack.length - 1] === char) {
235232
stringStack.pop();
233+
} else if (stringPairs.has(char)) {
234+
stringStack.push(stringPairs.get(char)!);
236235
}
237236

238237
if (commaSeparatedSyntax.has(char)) {

packages/core/schematics/test/control_flow_migration_spec.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2284,6 +2284,64 @@ describe('control flow migration', () => {
22842284
expect(actual).toBe(expected);
22852285
});
22862286

2287+
it('should migrate ngFor with a long ternary and trackby', async () => {
2288+
writeFile('/comp.ts', `
2289+
import {Component} from '@angular/core';
2290+
import {NgFor} from '@angular/common';
2291+
interface Item {
2292+
id: number;
2293+
text: string;
2294+
}
2295+
2296+
@Component({
2297+
imports: [NgFor,NgForOf],
2298+
templateUrl: 'comp.html',
2299+
})
2300+
class Comp {
2301+
items: Item[] = [{id: 1, text: 'blah'},{id: 2, text: 'stuff'}];
2302+
}
2303+
`);
2304+
2305+
writeFile('/comp.html', [
2306+
`<div`,
2307+
` *ngFor="`,
2308+
` let item of section === 'manage'`,
2309+
` ? filteredPermissions?.manage`,
2310+
` : section === 'customFields'`,
2311+
` ? filteredPermissions?.customFields`,
2312+
` : section === 'createAndDelete'`,
2313+
` ? filteredPermissions?.createAndDelete`,
2314+
` : filteredPermissions?.team;`,
2315+
` trackBy: trackById`,
2316+
` "`,
2317+
`>`,
2318+
` {{ item }}`,
2319+
`</div>`,
2320+
].join('\n'));
2321+
2322+
await runMigration();
2323+
const actual = tree.readContent('/comp.html');
2324+
2325+
const expected = [
2326+
`@for (`,
2327+
` item of section === 'manage'`,
2328+
` ? filteredPermissions?.manage`,
2329+
` : section === 'customFields'`,
2330+
` ? filteredPermissions?.customFields`,
2331+
` : section === 'createAndDelete'`,
2332+
` ? filteredPermissions?.createAndDelete`,
2333+
` : filteredPermissions?.team; track trackById($index,`,
2334+
` item)) {`,
2335+
` <div`,
2336+
` >`,
2337+
` {{ item }}`,
2338+
` </div>`,
2339+
`}`,
2340+
].join('\n');
2341+
2342+
expect(actual).toBe(expected);
2343+
});
2344+
22872345
it('should migrate ngForOf with track by and multiple aliases', async () => {
22882346
writeFile('/comp.ts', `
22892347
import {Component} from '@angular/core';

0 commit comments

Comments
 (0)