diff --git a/apps/angular/ionic-angular-modules/package.json b/apps/angular/ionic-angular-modules/package.json index fd07ac0..b8b2374 100644 --- a/apps/angular/ionic-angular-modules/package.json +++ b/apps/angular/ionic-angular-modules/package.json @@ -18,7 +18,7 @@ "@angular/platform-browser": "^16.0.0", "@angular/platform-browser-dynamic": "^16.0.0", "@angular/router": "^16.0.0", - "@ionic/angular": "^7.0.0", + "@ionic/angular": "^7.5.0", "ionicons": "^7.0.0", "rxjs": "~7.8.0", "tslib": "^2.3.0", diff --git a/apps/angular/ionic-angular-standalone/package.json b/apps/angular/ionic-angular-standalone/package.json index 1522c62..d1f9b02 100644 --- a/apps/angular/ionic-angular-standalone/package.json +++ b/apps/angular/ionic-angular-standalone/package.json @@ -26,7 +26,7 @@ "@capacitor/haptics": "5.0.6", "@capacitor/keyboard": "5.0.6", "@capacitor/status-bar": "5.0.6", - "@ionic/angular": "^7.0.0", + "@ionic/angular": "^7.5.0", "ionicons": "^7.0.0", "rxjs": "~7.8.0", "tslib": "^2.3.0", diff --git a/apps/angular/ionic-angular-standalone/src/app/view-child/view-child.page.html b/apps/angular/ionic-angular-standalone/src/app/view-child/view-child.page.html new file mode 100644 index 0000000..89b56ea --- /dev/null +++ b/apps/angular/ionic-angular-standalone/src/app/view-child/view-child.page.html @@ -0,0 +1,13 @@ + + + view-child + + + + + + + view-child + + + diff --git a/apps/angular/ionic-angular-standalone/src/app/view-child/view-child.page.ts b/apps/angular/ionic-angular-standalone/src/app/view-child/view-child.page.ts new file mode 100644 index 0000000..a29802a --- /dev/null +++ b/apps/angular/ionic-angular-standalone/src/app/view-child/view-child.page.ts @@ -0,0 +1,22 @@ +import { Component, OnInit, ViewChild } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; +import { IonContent, IonicModule } from '@ionic/angular'; + +@Component({ + selector: 'app-view-child', + templateUrl: './view-child.page.html', + standalone: true, + imports: [IonicModule, CommonModule, FormsModule], +}) +export class ViewChildPage implements OnInit { + /** + * Referencing the template's ion-content results in a double call. + */ + @ViewChild(IonContent) + content!: IonContent; + + constructor() {} + + ngOnInit() {} +} 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 b2df8a8..39c0cbe 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 @@ -167,6 +167,49 @@ describe("migrateComponents", () => { ); }); + it("should remove duplicate imports from existing declarations", async () => { + const project = new Project({ useInMemoryFileSystem: true }); + + const component = ` + import { Component, ViewChild } from "@angular/core"; + import { IonContent, IonicModule } from "@ionic/angular"; + + @Component({ + selector: 'my-component', + template: '', + standalone: true, + imports: [IonicModule] + }) + export class MyComponent { + @ViewChild(IonContent) content!: IonContent; + } + `; + + const componentSourceFile = project.createSourceFile( + "foo.component.ts", + dedent(component), + ); + + await migrateComponents(project, { dryRun: false }); + + expect(dedent(componentSourceFile.getText())).toBe( + dedent(` + import { Component, ViewChild } from "@angular/core"; + import { IonContent } from "@ionic/angular/standalone"; + + @Component({ + selector: 'my-component', + template: '', + standalone: true, + imports: [IonContent] + }) + export class MyComponent { + @ViewChild(IonContent) content!: IonContent; + } + `), + ); + }); + describe("hyperlinks", () => { it("should detect and import routerLink used in the template", async () => { const project = new Project({ useInMemoryFileSystem: true }); 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 4084c94..ca9ec13 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 @@ -154,6 +154,12 @@ async function migrateAngularComponentClass( componentClassName, "@ionic/angular/standalone", ); + /** + * This removes the import from the class, if it is present. + * An example where it may exist is when the developer has + * a @ViewChild decorator that references an ionic component. + */ + removeImportFromClass(sourceFile, componentClassName, "@ionic/angular"); } else if (ngModuleSourceFile) { const componentClassName = kebabCaseToPascalCase(ionicComponent); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3ed00d4..ddb7b12 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -48,8 +48,8 @@ importers: specifier: ^16.0.0 version: 16.0.0(@angular/common@16.0.0)(@angular/core@16.0.0)(@angular/platform-browser@16.0.0)(rxjs@7.8.1) '@ionic/angular': - specifier: ^7.0.0 - version: 7.0.0(@angular/core@16.0.0)(@angular/forms@16.0.0)(@angular/router@16.0.0)(rxjs@7.8.1)(zone.js@0.13.0) + specifier: ^7.5.0 + version: 7.5.0(@angular/core@16.0.0)(@angular/forms@16.0.0)(@angular/router@16.0.0)(rxjs@7.8.1)(zone.js@0.13.0) ionicons: specifier: ^7.0.0 version: 7.0.0 @@ -139,8 +139,8 @@ importers: specifier: 5.0.6 version: 5.0.6(@capacitor/core@5.4.0) '@ionic/angular': - specifier: ^7.0.0 - version: 7.0.0(@angular/core@16.0.0)(@angular/forms@16.0.0)(@angular/router@16.0.0)(rxjs@7.8.1)(zone.js@0.13.0) + specifier: ^7.5.0 + version: 7.5.0(@angular/core@16.0.0)(@angular/forms@16.0.0)(@angular/router@16.0.0)(rxjs@7.8.1)(zone.js@0.13.0) ionicons: specifier: ^7.0.0 version: 7.0.0 @@ -2791,8 +2791,8 @@ packages: - chokidar dev: true - /@ionic/angular@7.0.0(@angular/core@16.0.0)(@angular/forms@16.0.0)(@angular/router@16.0.0)(rxjs@7.8.1)(zone.js@0.13.0): - resolution: {integrity: sha512-vsSOPoWyO8Wl2EcUG9VJN50HsLG5B08q2mz/D6WAWeG0VlFGS2OdjtBOsFT3UKWuznuACxnTPNdUCk9JtFCgRw==} + /@ionic/angular@7.5.0(@angular/core@16.0.0)(@angular/forms@16.0.0)(@angular/router@16.0.0)(rxjs@7.8.1)(zone.js@0.13.0): + resolution: {integrity: sha512-0eZB/2/4ArfBt6YcYDF8VwfK0J8VRmywpbzlmsQXrubOAqd+Xaq2yYfLmzRfyrdKBhg7TyA+L6MyJ6w0Y7fbXA==} peerDependencies: '@angular/core': '>=14.0.0' '@angular/forms': '>=14.0.0' @@ -2803,7 +2803,7 @@ packages: '@angular/core': 16.0.0(rxjs@7.8.1)(zone.js@0.13.0) '@angular/forms': 16.0.0(@angular/common@16.0.0)(@angular/core@16.0.0)(@angular/platform-browser@16.0.0)(rxjs@7.8.1) '@angular/router': 16.0.0(@angular/common@16.0.0)(@angular/core@16.0.0)(@angular/platform-browser@16.0.0)(rxjs@7.8.1) - '@ionic/core': 7.0.0 + '@ionic/core': 7.5.0 ionicons: 7.1.2 jsonc-parser: 3.2.0 rxjs: 7.8.1 @@ -2822,11 +2822,11 @@ packages: - supports-color dev: true - /@ionic/core@7.0.0: - resolution: {integrity: sha512-pM8qOaea9ZbqZbGnoIswaeeTiHJKNQ9ziSNHSILDpdd4FjpxZjOeMgNUdvYzh5rX9fA6hEM2wodg7McIWHgvZQ==} + /@ionic/core@7.5.0: + resolution: {integrity: sha512-oreRvbKj8VqqO9JraxR/n56GC6MHQtnJEmZf/EFuw5ZvDV8My91uNIzLkb4P9SvPL5NRr/Z0TFem28cgRf5YVA==} dependencies: - '@stencil/core': 3.4.2 - ionicons: 7.1.2 + '@stencil/core': 4.4.1 + ionicons: 7.2.1 tslib: 2.5.0 dev: false @@ -3323,9 +3323,9 @@ packages: hasBin: true dev: false - /@stencil/core@3.4.2: - resolution: {integrity: sha512-FAUhUVaakCy29nU2GwO/HQBRV1ihPRvncz3PUc8oR+UJLAxGabTmP8PLY7wvHfbw+Cvi4VXfJFTBvdfDu6iKPQ==} - engines: {node: '>=14.10.0', npm: '>=6.0.0'} + /@stencil/core@4.4.1: + resolution: {integrity: sha512-SirGcrb5yKHCn2BwdM7HGVXuvCdmwiXlVczEj8jJxQIm42CAUQCUECxtZidTzp+oZBZnWLnoAvfanchJsgkQzA==} + engines: {node: '>=16.0.0', npm: '>=7.10.0'} hasBin: true dev: false @@ -7386,6 +7386,12 @@ packages: '@stencil/core': 2.22.3 dev: false + /ionicons@7.2.1: + resolution: {integrity: sha512-2pvCM7DGVEtbbj48PJzQrCADCQrqjU1nUYX9l9PyEWz3ZfdnLdAouqwPxLdl8tbaF9cE7OZRSlyQD7oLOLnGoQ==} + dependencies: + '@stencil/core': 4.4.1 + dev: false + /ip@2.0.0: resolution: {integrity: sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==} dev: true