diff --git a/packages/core/schematics/migrations/renderer-to-renderer2/index.ts b/packages/core/schematics/migrations/renderer-to-renderer2/index.ts index bf8345705acf4..7144db130eb63 100644 --- a/packages/core/schematics/migrations/renderer-to-renderer2/index.ts +++ b/packages/core/schematics/migrations/renderer-to-renderer2/index.ts @@ -18,18 +18,17 @@ import {HelperFunction, getHelper} from './helpers'; import {migrateExpression, replaceImport} from './migration'; import {findCoreImport, findRendererReferences} from './util'; - +const MODULE_AUGMENTATION_FILENAME = 'ɵɵRENDERER_MIGRATION_CORE_AUGMENTATION.d.ts'; /** * Migration that switches from `Renderer` to `Renderer2`. More information on how it works: * https://hackmd.angular.io/UTzUZTnPRA-cSa_4mHyfYw */ export default function(): Rule { - return (tree: Tree, context: SchematicContext) => { + return (tree: Tree) => { const {buildPaths, testPaths} = getProjectTsConfigPaths(tree); const basePath = process.cwd(); const allPaths = [...buildPaths, ...testPaths]; - const logger = context.logger; if (!allPaths.length) { throw new SchematicsException( @@ -44,8 +43,23 @@ export default function(): Rule { function runRendererToRenderer2Migration(tree: Tree, tsconfigPath: string, basePath: string) { const parsed = parseTsconfigFile(tsconfigPath, dirname(tsconfigPath)); - const host = createMigrationCompilerHost(tree, parsed.options, basePath); - const program = ts.createProgram(parsed.fileNames, parsed.options, host); + const host = createMigrationCompilerHost(tree, parsed.options, basePath, fileName => { + // In case the module augmentation file has been requested, we return a source file that + // augments "@angular/core" to include a named export called "Renderer". This ensures that + // we can rely on the type checker for this migration in v9 where "Renderer" has been removed. + if (fileName === MODULE_AUGMENTATION_FILENAME) { + return ` + import '@angular/core'; + declare module "@angular/core" { + class Renderer {} + } + `; + } + return null; + }); + + const program = + ts.createProgram(parsed.fileNames.concat(MODULE_AUGMENTATION_FILENAME), parsed.options, host); const typeChecker = program.getTypeChecker(); const printer = ts.createPrinter(); const sourceFiles = program.getSourceFiles().filter( diff --git a/packages/core/schematics/test/renderer_to_renderer2_migration_spec.ts b/packages/core/schematics/test/renderer_to_renderer2_migration_spec.ts index adf94c84f39e9..c30919ea5d9c8 100644 --- a/packages/core/schematics/test/renderer_to_renderer2_migration_spec.ts +++ b/packages/core/schematics/test/renderer_to_renderer2_migration_spec.ts @@ -35,7 +35,6 @@ describe('Renderer to Renderer2 migration', () => { })); // We need to declare the Angular symbols we're testing for, otherwise type checking won't work. writeFile('/node_modules/@angular/core/index.d.ts', ` - export declare abstract class Renderer {} export declare function forwardRef(fn: () => any): any {} `); diff --git a/packages/core/schematics/utils/typescript/compiler_host.ts b/packages/core/schematics/utils/typescript/compiler_host.ts index 7fcf339a3982c..25f4f083abe51 100644 --- a/packages/core/schematics/utils/typescript/compiler_host.ts +++ b/packages/core/schematics/utils/typescript/compiler_host.ts @@ -10,7 +10,8 @@ import {relative} from 'path'; import * as ts from 'typescript'; export function createMigrationCompilerHost( - tree: Tree, options: ts.CompilerOptions, basePath: string): ts.CompilerHost { + tree: Tree, options: ts.CompilerOptions, basePath: string, + fakeRead?: (fileName: string) => string | null): ts.CompilerHost { const host = ts.createCompilerHost(options, true); // We need to overwrite the host "readFile" method, as we want the TypeScript @@ -18,7 +19,9 @@ export function createMigrationCompilerHost( // if we run multiple migrations we might have intersecting changes and // source files. host.readFile = fileName => { - const buffer = tree.read(relative(basePath, fileName)); + const treeRelativePath = relative(basePath, fileName); + const fakeOutput = fakeRead ? fakeRead(treeRelativePath) : null; + const buffer = fakeOutput === null ? tree.read(treeRelativePath) : fakeOutput; // Strip BOM as otherwise TSC methods (Ex: getWidth) will return an offset which // which breaks the CLI UpdateRecorder. // See: https://github.com/angular/angular/pull/30719