refactor(ivy): ngcc - `Transformer` delegates to `Analyzer`s and `Renderer` (#26082)
PR Close #26082
This commit is contained in:
parent
632f66a461
commit
34b6d5fff9
|
@ -5,14 +5,13 @@
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
* 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
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
import {dirname, relative, resolve} from 'canonical-path';
|
import {dirname, resolve} from 'canonical-path';
|
||||||
import {existsSync, lstatSync, readFileSync, readdirSync, writeFileSync} from 'fs';
|
import {existsSync, lstatSync, readdirSync, writeFileSync} from 'fs';
|
||||||
import {mkdir, mv} from 'shelljs';
|
import {mkdir, mv} from 'shelljs';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {DtsFileTransformer} from '../../../ngtsc/transform';
|
import {DecorationAnalyzer} from '../analysis/decoration_analyzer';
|
||||||
import {DecorationAnalysis, DecorationAnalyzer} from '../analysis/decoration_analyzer';
|
import {SwitchMarkerAnalyzer} from '../analysis/switch_marker_analyzer';
|
||||||
import {IMPORT_PREFIX} from '../constants';
|
|
||||||
import {DtsMapper} from '../host/dts_mapper';
|
import {DtsMapper} from '../host/dts_mapper';
|
||||||
import {Esm2015ReflectionHost} from '../host/esm2015_host';
|
import {Esm2015ReflectionHost} from '../host/esm2015_host';
|
||||||
import {Esm5ReflectionHost} from '../host/esm5_host';
|
import {Esm5ReflectionHost} from '../host/esm5_host';
|
||||||
|
@ -20,6 +19,7 @@ import {Fesm2015ReflectionHost} from '../host/fesm2015_host';
|
||||||
import {NgccReflectionHost} from '../host/ngcc_host';
|
import {NgccReflectionHost} from '../host/ngcc_host';
|
||||||
import {Esm2015Renderer} from '../rendering/esm2015_renderer';
|
import {Esm2015Renderer} from '../rendering/esm2015_renderer';
|
||||||
import {Esm5Renderer} from '../rendering/esm5_renderer';
|
import {Esm5Renderer} from '../rendering/esm5_renderer';
|
||||||
|
import {Fesm2015Renderer} from '../rendering/fesm2015_renderer';
|
||||||
import {FileInfo, Renderer} from '../rendering/renderer';
|
import {FileInfo, Renderer} from '../rendering/renderer';
|
||||||
|
|
||||||
import {checkMarkerFile, writeMarkerFile} from './build_marker';
|
import {checkMarkerFile, writeMarkerFile} from './build_marker';
|
||||||
|
@ -52,7 +52,6 @@ export class Transformer {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const outputFiles: FileInfo[] = [];
|
|
||||||
const options: ts.CompilerOptions = {
|
const options: ts.CompilerOptions = {
|
||||||
allowJs: true,
|
allowJs: true,
|
||||||
maxNodeModuleJsDepth: Infinity,
|
maxNodeModuleJsDepth: Infinity,
|
||||||
|
@ -72,35 +71,22 @@ export class Transformer {
|
||||||
const r3SymbolsPath = isCore ? this.findR3SymbolsPath(dirname(entryPointFilePath)) : null;
|
const r3SymbolsPath = isCore ? this.findR3SymbolsPath(dirname(entryPointFilePath)) : null;
|
||||||
const rootPaths = r3SymbolsPath ? [entryPointFilePath, r3SymbolsPath] : [entryPointFilePath];
|
const rootPaths = r3SymbolsPath ? [entryPointFilePath, r3SymbolsPath] : [entryPointFilePath];
|
||||||
const packageProgram = ts.createProgram(rootPaths, options, host);
|
const packageProgram = ts.createProgram(rootPaths, options, host);
|
||||||
const typeChecker = packageProgram.getTypeChecker();
|
|
||||||
const dtsMapper = new DtsMapper(dirname(entryPointFilePath), dirname(entryPoint.typings));
|
const dtsMapper = new DtsMapper(dirname(entryPointFilePath), dirname(entryPoint.typings));
|
||||||
const reflectionHost = this.getHost(isCore, format, packageProgram, dtsMapper);
|
const reflectionHost = this.getHost(isCore, format, packageProgram, dtsMapper);
|
||||||
const r3SymbolsFile = r3SymbolsPath && packageProgram.getSourceFile(r3SymbolsPath) || null;
|
const r3SymbolsFile = r3SymbolsPath && packageProgram.getSourceFile(r3SymbolsPath) || null;
|
||||||
|
|
||||||
const analyzer = new DecorationAnalyzer(typeChecker, reflectionHost, rootDirs, isCore);
|
|
||||||
const renderer =
|
|
||||||
this.getRenderer(format, packageProgram, reflectionHost, isCore, r3SymbolsFile);
|
|
||||||
|
|
||||||
// Parse and analyze the files.
|
// Parse and analyze the files.
|
||||||
const entryPointFile = packageProgram.getSourceFile(entryPointFilePath) !;
|
const {decorationAnalyses, switchMarkerAnalyses} =
|
||||||
const decoratedFiles = reflectionHost.findDecoratedFiles(entryPointFile);
|
this.analyzeProgram(packageProgram, reflectionHost, rootDirs, isCore);
|
||||||
const analyzedFiles = Array.from(decoratedFiles.values())
|
|
||||||
.map(decoratedFile => analyzer.analyzeFile(decoratedFile));
|
|
||||||
|
|
||||||
// Transform the source files and source maps.
|
// Transform the source files and source maps.
|
||||||
outputFiles.push(
|
const renderer =
|
||||||
...this.transformSourceFiles(analyzedFiles, this.sourcePath, this.targetPath, renderer));
|
this.getRenderer(format, packageProgram, reflectionHost, isCore, r3SymbolsFile, dtsMapper);
|
||||||
|
const renderedFiles =
|
||||||
// Transform the `.d.ts` files (if necessary).
|
renderer.renderProgram(packageProgram, decorationAnalyses, switchMarkerAnalyses);
|
||||||
// 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, this.sourcePath, this.targetPath, dtsMapper));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write out all the transformed files.
|
// Write out all the transformed files.
|
||||||
outputFiles.forEach(file => this.writeFile(file));
|
renderedFiles.forEach(file => this.writeFile(file));
|
||||||
|
|
||||||
// Write the built-with-ngcc marker
|
// Write the built-with-ngcc marker
|
||||||
writeMarkerFile(entryPoint, format);
|
writeMarkerFile(entryPoint, format);
|
||||||
|
@ -133,68 +119,33 @@ export class Transformer {
|
||||||
|
|
||||||
getRenderer(
|
getRenderer(
|
||||||
format: string, program: ts.Program, host: NgccReflectionHost, isCore: boolean,
|
format: string, program: ts.Program, host: NgccReflectionHost, isCore: boolean,
|
||||||
rewriteCoreImportsTo: ts.SourceFile|null): Renderer {
|
rewriteCoreImportsTo: ts.SourceFile|null, dtsMapper: DtsMapper): Renderer {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case 'esm2015':
|
case 'esm2015':
|
||||||
|
return new Esm2015Renderer(
|
||||||
|
host, isCore, rewriteCoreImportsTo, this.sourcePath, this.targetPath, dtsMapper);
|
||||||
case 'fesm2015':
|
case 'fesm2015':
|
||||||
return new Esm2015Renderer(host, isCore, rewriteCoreImportsTo);
|
return new Fesm2015Renderer(
|
||||||
|
host, isCore, rewriteCoreImportsTo, this.sourcePath, this.targetPath);
|
||||||
case 'esm5':
|
case 'esm5':
|
||||||
case 'fesm5':
|
case 'fesm5':
|
||||||
return new Esm5Renderer(host, isCore, rewriteCoreImportsTo);
|
return new Esm5Renderer(
|
||||||
|
host, isCore, rewriteCoreImportsTo, this.sourcePath, this.targetPath);
|
||||||
default:
|
default:
|
||||||
throw new Error(`Renderer for "${format}" not yet implemented.`);
|
throw new Error(`Renderer for "${format}" not yet implemented.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
transformDtsFiles(
|
analyzeProgram(
|
||||||
analyzedFiles: DecorationAnalysis[], sourceNodeModules: string, targetNodeModules: string,
|
program: ts.Program, reflectionHost: NgccReflectionHost, rootDirs: string[],
|
||||||
dtsMapper: DtsMapper): FileInfo[] {
|
isCore: boolean) {
|
||||||
const outputFiles: FileInfo[] = [];
|
const decorationAnalyzer =
|
||||||
|
new DecorationAnalyzer(program.getTypeChecker(), reflectionHost, rootDirs, isCore);
|
||||||
analyzedFiles.forEach(analyzedFile => {
|
const switchMarkerAnalyzer = new SwitchMarkerAnalyzer(reflectionHost);
|
||||||
// Create a `DtsFileTransformer` for the source file and record the generated fields, which
|
return {
|
||||||
// will allow the corresponding `.d.ts` file to be transformed later.
|
decorationAnalyses: decorationAnalyzer.analyzeProgram(program),
|
||||||
const dtsTransformer = new DtsFileTransformer(null, IMPORT_PREFIX);
|
switchMarkerAnalyses: switchMarkerAnalyzer.analyzeProgram(program),
|
||||||
analyzedFile.analyzedClasses.forEach(
|
};
|
||||||
analyzedClass =>
|
|
||||||
dtsTransformer.recordStaticField(analyzedClass.name, analyzedClass.compilation));
|
|
||||||
|
|
||||||
// Find the corresponding `.d.ts` file.
|
|
||||||
const sourceFileName = analyzedFile.sourceFile.fileName;
|
|
||||||
const originalDtsFileName = dtsMapper.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: DecorationAnalysis[], sourceNodeModules: string, targetNodeModules: string,
|
|
||||||
renderer: Renderer): FileInfo[] {
|
|
||||||
const outputFiles: FileInfo[] = [];
|
|
||||||
|
|
||||||
analyzedFiles.forEach(analyzedFile => {
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Add the transformed file (and source map, if available) to the list of output files.
|
|
||||||
outputFiles.push(source);
|
|
||||||
if (map) {
|
|
||||||
outputFiles.push(map);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return outputFiles;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
writeFile(file: FileInfo): void {
|
writeFile(file: FileInfo): void {
|
||||||
|
|
Loading…
Reference in New Issue