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 3bb909e..987bf09 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 @@ -74,11 +74,13 @@ describe("migrateComponents", () => { const component = ` import { Component } from "@angular/core"; + import { IonicModule } from "@ionic/angular"; @Component({ selector: 'my-component', templateUrl: './my-component.component.html', - standalone: true + standalone: true, + imports: [IonicModule] }) export class MyComponent { } `; 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 5332b90..3232a4f 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 @@ -17,6 +17,7 @@ import { getAngularComponentDecorator, isAngularComponentClass, isAngularComponentStandalone, + removeImportFromComponentDecorator, } from "../../utils/angular-utils"; import { IONIC_COMPONENTS } from "../../utils/ionic-utils"; import { @@ -26,6 +27,7 @@ import { import { addImportToClass, getOrCreateConstructor, + removeImportFromClass, } from "../../utils/typescript-utils"; import { saveFileChanges } from "../../utils/log-utils"; @@ -115,6 +117,8 @@ async function migrateAngularComponentClass( if (isAngularComponentStandalone(sourceFile)) { const componentClassName = kebabCaseToPascalCase(ionicComponent); addImportToComponentDecorator(sourceFile, componentClassName); + removeImportFromComponentDecorator(sourceFile, 'IonicModule'); + removeImportFromClass(sourceFile, 'IonicModule', '@ionic/angular'); addImportToClass( sourceFile, componentClassName, diff --git a/packages/cli/src/angular/utils/angular-utils.ts b/packages/cli/src/angular/utils/angular-utils.ts index 4278b48..bbe6bb0 100644 --- a/packages/cli/src/angular/utils/angular-utils.ts +++ b/packages/cli/src/angular/utils/angular-utils.ts @@ -122,6 +122,29 @@ export function addImportToComponentDecorator( sourceFile.formatText(); } +/** + * Removes an import from the imports array in the Component decorator. + * @param sourceFile The source file to remove the import from. + * @param importName The name of the import to remove. + */ +export function removeImportFromComponentDecorator( + sourceFile: SourceFile, + importName: string, +) { + if (!isAngularComponentStandalone(sourceFile)) { + console.warn( + "[Ionic Dev] Cannot remove import from component decorator. Component is not standalone.", + ); + return; + } + + const componentDecorator = getAngularComponentDecorator(sourceFile)!; + + deleteFromDecoratorArgArray(componentDecorator, "imports", importName); + + sourceFile.formatText(); +} + /** * Adds a new import to the imports array in the NgModule decorator. * @param sourceFile The source file to add the import to. diff --git a/packages/cli/src/angular/utils/typescript-utils.test.ts b/packages/cli/src/angular/utils/typescript-utils.test.ts index da22822..45684a4 100644 --- a/packages/cli/src/angular/utils/typescript-utils.test.ts +++ b/packages/cli/src/angular/utils/typescript-utils.test.ts @@ -2,7 +2,7 @@ import { describe, it, expect } from "vitest"; import { Project } from "ts-morph"; import { dedent } from "ts-dedent"; -import { getOrCreateConstructor, addImportToClass } from "./typescript-utils"; +import { getOrCreateConstructor, addImportToClass, removeImportFromClass } from "./typescript-utils"; describe("getOrCreateConstructor", () => { it("should return the existing constructor", () => { @@ -109,3 +109,60 @@ describe("addImportToClass", () => { ); }); }); + +describe("removeImportFromClass", () => { + + it("should remove an import from a class", () => { + const sourceFileContent = ` + import { Component } from "@angular/core"; + export class Foo { } + `; + + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile("foo.ts", sourceFileContent); + + removeImportFromClass(sourceFile, "Component", "@angular/core"); + + expect(dedent(sourceFile.getText())).toBe( + dedent(` + export class Foo { } + `), + ); + }); + + it("should remove an import from an existing import declaration", () => { + const sourceFileContent = ` + import { Injectable, Component } from "@angular/core"; + export class Foo { } + `; + + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile("foo.ts", sourceFileContent); + + removeImportFromClass(sourceFile, "Component", "@angular/core"); + + expect(dedent(sourceFile.getText())).toBe( + dedent(` + import { Injectable } from "@angular/core"; + export class Foo { } + `), + ); + }); + + it("should do nothing if the source file does not have a class", () => { + const sourceFileContent = ` + export function foo() { } + `; + + const project = new Project({ useInMemoryFileSystem: true }); + const sourceFile = project.createSourceFile("foo.ts", sourceFileContent); + + removeImportFromClass(sourceFile, "Component", "@angular/core"); + + expect(dedent(sourceFile.getText())).toBe( + dedent(` + export function foo() { } + `), + ); + }); +}); \ No newline at end of file diff --git a/packages/cli/src/angular/utils/typescript-utils.ts b/packages/cli/src/angular/utils/typescript-utils.ts index c45713d..6062304 100644 --- a/packages/cli/src/angular/utils/typescript-utils.ts +++ b/packages/cli/src/angular/utils/typescript-utils.ts @@ -53,3 +53,41 @@ export function addImportToClass( addImport(sourceFile, importName, moduleSpecifier); } } + +export function removeImportFromClass( + sourceFile: SourceFile, + importName: string | string[], + moduleSpecifier: string, +) { + const removeImport = ( + sourceFile: SourceFile, + importName: string, + moduleSpecifier: string, + ) => { + const importDeclaration = sourceFile.getImportDeclaration(moduleSpecifier); + + if (!importDeclaration) { + return; + } + + const importSpecifier = importDeclaration + .getNamedImports() + .find((n) => n.getName() === importName); + + if (importSpecifier) { + importSpecifier.remove(); + } + + if (importDeclaration.getNamedImports().length === 0) { + importDeclaration.remove(); + } + }; + + if (Array.isArray(importName)) { + importName.forEach((name) => { + removeImport(sourceFile, name, moduleSpecifier); + }); + } else { + removeImport(sourceFile, importName, moduleSpecifier); + } +} \ No newline at end of file