From b97d770e609a6839b2231b73f94503c696e7220c Mon Sep 17 00:00:00 2001 From: George Kalpakas Date: Mon, 30 Jul 2018 23:15:58 +0300 Subject: [PATCH] feat(ivy): add support for typings in ngcc (#25406) PR Close #25406 --- .../ngcc/src/transform/package_transformer.ts | 57 ++++++++++++++++--- .../compiler-cli/src/ngtsc/transform/index.ts | 3 +- 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/packages/compiler-cli/src/ngcc/src/transform/package_transformer.ts b/packages/compiler-cli/src/ngcc/src/transform/package_transformer.ts index c500d757ea..8ce7d995df 100644 --- a/packages/compiler-cli/src/ngcc/src/transform/package_transformer.ts +++ b/packages/compiler-cli/src/ngcc/src/transform/package_transformer.ts @@ -5,19 +5,22 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {writeFileSync} from 'fs'; +import {readFileSync, writeFileSync} from 'fs'; import {dirname, relative, resolve} from 'path'; import {mkdir} from 'shelljs'; import * as ts from 'typescript'; +import {DtsFileTransformer} from '../../../ngtsc/transform'; + import {AnalyzedFile, Analyzer} from '../analyzer'; +import {IMPORT_PREFIX} from '../constants'; import {Esm2015ReflectionHost} from '../host/esm2015_host'; import {Esm5ReflectionHost} from '../host/esm5_host'; import {NgccReflectionHost} from '../host/ngcc_host'; import {Esm2015FileParser} from '../parsing/esm2015_parser'; import {Esm5FileParser} from '../parsing/esm5_parser'; import {FileParser} from '../parsing/file_parser'; -import {getEntryPoints} from '../parsing/utils'; +import {EntryPoint, getEntryPoints} from '../parsing/utils'; import {Esm2015Renderer} from '../rendering/esm2015_renderer'; import {Esm5Renderer} from '../rendering/esm5_renderer'; import {FileInfo, Renderer} from '../rendering/renderer'; @@ -25,17 +28,19 @@ import {FileInfo, Renderer} from '../rendering/renderer'; /** * A Package is stored in a directory on disk and that directory can contain one or more package - formats - e.g. fesm2015, UMD, etc. + * formats - e.g. fesm2015, UMD, etc. Additionally, each package provides typings (`.d.ts` files). * * Each of these formats exposes one or more entry points, which are source files that need to be * parsed to identify the decorated exported classes that need to be analyzed and compiled by one or * more `DecoratorHandler` objects. * - * Each entry point to a package is identified by a `SourceFile` that can be parsed and analyzed - * to identify classes that need to be transformed; and then finally rendered and written to disk. - + * Each entry point to a package is identified by a `SourceFile` that can be parsed and analyzed to + * identify classes that need to be transformed; and then finally rendered and written to disk. * The actual file which needs to be transformed depends upon the package format. * + * Along with the source files, the corresponding source maps (either inline or external) and + * `.d.ts` files are transformed accordingly. + * * - Flat file packages have all the classes in a single file. * - Other packages may re-export classes from other non-entry point files. * - Some formats may contain multiple "modules" in a single file. @@ -73,6 +78,14 @@ export class PackageTransformer { outputFiles.push(...this.transformSourceFiles( analyzedFiles, sourceNodeModules, targetNodeModules, renderer)); + // Transform the `.d.ts` files (if necessary). + // TODO(gkalpak): What about `.d.ts` source maps? (See + // https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-9.html#new---declarationmap.) + if (format === 'esm2015') { + outputFiles.push(...this.transformDtsFiles( + analyzedFiles, sourceNodeModules, targetNodeModules, entryPoint)); + } + // Write out all the transformed files. outputFiles.forEach(file => this.writeFile(file)); }); @@ -124,13 +137,43 @@ export class PackageTransformer { return src; } + transformDtsFiles( + analyzedFiles: AnalyzedFile[], sourceNodeModules: string, targetNodeModules: string, + entryPoint: EntryPoint): FileInfo[] { + const outputFiles: FileInfo[] = []; + + analyzedFiles.forEach(analyzedFile => { + // Create a `DtsFileTransformer` for the source file and record the generated fields, which + // will allow the corresponding `.d.ts` file to be transformed later. + const dtsTransformer = new DtsFileTransformer(null, IMPORT_PREFIX); + analyzedFile.analyzedClasses.forEach( + analyzedClass => + dtsTransformer.recordStaticField(analyzedClass.name, analyzedClass.compilation)); + + // Find the corresponding `.d.ts` file. + const sourceFileName = analyzedFile.sourceFile.fileName; + const originalDtsFileName = entryPoint.getDtsFileNameFor(sourceFileName); + const originalDtsContents = readFileSync(originalDtsFileName, 'utf8'); + + // Transform the `.d.ts` file based on the recorded source file changes. + const transformedDtsFileName = + resolve(targetNodeModules, relative(sourceNodeModules, originalDtsFileName)); + const transformedDtsContents = dtsTransformer.transform(originalDtsContents, sourceFileName); + + // Add the transformed `.d.ts` file to the list of output files. + outputFiles.push({path: transformedDtsFileName, contents: transformedDtsContents}); + }); + + return outputFiles; + } + transformSourceFiles( analyzedFiles: AnalyzedFile[], sourceNodeModules: string, targetNodeModules: string, renderer: Renderer): FileInfo[] { const outputFiles: FileInfo[] = []; analyzedFiles.forEach(analyzedFile => { - // Tranform the source file based on the recorded changes. + // Transform the source file based on the recorded changes. const targetPath = resolve(targetNodeModules, relative(sourceNodeModules, analyzedFile.sourceFile.fileName)); const {source, map} = renderer.renderFile(analyzedFile, targetPath); diff --git a/packages/compiler-cli/src/ngtsc/transform/index.ts b/packages/compiler-cli/src/ngtsc/transform/index.ts index 00eea48b13..30cde5930b 100644 --- a/packages/compiler-cli/src/ngtsc/transform/index.ts +++ b/packages/compiler-cli/src/ngtsc/transform/index.ts @@ -8,5 +8,6 @@ export * from './src/api'; export {IvyCompilation} from './src/compilation'; +export {DtsFileTransformer} from './src/declaration'; export {ivyTransformFactory} from './src/transform'; -export {ImportManager, translateStatement} from './src/translator'; \ No newline at end of file +export {ImportManager, translateStatement} from './src/translator';