Skip to content

Commit cca8cc1

Browse files
authored
feat(): support icon name of conditional (#38)
1 parent 2561b82 commit cca8cc1

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

packages/cli/src/angular/migrations/standalone/0002-import-standalone-component.test.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,53 @@ describe("migrateComponents", () => {
167167
);
168168
});
169169

170+
it("should detect and import icons in conditional used in the template", async () => {
171+
const project = new Project({ useInMemoryFileSystem: true });
172+
173+
const component = `
174+
import { Component } from "@angular/core";
175+
176+
@Component({
177+
selector: 'my-component',
178+
template: \`<ion-icon [name]="isLogo ? 'logo-ionic' : 'alert'"></ion-icon>\`,
179+
standalone: true
180+
})
181+
export class MyComponent {
182+
isLogo = true;
183+
}
184+
`;
185+
186+
const componentSourceFile = project.createSourceFile(
187+
"foo.component.ts",
188+
dedent(component),
189+
);
190+
191+
await migrateComponents(project, { dryRun: false });
192+
193+
expect(dedent(componentSourceFile.getText())).toBe(
194+
dedent(`
195+
import { Component } from "@angular/core";
196+
import { addIcons } from "ionicons";
197+
import { logoIonic, alert } from "ionicons/icons";
198+
import { IonIcon } from "@ionic/angular/standalone";
199+
200+
@Component({
201+
selector: 'my-component',
202+
template: \`<ion-icon [name]="isLogo ? 'logo-ionic' : 'alert'"></ion-icon>\`,
203+
standalone: true,
204+
imports: [IonIcon]
205+
})
206+
export class MyComponent {
207+
isLogo = true;
208+
209+
constructor() {
210+
addIcons({ logoIonic, alert });
211+
}
212+
}
213+
`),
214+
);
215+
});
216+
170217
it("should remove duplicate imports from existing declarations", async () => {
171218
const project = new Project({ useInMemoryFileSystem: true });
172219

packages/cli/src/angular/migrations/standalone/0002-import-standalone-component.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,10 +292,38 @@ function detectIonicComponentsAndIcons(htmlAsString: string, filePath: string) {
292292
*/
293293
const iconNameMatch = skippedIcon.match(iconNameRegex);
294294

295+
const deepGetIconConditional = (
296+
ast: typeof boundNameAttribute.value.ast,
297+
icons: string[],
298+
): string[] => {
299+
if (ast.trueExp.type === "LiteralPrimitive") {
300+
if (!ionIcons.includes(ast.trueExp.value)) {
301+
ionIcons.push(ast.trueExp.value);
302+
}
303+
} else if (ast.trueExp.type === "Conditional") {
304+
deepGetIconConditional(ast.trueExp, icons);
305+
} else {
306+
skippedIconsHtml.push(skippedIcon);
307+
}
308+
309+
if (ast.falseExp.type === "LiteralPrimitive") {
310+
if (!ionIcons.includes(ast.falseExp.value)) {
311+
ionIcons.push(ast.falseExp.value);
312+
}
313+
} else if (ast.falseExp.type === "Conditional") {
314+
deepGetIconConditional(ast.falseExp, icons);
315+
} else {
316+
skippedIconsHtml.push(skippedIcon);
317+
}
318+
return icons;
319+
};
320+
295321
if (iconNameMatch) {
296322
if (!ionIcons.includes(iconNameMatch[1])) {
297323
ionIcons.push(iconNameMatch[1]);
298324
}
325+
} else if (boundNameAttribute.value.ast.type === "Conditional") {
326+
deepGetIconConditional(boundNameAttribute.value.ast, ionIcons);
299327
} else {
300328
// IonIcon name is a calculated value from a variable or function.
301329
// We can't determine the value of the name at this time.

0 commit comments

Comments
 (0)