diff --git a/packages/core/schematics/ng-generate/control-flow-migration/fors.ts b/packages/core/schematics/ng-generate/control-flow-migration/fors.ts index cc0ad8b4003..c9865a99db6 100644 --- a/packages/core/schematics/ng-generate/control-flow-migration/fors.ts +++ b/packages/core/schematics/ng-generate/control-flow-migration/fors.ts @@ -113,8 +113,8 @@ function migrateStandardNgFor(etm: ElementToMigrate, tmpl: string, offset: numbe // template if (part.startsWith('template:')) { // this generates a special template placeholder just for this use case - // which has a # at the end instead of the standard | in other placeholders - tmplPlaceholder = `#${part.split(':')[1].trim()}#`; + // which has a φ at the end instead of the standard δ in other placeholders + tmplPlaceholder = `θ${part.split(':')[1].trim()}φ`; } // aliases // declared with `let myIndex = index` diff --git a/packages/core/schematics/ng-generate/control-flow-migration/ifs.ts b/packages/core/schematics/ng-generate/control-flow-migration/ifs.ts index 25087c8b7c8..a5dcace6683 100644 --- a/packages/core/schematics/ng-generate/control-flow-migration/ifs.ts +++ b/packages/core/schematics/ng-generate/control-flow-migration/ifs.ts @@ -133,7 +133,7 @@ function buildStandardIfElseBlock( .replace(' as ', '; as ') // replace 'let' with 'as' whatever spaces are between ; and 'let' .replace(/;\s*let/g, '; as'); - const elsePlaceholder = `#${etm.getTemplateName(elseString)}|`; + const elsePlaceholder = `θ${etm.getTemplateName(elseString)}δ`; return buildIfElseBlock(etm, tmpl, condition, elsePlaceholder, offset); } @@ -153,9 +153,9 @@ function buildBoundIfElseBlock(etm: ElementToMigrate, tmpl: string, offset: numb } else if (aliases.length === 1) { condition += `; as ${aliases[0]}`; } - const elsePlaceholder = `#${etm.elseAttr!.value}|`; + const elsePlaceholder = `θ${etm.elseAttr!.value}δ`; if (etm.thenAttr !== undefined) { - const thenPlaceholder = `#${etm.thenAttr!.value}|`; + const thenPlaceholder = `θ${etm.thenAttr!.value}δ`; return buildIfThenElseBlock(etm, tmpl, condition, thenPlaceholder, elsePlaceholder, offset); } return buildIfElseBlock(etm, tmpl, condition, elsePlaceholder, offset); @@ -194,8 +194,8 @@ function buildStandardIfThenElseBlock( .replace(' as ', '; as ') // replace 'let' with 'as' whatever spaces are between ; and 'let' .replace(/;\s*let/g, '; as'); - const thenPlaceholder = `#${etm.getTemplateName(thenString, elseString)}|`; - const elsePlaceholder = `#${etm.getTemplateName(elseString)}|`; + const thenPlaceholder = `θ${etm.getTemplateName(thenString, elseString)}δ`; + const elsePlaceholder = `θ${etm.getTemplateName(elseString)}δ`; return buildIfThenElseBlock(etm, tmpl, condition, thenPlaceholder, elsePlaceholder, offset); } @@ -206,7 +206,7 @@ function buildStandardIfThenBlock( .replace(' as ', '; as ') // replace 'let' with 'as' whatever spaces are between ; and 'let' .replace(/;\s*let/g, '; as'); - const thenPlaceholder = `#${etm.getTemplateName(thenString)}|`; + const thenPlaceholder = `θ${etm.getTemplateName(thenString)}δ`; return buildIfThenBlock(etm, tmpl, condition, thenPlaceholder, offset); } diff --git a/packages/core/schematics/ng-generate/control-flow-migration/types.ts b/packages/core/schematics/ng-generate/control-flow-migration/types.ts index 85dde952b52..32a27bc15c1 100644 --- a/packages/core/schematics/ng-generate/control-flow-migration/types.ts +++ b/packages/core/schematics/ng-generate/control-flow-migration/types.ts @@ -141,11 +141,12 @@ export class ElementToMigrate { getTemplateName(targetStr: string, secondStr?: string): string { const targetLocation = this.attr.value.indexOf(targetStr); const secondTargetLocation = secondStr ? this.attr.value.indexOf(secondStr) : undefined; - return this.attr.value.slice(targetLocation + targetStr.length, secondTargetLocation) - .replace(':', '') - .trim() - .split(';')[0] - .trim(); + let templateName = + this.attr.value.slice(targetLocation + targetStr.length, secondTargetLocation); + if (templateName.startsWith(':')) { + templateName = templateName.slice(1).trim(); + } + return templateName.split(';')[0].trim(); } getValueEnd(offset: number): number { 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 87e8ecfec9a..4c83442bca8 100644 --- a/packages/core/schematics/ng-generate/control-flow-migration/util.ts +++ b/packages/core/schematics/ng-generate/control-flow-migration/util.ts @@ -325,8 +325,8 @@ export function processNgTemplates(template: string): {migrated: string, err: Er // swap placeholders and remove for (const [name, t] of templates) { - const replaceRegex = new RegExp(`${name}\\|`, 'g'); - const forRegex = new RegExp(`${name}\\#`, 'g'); + const replaceRegex = new RegExp(`θ${name.slice(1)}\\δ`, 'g'); + const forRegex = new RegExp(`θ${name.slice(1)}\\φ`, 'g'); const forMatches = [...template.matchAll(forRegex)]; const matches = [...forMatches, ...template.matchAll(replaceRegex)]; let safeToRemove = true; @@ -367,7 +367,7 @@ export function processNgTemplates(template: string): {migrated: string, err: Er } function replaceRemainingPlaceholders(template: string): string { - const replaceRegex = new RegExp(`#\\w*\\|`, 'g'); + const replaceRegex = new RegExp(`θ.*δ`, 'g'); const placeholders = [...template.matchAll(replaceRegex)]; let migrated = template; for (let ph of placeholders) { diff --git a/packages/core/schematics/test/control_flow_migration_spec.ts b/packages/core/schematics/test/control_flow_migration_spec.ts index aac93e7096f..ce73c9cb682 100644 --- a/packages/core/schematics/test/control_flow_migration_spec.ts +++ b/packages/core/schematics/test/control_flow_migration_spec.ts @@ -4046,6 +4046,109 @@ describe('control flow migration', () => { `}`, ].join('\n')); }); + + it('should handle OR logic in ngIf else case', async () => { + writeFile('/comp.ts', ` + import {Component} from '@angular/core'; + import {NgIf} from '@angular/common'; + + @Component({ + templateUrl: './comp.html' + }) + class Comp { + show = false; + } + `); + + writeFile('/comp.html', [ + `
Hello!
`, + ` Default `, + ].join('\n')); + + await runMigration(); + const content = tree.readContent('/comp.html'); + + expect(content).toBe([ + `@if (condition) {`, + `
Hello!
`, + `} @else {`, + ` `, + `}`, + ` Default `, + ].join('\n')); + }); + + it('should handle ternaries in ngIfElse', async () => { + writeFile('/comp.ts', ` + import {Component} from '@angular/core'; + import {NgIf} from '@angular/common'; + + @Component({ + templateUrl: './comp.html' + }) + class Comp { + show = false; + } + `); + + writeFile('/comp.html', [ + ``, + `v3`, + `clear`, + ].join('\n')); + + await runMigration(); + const content = tree.readContent('/comp.html'); + + expect(content).toBe([ + `@if (customClearTemplate) {`, + ` `, + `} @else {`, + ` `, + `}`, + `v3`, + `clear`, + ].join('\n')); + }); + + it('should handle ternaries in ngIf', async () => { + writeFile('/comp.ts', ` + import {Component} from '@angular/core'; + import {NgIf} from '@angular/common'; + + @Component({ + templateUrl: './comp.html' + }) + class Comp { + show = false; + } + `); + + writeFile('/comp.html', [ + `
`, + `Loading`, + `Empty`, + ].join('\n')); + + await runMigration(); + const content = tree.readContent('/comp.html'); + + expect(content).toBe([ + `@if (!vm.isEmpty) {`, + `
`, + `} @else {`, + ` `, + `}`, + `Loading`, + `Empty`, + ].join('\n')); + }); }); describe('formatting', () => {