From 775edb01ff189c3e04fc86b210a680b0c97a119a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A6=8A=E5=8E=9F=E6=98=8C=E5=BD=A6?= Date: Tue, 23 Jan 2024 15:23:34 +0900 Subject: [PATCH 1/2] feat(): support ios/md attribute of ion-icon --- .../0002-import-standalone-component.test.ts | 8 +- .../0002-import-standalone-component.ts | 90 ++++++++++++------- 2 files changed, 64 insertions(+), 34 deletions(-) diff --git a/packages/cli/src/angular/migrations/standalone/0002-import-standalone-component.test.ts b/packages/cli/src/angular/migrations/standalone/0002-import-standalone-component.test.ts index 68c19d8..e3e84c5 100644 --- a/packages/cli/src/angular/migrations/standalone/0002-import-standalone-component.test.ts +++ b/packages/cli/src/angular/migrations/standalone/0002-import-standalone-component.test.ts @@ -132,7 +132,7 @@ describe("migrateComponents", () => { @Component({ selector: 'my-component', - template: '', + template: '', standalone: true }) export class MyComponent { } @@ -149,18 +149,18 @@ describe("migrateComponents", () => { dedent(` import { Component } from "@angular/core"; import { addIcons } from "ionicons"; - import { logoIonic } from "ionicons/icons"; + import { logoIonic, add, remove } from "ionicons/icons"; import { IonIcon } from "@ionic/angular/standalone"; @Component({ selector: 'my-component', - template: '', + template: '', standalone: true, imports: [IonIcon] }) export class MyComponent { constructor() { - addIcons({ logoIonic }); + addIcons({ logoIonic, add, remove }); } } `), diff --git a/packages/cli/src/angular/migrations/standalone/0002-import-standalone-component.ts b/packages/cli/src/angular/migrations/standalone/0002-import-standalone-component.ts index d370ea1..0316123 100644 --- a/packages/cli/src/angular/migrations/standalone/0002-import-standalone-component.ts +++ b/packages/cli/src/angular/migrations/standalone/0002-import-standalone-component.ts @@ -267,40 +267,70 @@ function detectIonicComponentsAndIcons(htmlAsString: string, filePath: string) { } if (node.name === "ion-icon") { - const staticNameAttribute = node.attributes.find( - (a: any) => a.name === "name" || a.name === "icon", - ); - - if (staticNameAttribute) { - const iconName = staticNameAttribute.value; - if (!ionIcons.includes(iconName)) { - ionIcons.push(iconName); - } - } else { - const boundNameAttribute = node.inputs.find( - (a: any) => a.name === "name" || a.name === "icon", + for (const attribute of ["name", "icon", "ios", "md"]) { + const staticNameAttribute = node.attributes.find( + (a: any) => a.name === attribute, ); - if (boundNameAttribute) { - const skippedIcon = node.sourceSpan.toString(); - - const iconNameRegex = /{{\s*'([^']+)'\s*}}/; - /** - * Attempt to find the icon name from the bound name attribute - * when the developer has a template like this: - * - */ - const iconNameMatch = skippedIcon.match(iconNameRegex); + if (staticNameAttribute) { + const iconName = staticNameAttribute.value; + if (!ionIcons.includes(iconName)) { + ionIcons.push(iconName); + } + } else { + const boundNameAttribute = node.inputs.find( + (a: any) => a.name === attribute, + ); - if (iconNameMatch) { - if (!ionIcons.includes(iconNameMatch[1])) { - ionIcons.push(iconNameMatch[1]); + if (boundNameAttribute) { + const skippedIcon = node.sourceSpan.toString(); + + const iconNameRegex = /{{\s*'([^']+)'\s*}}/; + /** + * Attempt to find the icon name from the bound name attribute + * when the developer has a template like this: + * + */ + const iconNameMatch = skippedIcon.match(iconNameRegex); + + const deepGetIconConditional = ( + ast: typeof boundNameAttribute.value.ast, + icons: string[], + ): string[] => { + if (ast.trueExp.type === "LiteralPrimitive") { + if (!ionIcons.includes(ast.trueExp.value)) { + ionIcons.push(ast.trueExp.value); + } + } else if (ast.trueExp.type === "Conditional") { + deepGetIconConditional(ast.trueExp, icons); + } else { + skippedIconsHtml.push(skippedIcon); + } + + if (ast.falseExp.type === "LiteralPrimitive") { + if (!ionIcons.includes(ast.falseExp.value)) { + ionIcons.push(ast.falseExp.value); + } + } else if (ast.falseExp.type === "Conditional") { + deepGetIconConditional(ast.falseExp, icons); + } else { + skippedIconsHtml.push(skippedIcon); + } + return icons; + }; + + if (iconNameMatch) { + if (!ionIcons.includes(iconNameMatch[1])) { + ionIcons.push(iconNameMatch[1]); + } + } else if (boundNameAttribute.value.ast.type === "Conditional") { + deepGetIconConditional(boundNameAttribute.value.ast, ionIcons); + } else { + // IonIcon name is a calculated value from a variable or function. + // We can't determine the value of the name at this time. + // The developer will need to manually import these icons. + skippedIconsHtml.push(skippedIcon); } - } else { - // IonIcon name is a calculated value from a variable or function. - // We can't determine the value of the name at this time. - // The developer will need to manually import these icons. - skippedIconsHtml.push(skippedIcon); } } } From 5d740f865b23726d067e0c54de3cf345e4e564cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A6=8A=E5=8E=9F=E6=98=8C=E5=BD=A6?= Date: Sun, 28 Jan 2024 12:03:05 +0900 Subject: [PATCH 2/2] fmt --- .../standalone/0002-import-standalone-component.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/angular/migrations/standalone/0002-import-standalone-component.ts b/packages/cli/src/angular/migrations/standalone/0002-import-standalone-component.ts index 779a806..0316123 100644 --- a/packages/cli/src/angular/migrations/standalone/0002-import-standalone-component.ts +++ b/packages/cli/src/angular/migrations/standalone/0002-import-standalone-component.ts @@ -268,7 +268,9 @@ function detectIonicComponentsAndIcons(htmlAsString: string, filePath: string) { if (node.name === "ion-icon") { for (const attribute of ["name", "icon", "ios", "md"]) { - const staticNameAttribute = node.attributes.find((a: any) => a.name === attribute); + const staticNameAttribute = node.attributes.find( + (a: any) => a.name === attribute, + ); if (staticNameAttribute) { const iconName = staticNameAttribute.value; @@ -276,7 +278,9 @@ function detectIonicComponentsAndIcons(htmlAsString: string, filePath: string) { ionIcons.push(iconName); } } else { - const boundNameAttribute = node.inputs.find((a: any) => a.name === attribute); + const boundNameAttribute = node.inputs.find( + (a: any) => a.name === attribute, + ); if (boundNameAttribute) { const skippedIcon = node.sourceSpan.toString();