Skip to content

Commit 44a7387

Browse files
authored
feat(): support ios/md attribute of ion-icon (#39)
* feat(): support ios/md attribute of ion-icon
1 parent 336c91b commit 44a7387

File tree

2 files changed

+60
-58
lines changed

2 files changed

+60
-58
lines changed

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ describe("migrateComponents", () => {
132132
133133
@Component({
134134
selector: 'my-component',
135-
template: '<ion-icon name="logo-ionic"></ion-icon>',
135+
template: '<ion-icon name="logo-ionic" ios="add" md="remove"></ion-icon>',
136136
standalone: true
137137
})
138138
export class MyComponent { }
@@ -149,18 +149,18 @@ describe("migrateComponents", () => {
149149
dedent(`
150150
import { Component } from "@angular/core";
151151
import { addIcons } from "ionicons";
152-
import { logoIonic } from "ionicons/icons";
152+
import { logoIonic, add, remove } from "ionicons/icons";
153153
import { IonIcon } from "@ionic/angular/standalone";
154154
155155
@Component({
156156
selector: 'my-component',
157-
template: '<ion-icon name="logo-ionic"></ion-icon>',
157+
template: '<ion-icon name="logo-ionic" ios="add" md="remove"></ion-icon>',
158158
standalone: true,
159159
imports: [IonIcon]
160160
})
161161
export class MyComponent {
162162
constructor() {
163-
addIcons({ logoIonic });
163+
addIcons({ logoIonic, add, remove });
164164
}
165165
}
166166
`),

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

Lines changed: 56 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -267,68 +267,70 @@ function detectIonicComponentsAndIcons(htmlAsString: string, filePath: string) {
267267
}
268268

269269
if (node.name === "ion-icon") {
270-
const staticNameAttribute = node.attributes.find(
271-
(a: any) => a.name === "name" || a.name === "icon",
272-
);
273-
274-
if (staticNameAttribute) {
275-
const iconName = staticNameAttribute.value;
276-
if (!ionIcons.includes(iconName)) {
277-
ionIcons.push(iconName);
278-
}
279-
} else {
280-
const boundNameAttribute = node.inputs.find(
281-
(a: any) => a.name === "name" || a.name === "icon",
270+
for (const attribute of ["name", "icon", "ios", "md"]) {
271+
const staticNameAttribute = node.attributes.find(
272+
(a: any) => a.name === attribute,
282273
);
283274

284-
if (boundNameAttribute) {
285-
const skippedIcon = node.sourceSpan.toString();
286-
287-
const iconNameRegex = /{{\s*'([^']+)'\s*}}/;
288-
/**
289-
* Attempt to find the icon name from the bound name attribute
290-
* when the developer has a template like this:
291-
* <ion-icon name="'user'"></ion-icon>
292-
*/
293-
const iconNameMatch = skippedIcon.match(iconNameRegex);
294-
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);
275+
if (staticNameAttribute) {
276+
const iconName = staticNameAttribute.value;
277+
if (!ionIcons.includes(iconName)) {
278+
ionIcons.push(iconName);
279+
}
280+
} else {
281+
const boundNameAttribute = node.inputs.find(
282+
(a: any) => a.name === attribute,
283+
);
284+
285+
if (boundNameAttribute) {
286+
const skippedIcon = node.sourceSpan.toString();
287+
288+
const iconNameRegex = /{{\s*'([^']+)'\s*}}/;
289+
/**
290+
* Attempt to find the icon name from the bound name attribute
291+
* when the developer has a template like this:
292+
* <ion-icon name="'user'"></ion-icon>
293+
*/
294+
const iconNameMatch = skippedIcon.match(iconNameRegex);
295+
296+
const deepGetIconConditional = (
297+
ast: typeof boundNameAttribute.value.ast,
298+
icons: string[],
299+
): string[] => {
300+
if (ast.trueExp.type === "LiteralPrimitive") {
301+
if (!ionIcons.includes(ast.trueExp.value)) {
302+
ionIcons.push(ast.trueExp.value);
303+
}
304+
} else if (ast.trueExp.type === "Conditional") {
305+
deepGetIconConditional(ast.trueExp, icons);
306+
} else {
307+
skippedIconsHtml.push(skippedIcon);
302308
}
303-
} else if (ast.trueExp.type === "Conditional") {
304-
deepGetIconConditional(ast.trueExp, icons);
305-
} else {
306-
skippedIconsHtml.push(skippedIcon);
307-
}
308309

309-
if (ast.falseExp.type === "LiteralPrimitive") {
310-
if (!ionIcons.includes(ast.falseExp.value)) {
311-
ionIcons.push(ast.falseExp.value);
310+
if (ast.falseExp.type === "LiteralPrimitive") {
311+
if (!ionIcons.includes(ast.falseExp.value)) {
312+
ionIcons.push(ast.falseExp.value);
313+
}
314+
} else if (ast.falseExp.type === "Conditional") {
315+
deepGetIconConditional(ast.falseExp, icons);
316+
} else {
317+
skippedIconsHtml.push(skippedIcon);
318+
}
319+
return icons;
320+
};
321+
322+
if (iconNameMatch) {
323+
if (!ionIcons.includes(iconNameMatch[1])) {
324+
ionIcons.push(iconNameMatch[1]);
312325
}
313-
} else if (ast.falseExp.type === "Conditional") {
314-
deepGetIconConditional(ast.falseExp, icons);
326+
} else if (boundNameAttribute.value.ast.type === "Conditional") {
327+
deepGetIconConditional(boundNameAttribute.value.ast, ionIcons);
315328
} else {
329+
// IonIcon name is a calculated value from a variable or function.
330+
// We can't determine the value of the name at this time.
331+
// The developer will need to manually import these icons.
316332
skippedIconsHtml.push(skippedIcon);
317333
}
318-
return icons;
319-
};
320-
321-
if (iconNameMatch) {
322-
if (!ionIcons.includes(iconNameMatch[1])) {
323-
ionIcons.push(iconNameMatch[1]);
324-
}
325-
} else if (boundNameAttribute.value.ast.type === "Conditional") {
326-
deepGetIconConditional(boundNameAttribute.value.ast, ionIcons);
327-
} else {
328-
// IonIcon name is a calculated value from a variable or function.
329-
// We can't determine the value of the name at this time.
330-
// The developer will need to manually import these icons.
331-
skippedIconsHtml.push(skippedIcon);
332334
}
333335
}
334336
}

0 commit comments

Comments
 (0)