mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(core): fix used templates are not deleted (#60459)
After running the control flow migration, used templates are not deleted. PR Close #60459
This commit is contained in:
@@ -385,10 +385,6 @@ export function calculateNesting(
|
||||
}
|
||||
}
|
||||
|
||||
function escapeRegExp(val: string) {
|
||||
return val.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
||||
}
|
||||
|
||||
/**
|
||||
* determines if a given template string contains line breaks
|
||||
*/
|
||||
@@ -425,20 +421,48 @@ export function getTemplates(template: string): Map<string, Template> {
|
||||
const visitor = new TemplateCollector();
|
||||
visitAll(visitor, parsed.tree.rootNodes);
|
||||
|
||||
// count usages of each ng-template
|
||||
for (let [key, tmpl] of visitor.templates) {
|
||||
const escapeKey = escapeRegExp(key.slice(1));
|
||||
const regex = new RegExp(`[^a-zA-Z0-9-<(\']${escapeKey}\\W`, 'gm');
|
||||
const matches = template.match(regex);
|
||||
tmpl.count = matches?.length ?? 0;
|
||||
tmpl.count = countTemplateUsage(parsed.tree.rootNodes, key);
|
||||
tmpl.generateContents(template);
|
||||
}
|
||||
|
||||
return visitor.templates;
|
||||
}
|
||||
return new Map<string, Template>();
|
||||
}
|
||||
|
||||
function countTemplateUsage(nodes: any[], templateName: string): number {
|
||||
let count = 0;
|
||||
let isReferencedInTemplateOutlet = false;
|
||||
|
||||
for (const node of nodes) {
|
||||
if (node.attrs) {
|
||||
for (const attr of node.attrs) {
|
||||
if (attr.name === '*ngTemplateOutlet' && attr.value === templateName.slice(1)) {
|
||||
isReferencedInTemplateOutlet = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (attr.name.trim() === templateName) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (node.children) {
|
||||
if (node.name === 'for') {
|
||||
for (const child of node.children) {
|
||||
if (child.value?.includes(templateName.slice(1))) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
count += countTemplateUsage(node.children, templateName);
|
||||
}
|
||||
}
|
||||
|
||||
return isReferencedInTemplateOutlet ? count + 2 : count;
|
||||
}
|
||||
|
||||
export function updateTemplates(
|
||||
template: string,
|
||||
templates: Map<string, Template>,
|
||||
@@ -497,8 +521,12 @@ export function processNgTemplates(
|
||||
} else {
|
||||
template = template.replace(replaceRegex, t.children);
|
||||
}
|
||||
// the +1 accounts for the t.count's counting of the original template
|
||||
if (t.count === matches.length + 1 && safeToRemove) {
|
||||
|
||||
const dist = matches.filter(
|
||||
(obj, index, self) => index === self.findIndex((t) => t.input === obj.input),
|
||||
);
|
||||
|
||||
if ((t.count === dist.length || t.count - matches.length === 1) && safeToRemove) {
|
||||
const refsInComponentFile = getViewChildOrViewChildrenNames(sourceFile);
|
||||
if (refsInComponentFile?.length > 0) {
|
||||
const templateRefs = getTemplateReferences(template);
|
||||
|
||||
@@ -6932,5 +6932,38 @@ describe('control flow migration', () => {
|
||||
const content = tree.readContent('/comp.ts');
|
||||
expect(content).not.toContain('<ng-template #contentTemplate>');
|
||||
});
|
||||
|
||||
it('should remove ng-template reference when use in if-else block', async () => {
|
||||
writeFile(
|
||||
'/comp.ts',
|
||||
`
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
templateUrl: './comp.html'
|
||||
})
|
||||
class Comp {
|
||||
}
|
||||
`,
|
||||
);
|
||||
|
||||
writeFile(
|
||||
'/comp.html',
|
||||
[
|
||||
`<div>`,
|
||||
`<div *ngIf="param; else loading">`,
|
||||
`<div>content</div>`,
|
||||
`</div>`,
|
||||
`<ng-template #loading>`,
|
||||
`<div>loading</div>`,
|
||||
`</ng-template>`,
|
||||
`</div>`,
|
||||
].join('\n'),
|
||||
);
|
||||
|
||||
await runMigration();
|
||||
const content = tree.readContent('/comp.html');
|
||||
expect(content).not.toContain('<ng-template #loading>');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user