diff --git a/packages/core/schematics/migrations/static-queries/migration.ts b/packages/core/schematics/migrations/static-queries/migration.ts index d54a08b784..57b7822119 100644 --- a/packages/core/schematics/migrations/static-queries/migration.ts +++ b/packages/core/schematics/migrations/static-queries/migration.ts @@ -25,6 +25,16 @@ import {parseTsconfigFile} from './typescript/tsconfig'; export function runStaticQueryMigration(tree: Tree, tsconfigPath: string, basePath: string) { const parsed = parseTsconfigFile(tsconfigPath, dirname(tsconfigPath)); const host = ts.createCompilerHost(parsed.options, true); + + // We need to overwrite the host "readFile" method, as we want the TypeScript + // program to be based on the file contents in the virtual file tree. Otherwise + // if we run the migration for multiple tsconfig files which have intersecting + // source files, it can end up updating query definitions multiple times. + host.readFile = fileName => { + const buffer = tree.read(relative(basePath, fileName)); + return buffer ? buffer.toString() : undefined; + }; + const program = ts.createProgram(parsed.fileNames, parsed.options, host); const typeChecker = program.getTypeChecker(); const queryVisitor = new NgQueryResolveVisitor(typeChecker); diff --git a/packages/core/schematics/test/static_queries_migration_spec.ts b/packages/core/schematics/test/static_queries_migration_spec.ts index 8bd207ceed..dc23eae3b0 100644 --- a/packages/core/schematics/test/static_queries_migration_spec.ts +++ b/packages/core/schematics/test/static_queries_migration_spec.ts @@ -710,5 +710,30 @@ describe('static-queries migration', () => { expect(tree.readContent('/index.ts')) .toContain(`@${queryType}('test', { static: true }) query2: any;`); }); + + it('should properly handle multiple tsconfig files', () => { + writeFile('/src/index.ts', ` + import {Component, ${queryType}} from '@angular/core'; + + @Component({template: ''}) + export class MyComp { + private @${queryType}('test') query: any; + } + `); + + writeFile('/src/tsconfig.json', JSON.stringify({ + compilerOptions: { + lib: ['es2015'], + } + })); + + // The migration runs for "/tsconfig.json" and "/src/tsconfig.json" which both + // contain the "src/index.ts" file. This test ensures that we don't incorrectly + // apply the code transformation multiple times with outdated offsets. + runMigration(); + + expect(tree.readContent('/src/index.ts')) + .toContain(`@${queryType}('test', { static: false }) query: any;`); + }); } });