refactor(ivy): ngcc - move typings rendering to Renderer (#26403)

The rendering of typings is not specific to the package
format, so it doesn't make sense to put it in a specific
renderer.

As a result there is no real difference between esm5 and esm2015
renderers, so there is no point in having separate classes.

PR Close #26403
This commit is contained in:
Pete Bacon Darwin 2018-10-10 17:52:55 +01:00 committed by Kara Erickson
parent e804143183
commit dff10085e8
9 changed files with 45 additions and 100 deletions

View File

@ -16,9 +16,7 @@ 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';
import {NgccReflectionHost} from '../host/ngcc_host'; import {NgccReflectionHost} from '../host/ngcc_host';
import {Esm2015Renderer} from '../rendering/esm2015_renderer'; import {EsmRenderer} from '../rendering/esm_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';
@ -122,18 +120,13 @@ 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, dtsMapper: DtsMapper): Renderer { rewriteCoreImportsTo: ts.SourceFile|null, dtsMapper: DtsMapper|null): Renderer {
switch (format) { switch (format) {
case 'esm2015': case 'esm2015':
return new Esm2015Renderer(
host, isCore, rewriteCoreImportsTo, this.sourcePath, this.targetPath, dtsMapper);
case 'fesm2015':
return new Fesm2015Renderer(
host, isCore, rewriteCoreImportsTo, this.sourcePath, this.targetPath);
case 'esm5': case 'esm5':
case 'fesm2015':
case 'fesm5': case 'fesm5':
return new Esm5Renderer( return new EsmRenderer(host, isCore, rewriteCoreImportsTo, this.sourcePath, this.targetPath, dtsMapper);
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.`);
} }

View File

@ -1,63 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {relative, resolve} from 'canonical-path';
import {readFileSync} from 'fs';
import * as ts from 'typescript';
import {DtsFileTransformer} from '../../../ngtsc/transform';
import {DecorationAnalysis} from '../analysis/decoration_analyzer';
import {SwitchMarkerAnalysis} from '../analysis/switch_marker_analyzer';
import {IMPORT_PREFIX} from '../constants';
import {DtsMapper} from '../host/dts_mapper';
import {NgccReflectionHost} from '../host/ngcc_host';
import {Fesm2015Renderer} from './fesm2015_renderer';
import {FileInfo} from './renderer';
export class Esm2015Renderer extends Fesm2015Renderer {
constructor(
protected host: NgccReflectionHost, protected isCore: boolean,
protected rewriteCoreImportsTo: ts.SourceFile|null, protected sourcePath: string,
protected targetPath: string, protected dtsMapper: DtsMapper) {
super(host, isCore, rewriteCoreImportsTo, sourcePath, targetPath);
}
renderFile(
sourceFile: ts.SourceFile, decorationAnalysis: DecorationAnalysis|undefined,
switchMarkerAnalysis: SwitchMarkerAnalysis|undefined, targetPath: string): FileInfo[] {
const renderedFiles =
super.renderFile(sourceFile, decorationAnalysis, switchMarkerAnalysis, targetPath);
// Transform the `.d.ts` files.
// TODO(gkalpak): What about `.d.ts` source maps? (See
// https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-9.html#new---declarationmap.)
if (decorationAnalysis) {
// 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(this.rewriteCoreImportsTo, IMPORT_PREFIX);
decorationAnalysis.analyzedClasses.forEach(
analyzedClass =>
dtsTransformer.recordStaticField(analyzedClass.name, analyzedClass.compilation));
// Find the corresponding `.d.ts` file.
const sourceFileName = sourceFile.fileName;
const originalDtsFileName = this.dtsMapper.getDtsFileNameFor(sourceFileName);
const originalDtsContents = readFileSync(originalDtsFileName, 'utf8');
// Transform the `.d.ts` file based on the recorded source file changes.
const transformedDtsFileName =
resolve(this.targetPath, relative(this.sourcePath, originalDtsFileName));
const transformedDtsContents = dtsTransformer.transform(originalDtsContents, sourceFileName);
// Add the transformed `.d.ts` file to the list of output files.
renderedFiles.push({path: transformedDtsFileName, contents: transformedDtsContents});
}
return renderedFiles;
}
}

View File

@ -1,10 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* 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 {Fesm2015Renderer} from './fesm2015_renderer';
export class Esm5Renderer extends Fesm2015Renderer {}

View File

@ -7,16 +7,17 @@
*/ */
import * as ts from 'typescript'; import * as ts from 'typescript';
import MagicString from 'magic-string'; import MagicString from 'magic-string';
import {DtsMapper} from '../host/dts_mapper';
import {NgccReflectionHost, POST_R3_MARKER, PRE_R3_MARKER, SwitchableVariableDeclaration} from '../host/ngcc_host'; import {NgccReflectionHost, POST_R3_MARKER, PRE_R3_MARKER, SwitchableVariableDeclaration} from '../host/ngcc_host';
import {AnalyzedClass} from '../analysis/decoration_analyzer'; import {AnalyzedClass} from '../analysis/decoration_analyzer';
import {Renderer} from './renderer'; import {Renderer} from './renderer';
export class Fesm2015Renderer extends Renderer { export class EsmRenderer extends Renderer {
constructor( constructor(
protected host: NgccReflectionHost, protected isCore: boolean, protected host: NgccReflectionHost, protected isCore: boolean,
protected rewriteCoreImportsTo: ts.SourceFile|null, protected sourcePath: string, protected rewriteCoreImportsTo: ts.SourceFile|null, protected sourcePath: string,
protected targetPath: string) { protected targetPath: string, dtsMapper: DtsMapper|null) {
super(host, isCore, rewriteCoreImportsTo, sourcePath, targetPath); super(host, isCore, rewriteCoreImportsTo, sourcePath, targetPath, dtsMapper);
} }
/** /**

View File

@ -14,11 +14,13 @@ import {SourceMapConsumer, SourceMapGenerator, RawSourceMap} from 'source-map';
import * as ts from 'typescript'; import * as ts from 'typescript';
import {Decorator} from '../../../ngtsc/host'; import {Decorator} from '../../../ngtsc/host';
import {DtsFileTransformer} from '../../../ngtsc/transform';
import {translateStatement} from '../../../ngtsc/translator'; import {translateStatement} from '../../../ngtsc/translator';
import {NgccImportManager} from './ngcc_import_manager'; import {NgccImportManager} from './ngcc_import_manager';
import {AnalyzedClass, DecorationAnalysis, DecorationAnalyses} from '../analysis/decoration_analyzer'; import {AnalyzedClass, DecorationAnalysis, DecorationAnalyses} from '../analysis/decoration_analyzer';
import {SwitchMarkerAnalyses, SwitchMarkerAnalysis} from '../analysis/switch_marker_analyzer'; import {SwitchMarkerAnalyses, SwitchMarkerAnalysis} from '../analysis/switch_marker_analyzer';
import {IMPORT_PREFIX} from '../constants'; import {IMPORT_PREFIX} from '../constants';
import {DtsMapper} from '../host/dts_mapper';
import {NgccReflectionHost, SwitchableVariableDeclaration} from '../host/ngcc_host'; import {NgccReflectionHost, SwitchableVariableDeclaration} from '../host/ngcc_host';
interface SourceMapInfo { interface SourceMapInfo {
@ -65,23 +67,27 @@ export abstract class Renderer {
constructor( constructor(
protected host: NgccReflectionHost, protected isCore: boolean, protected host: NgccReflectionHost, protected isCore: boolean,
protected rewriteCoreImportsTo: ts.SourceFile|null, protected sourcePath: string, protected rewriteCoreImportsTo: ts.SourceFile|null, protected sourcePath: string,
protected targetPath: string) {} protected targetPath: string, protected dtsMapper: DtsMapper|null) {}
renderProgram( renderProgram(
program: ts.Program, decorationAnalyses: DecorationAnalyses, program: ts.Program, decorationAnalyses: DecorationAnalyses,
switchMarkerAnalyses: SwitchMarkerAnalyses): FileInfo[] { switchMarkerAnalyses: SwitchMarkerAnalyses): FileInfo[] {
const renderedFiles: FileInfo[] = []; const renderedFiles: FileInfo[] = [];
// Transform the source files and source maps.
// Transform the source files, source maps and typings files.
program.getSourceFiles().map(sourceFile => { program.getSourceFiles().map(sourceFile => {
const decorationAnalysis = decorationAnalyses.get(sourceFile); const decorationAnalysis = decorationAnalyses.get(sourceFile);
const switchMarkerAnalysis = switchMarkerAnalyses.get(sourceFile); const switchMarkerAnalysis = switchMarkerAnalyses.get(sourceFile);
// Transform the source files and source maps.
if (decorationAnalysis || switchMarkerAnalysis) { if (decorationAnalysis || switchMarkerAnalysis) {
const targetPath = resolve(this.targetPath, relative(this.sourcePath, sourceFile.fileName)); const targetPath = resolve(this.targetPath, relative(this.sourcePath, sourceFile.fileName));
renderedFiles.push( renderedFiles.push(
...this.renderFile(sourceFile, decorationAnalysis, switchMarkerAnalysis, targetPath)); ...this.renderFile(sourceFile, decorationAnalysis, switchMarkerAnalysis, targetPath));
} }
if (decorationAnalyses) {
renderedFiles.push(...this.renderTypings(decorationAnalyses));
}
}); });
return renderedFiles; return renderedFiles;
} }
@ -244,6 +250,27 @@ export abstract class Renderer {
}; };
} }
} }
// TODO(gkalpak): What about `.d.ts` source maps? (See
// https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-9.html#new---declarationmap.)
renderTypings(decorationAnalyses: DecorationAnalyses): FileInfo[] {
const renderedFiles: FileInfo[] = [];
if (this.dtsMapper) {
const dtsTransformer = new DtsFileTransformer(this.rewriteCoreImportsTo, IMPORT_PREFIX);
decorationAnalyses.forEach((analysis, sourceFile) => {
const sourceFileName = sourceFile.fileName;
const dtsFileName = this.dtsMapper !.getDtsFileNameFor(sourceFileName);
const dtsContents = readFileSync(dtsFileName, 'utf8');
analysis.analyzedClasses.forEach(analyzedClass => dtsTransformer.recordStaticField(analyzedClass.name, analyzedClass.compilation));
const newDtsFileName = resolve(this.targetPath, relative(this.sourcePath, dtsFileName));
const newDtsContents = dtsTransformer.transform(dtsContents, sourceFileName);
renderedFiles.push({path: newDtsFileName, contents: newDtsContents});
});
}
return renderedFiles;
// }
}
} }
/** /**

View File

@ -1208,8 +1208,7 @@ describe('Fesm2015ReflectionHost', () => {
it('should return a collection of all the switchable variable declarations in the given module', it('should return a collection of all the switchable variable declarations in the given module',
() => { () => {
const program = makeProgram(MARKER_FILE); const program = makeProgram(MARKER_FILE);
const dtsMapper = new DtsMapper('/src', '/typings'); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const host = new Esm2015ReflectionHost(false, program.getTypeChecker(), dtsMapper);
const file = program.getSourceFile(MARKER_FILE.name) !; const file = program.getSourceFile(MARKER_FILE.name) !;
const declarations = host.getSwitchableDeclarations(file); const declarations = host.getSwitchableDeclarations(file);
expect(declarations.map(d => [d.name.getText(), d.initializer !.getText()])).toEqual([ expect(declarations.map(d => [d.name.getText(), d.initializer !.getText()])).toEqual([
@ -1222,8 +1221,7 @@ describe('Fesm2015ReflectionHost', () => {
it('should return an array of objects for each file that has exported and decorated classes', it('should return an array of objects for each file that has exported and decorated classes',
() => { () => {
const program = makeProgram(...DECORATED_FILES); const program = makeProgram(...DECORATED_FILES);
const dtsMapper = new DtsMapper('/src', '/typings'); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const host = new Esm2015ReflectionHost(false, program.getTypeChecker(), dtsMapper);
const primaryFile = program.getSourceFile(DECORATED_FILES[0].name) !; const primaryFile = program.getSourceFile(DECORATED_FILES[0].name) !;
const secondaryFile = program.getSourceFile(DECORATED_FILES[1].name) !; const secondaryFile = program.getSourceFile(DECORATED_FILES[1].name) !;
const decoratedFiles = host.findDecoratedFiles(primaryFile); const decoratedFiles = host.findDecoratedFiles(primaryFile);

View File

@ -14,18 +14,17 @@ import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer';
import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer'; import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer';
import {DtsMapper} from '../../src/host/dts_mapper'; import {DtsMapper} from '../../src/host/dts_mapper';
import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
import {Esm2015Renderer} from '../../src/rendering/esm2015_renderer'; import {EsmRenderer} from '../../src/rendering/esm_renderer';
function setup(file: {name: string, contents: string}, transformDts: boolean = false) { function setup(file: {name: string, contents: string}, transformDts: boolean = false) {
const dir = dirname(file.name); const dir = dirname(file.name);
const dtsMapper = new DtsMapper(dir, dir);
const program = makeProgram(file); const program = makeProgram(file);
const sourceFile = program.getSourceFile(file.name) !; const sourceFile = program.getSourceFile(file.name) !;
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const decorationAnalyses = const decorationAnalyses =
new DecorationAnalyzer(program.getTypeChecker(), host, [''], false).analyzeProgram(program); new DecorationAnalyzer(program.getTypeChecker(), host, [''], false).analyzeProgram(program);
const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(program); const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(program);
const renderer = new Esm2015Renderer(host, false, null, dir, dir, dtsMapper); const renderer = new EsmRenderer(host, false, null, dir, dir, null);
return {host, program, sourceFile, renderer, decorationAnalyses, switchMarkerAnalyses}; return {host, program, sourceFile, renderer, decorationAnalyses, switchMarkerAnalyses};
} }

View File

@ -11,7 +11,7 @@ import {makeProgram} from '../helpers/utils';
import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer'; import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer';
import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer'; import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer';
import {Esm5ReflectionHost} from '../../src/host/esm5_host'; import {Esm5ReflectionHost} from '../../src/host/esm5_host';
import {Esm5Renderer} from '../../src/rendering/esm5_renderer'; import {EsmRenderer} from '../../src/rendering/esm_renderer';
function setup(file: {name: string, contents: string}) { function setup(file: {name: string, contents: string}) {
const program = makeProgram(file); const program = makeProgram(file);
@ -20,7 +20,7 @@ function setup(file: {name: string, contents: string}) {
const decorationAnalyses = const decorationAnalyses =
new DecorationAnalyzer(program.getTypeChecker(), host, [''], false).analyzeProgram(program); new DecorationAnalyzer(program.getTypeChecker(), host, [''], false).analyzeProgram(program);
const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(program); const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(program);
const renderer = new Esm5Renderer(host, false, null, '', ''); const renderer = new EsmRenderer(host, false, null, '', '', null);
return {host, program, sourceFile, renderer, decorationAnalyses, switchMarkerAnalyses}; return {host, program, sourceFile, renderer, decorationAnalyses, switchMarkerAnalyses};
} }

View File

@ -17,7 +17,7 @@ import {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
import {Renderer} from '../../src/rendering/renderer'; import {Renderer} from '../../src/rendering/renderer';
class TestRenderer extends Renderer { class TestRenderer extends Renderer {
constructor(host: Esm2015ReflectionHost) { super(host, false, null, '/src', '/dist'); } constructor(host: Esm2015ReflectionHost) { super(host, false, null, '/src', '/dist', null); }
addImports(output: MagicString, imports: {name: string, as: string}[]) { addImports(output: MagicString, imports: {name: string, as: string}[]) {
output.prepend('\n// ADD IMPORTS\n'); output.prepend('\n// ADD IMPORTS\n');
} }