diff --git a/packages/apollo-angular/CHANGELOG.md b/packages/apollo-angular/CHANGELOG.md index d94a85c23..b79f6ada8 100644 --- a/packages/apollo-angular/CHANGELOG.md +++ b/packages/apollo-angular/CHANGELOG.md @@ -2,6 +2,10 @@ ### vNext +### v2.0.2 + +- Fix duplicated imports in v2 migration + ### v2.0.1 - Fix missing migration code diff --git a/packages/apollo-angular/schematics/migrations/v2.ts b/packages/apollo-angular/schematics/migrations/v2.ts index 52943aa94..2a623d8f3 100644 --- a/packages/apollo-angular/schematics/migrations/v2.ts +++ b/packages/apollo-angular/schematics/migrations/v2.ts @@ -44,7 +44,7 @@ function migrateDependencies() { 'apollo-link-ws', 'apollo-angular-link-http', 'apollo-angular-link-http-batch', - 'apollo-angular-link-headers' + 'apollo-angular-link-headers', ]; const removedPackages: string[] = []; @@ -122,55 +122,55 @@ function getIdentifiers( } export async function migrateImports(tree: Tree) { - const importsMap: Record< - string, - Array<{ - name: string; - alias?: string; - }> - > = {}; - - function collectIdentifiers( - packageName: string, - namedBindings: ts.NamedImportBindings, - ) { - getIdentifiers(namedBindings, ({name, alias}) => { - if (!importsMap[packageName]) { - importsMap[packageName] = []; - } - - importsMap[packageName].push({ - name, - alias, - }); - }); - } + tree.visit((path) => { + if (path.includes('node_modules') || !path.endsWith('.ts')) { + return; + } - function redirectImport({ - source, - target, - modulePath, - statement, - recorder, - }: { - source: string; - target: string; - modulePath: string; - statement: any; - recorder: UpdateRecorder; - }) { - if (modulePath === source) { - if (statement.importClause.namedBindings) { - collectIdentifiers(target, statement.importClause.namedBindings); - } + const importsMap: Record< + string, + Array<{ + name: string; + alias?: string; + }> + > = {}; + + function collectIdentifiers( + packageName: string, + namedBindings: ts.NamedImportBindings, + ) { + getIdentifiers(namedBindings, ({name, alias}) => { + if (!importsMap[packageName]) { + importsMap[packageName] = []; + } - recorder.remove(statement.getStart(), statement.getWidth()); + importsMap[packageName].push({ + name, + alias, + }); + }); } - } - tree.visit((path) => { - if (path.includes('node_modules') || !path.endsWith('.ts')) { - return; + function redirectImport({ + source, + target, + modulePath, + statement, + recorder, + }: { + source: string; + target: string; + modulePath: string; + statement: any; + recorder: UpdateRecorder; + }) { + if (modulePath === source) { + if (statement.importClause.namedBindings) { + collectIdentifiers(target, statement.importClause.namedBindings); + } + + recorder.remove(statement.getStart(), statement.getWidth()); + } } const sourceFile = ts.createSourceFile( @@ -316,12 +316,12 @@ export async function migrateImports(tree: Tree) { if (!importsMap['apollo-angular']) { importsMap['apollo-angular'] = []; } + + const alias = statement.importClause.name.escapedText.toString(); + importsMap['apollo-angular'].push({ name: 'gql', - alias: - statement.importClause.name.escapedText.toString() === 'gql' - ? undefined - : statement.importClause.name.escapedText.toString(), + alias: alias !== 'gql' ? alias : undefined, }); recorder.remove(statement.getStart(), statement.getWidth()); @@ -330,6 +330,7 @@ export async function migrateImports(tree: Tree) { }); const importSources = Object.keys(importsMap); + importSources.forEach((importSource) => { const props = importsMap[importSource] .map((im) => (im.alias ? `${im.name} as ${im.alias}` : im.name)) diff --git a/packages/apollo-angular/schematics/tests/migration-v2.spec.ts b/packages/apollo-angular/schematics/tests/migration-v2.spec.ts index 1c2bf1178..b3d7c86ca 100644 --- a/packages/apollo-angular/schematics/tests/migration-v2.spec.ts +++ b/packages/apollo-angular/schematics/tests/migration-v2.spec.ts @@ -80,6 +80,37 @@ describe('Migration: Apollo Angular V2', () => { ); }); + test('should update imports without leaking to other files', async () => { + appTree.create( + 'file1.ts', + ` + import { ApolloClient } from 'apollo-client'; + import { ApolloLink } from 'apollo-link'; + `, + ); + + appTree.create( + 'file2.ts', + ` + import { InMemoryCache } from 'apollo-cache-inmemory'; + import { ApolloClient } from 'apollo-client'; + `, + ); + const tree = await runner + .runSchematicAsync(migrationName, {}, appTree) + .toPromise(); + + const file1 = tree.readContent('file1.ts').trim(); + const file2 = tree.readContent('file2.ts').trim(); + + expect(file1).toContain( + `import {ApolloClient, ApolloLink} from '@apollo/client/core';`, + ); + expect(file2).toContain( + `import {InMemoryCache, ApolloClient} from '@apollo/client/core';`, + ); + }); + test('should enable allowSyntheticDefaultImports in tsconfig.base.json', async () => { const tree = await runner .runSchematicAsync(migrationName, {}, appTree)