diff --git a/packages/core/schematics/ng-generate/control-flow-migration/util.ts b/packages/core/schematics/ng-generate/control-flow-migration/util.ts index b41faedbf89cd..57ac12a426218 100644 --- a/packages/core/schematics/ng-generate/control-flow-migration/util.ts +++ b/packages/core/schematics/ng-generate/control-flow-migration/util.ts @@ -18,11 +18,7 @@ import {AnalyzedFile, boundngif, CaseCollector, ElementCollector, ElementToMigra * @param analyzedFiles Map in which to store the results. */ export function analyze(sourceFile: ts.SourceFile, analyzedFiles: Map) { - for (const node of sourceFile.statements) { - if (!ts.isClassDeclaration(node)) { - continue; - } - + forEachClass(sourceFile, node => { // Note: we have a utility to resolve the Angular decorators from a class declaration already. // We don't use it here, because it requires access to the type checker which makes it more // time-consuming to run internally. @@ -38,7 +34,7 @@ export function analyze(sourceFile: ts.SourceFile, analyzedFiles: Map void) { + sourceFile.forEachChild(function walk(node) { + if (ts.isClassDeclaration(node)) { + callback(node); + } + node.forEachChild(walk); + }); +} diff --git a/packages/core/schematics/test/control_flow_migration_spec.ts b/packages/core/schematics/test/control_flow_migration_spec.ts index 28762ac2fe7d4..2e81081b18c7d 100644 --- a/packages/core/schematics/test/control_flow_migration_spec.ts +++ b/packages/core/schematics/test/control_flow_migration_spec.ts @@ -570,6 +570,51 @@ describe('control flow migration', () => { ``, ].join('\n')); }); + + it('should migrate a nested class', async () => { + writeFile('/comp.ts', ` + import {Component} from '@angular/core'; + import {NgIf} from '@angular/common'; + + function foo() { + @Component({ + imports: [NgIf], + template: \`
This should be hidden
\` + }) + class Comp { + toggle = false; + } + } + `); + + await runMigration(); + const content = tree.readContent('/comp.ts'); + + expect(content).toContain( + 'template: `
@if (toggle) {This should be hidden}
`'); + }); + + it('should migrate a nested class', async () => { + writeFile('/comp.ts', ` + import {Component} from '@angular/core'; + import {NgIf} from '@angular/common'; + function foo() { + @Component({ + imports: [NgIf], + template: \`
This should be hidden
\` + }) + class Comp { + toggle = false; + } + } + `); + + await runMigration(); + const content = tree.readContent('/comp.ts'); + + expect(content).toContain( + 'template: `
@if (toggle) {This should be hidden}
`'); + }); }); describe('ngFor', () => { @@ -870,6 +915,59 @@ describe('control flow migration', () => { expect(content).toContain( 'template: `@for (item of items; track item) {

{{item.text}}

}`'); }); + + it('should migrate a nested class', async () => { + writeFile('/comp.ts', ` + import {Component} from '@angular/core'; + import {NgFor} from '@angular/common'; + interface Item { + id: number; + text: string; + } + + function foo() { + @Component({ + imports: [NgFor], + template: \`\` + }) + class Comp { + items: Item[] = [{id: 1, text: 'blah'},{id: 2, text: 'stuff'}]; + } + } + `); + + await runMigration(); + const content = tree.readContent('/comp.ts'); + + expect(content).toContain( + 'template: ``'); + }); + + it('should migrate a nested class', async () => { + writeFile('/comp.ts', ` + import {Component} from '@angular/core'; + import {NgFor} from '@angular/common'; + interface Item { + id: number; + text: string; + } + function foo() { + @Component({ + imports: [NgFor], + template: \`\` + }) + class Comp { + items: Item[] = [{id: 1, text: 'blah'},{id: 2, text: 'stuff'}]; + } + } + `); + + await runMigration(); + const content = tree.readContent('/comp.ts'); + + expect(content).toContain( + 'template: ``'); + }); }); describe('ngSwitch', () => { @@ -1131,6 +1229,32 @@ describe('control flow migration', () => { expect(content).toContain( 'template: `
@switch (testOpts) { @case (1) {

Option 1

} @case (2) {

Option 2

} @default {

Option 3

}}
'); }); + + it('should migrate a nested class', async () => { + writeFile( + '/comp.ts', + ` + import {Component} from '@angular/core'; + import {ngSwitch, ngSwitchCase} from '@angular/common'; + function foo() { + @Component({ + template: \`
` + + `

Option 1

` + + `

Option 2

` + + `
\` + }) + class Comp { + testOpts = "1"; + } + } + `); + + await runMigration(); + const content = tree.readContent('/comp.ts'); + + expect(content).toContain( + 'template: `
@switch (testOpts) { @case (1) {

Option 1

} @case (2) {

Option 2

}}
`'); + }); }); describe('nested structures', () => {