refactor(compiler-cli): refactor compiler host parameters (#13147)
This commit is contained in:
parent
5908b66ae9
commit
25a6da244c
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
export {AotCompilerHost, AotCompilerHost as StaticReflectorHost, StaticReflector, StaticSymbol} from '@angular/compiler';
|
||||
export {CodeGenerator} from './src/codegen';
|
||||
export {CompilerHost, CompilerHostContext, NodeCompilerHostContext} from './src/compiler_host';
|
||||
export {CompilerHost, CompilerHostContext, ModuleResolutionHostAdapter, NodeCompilerHostContext} from './src/compiler_host';
|
||||
export {Extractor} from './src/extractor';
|
||||
export * from '@angular/tsc-wrapped';
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ import {readFileSync} from 'fs';
|
|||
import * as path from 'path';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {CompilerHost, CompilerHostContext} from './compiler_host';
|
||||
import {CompilerHost, CompilerHostContext, ModuleResolutionHostAdapter} from './compiler_host';
|
||||
import {PathMappedCompilerHost} from './path_mapped_compiler_host';
|
||||
import {Console} from './private_import_core';
|
||||
|
||||
|
@ -82,9 +82,9 @@ export class CodeGenerator {
|
|||
ngCompilerHost?: CompilerHost): CodeGenerator {
|
||||
if (!ngCompilerHost) {
|
||||
const usePathMapping = !!options.rootDirs && options.rootDirs.length > 0;
|
||||
ngCompilerHost = usePathMapping ?
|
||||
new PathMappedCompilerHost(program, tsCompilerHost, options, compilerHostContext) :
|
||||
new CompilerHost(program, tsCompilerHost, options, compilerHostContext);
|
||||
const context = compilerHostContext || new ModuleResolutionHostAdapter(tsCompilerHost);
|
||||
ngCompilerHost = usePathMapping ? new PathMappedCompilerHost(program, options, context) :
|
||||
new CompilerHost(program, options, context);
|
||||
}
|
||||
const transFile = cliOptions.i18nFile;
|
||||
const locale = cliOptions.locale;
|
||||
|
|
|
@ -17,30 +17,25 @@ const DTS = /\.d\.ts$/;
|
|||
const NODE_MODULES = '/node_modules/';
|
||||
const IS_GENERATED = /\.(ngfactory|css(\.shim)?)$/;
|
||||
|
||||
export interface CompilerHostContext {
|
||||
fileExists(fileName: string): boolean;
|
||||
directoryExists(directoryName: string): boolean;
|
||||
readFile(fileName: string): string;
|
||||
export interface CompilerHostContext extends ts.ModuleResolutionHost {
|
||||
readResource(fileName: string): Promise<string>;
|
||||
assumeFileExists(fileName: string): void;
|
||||
}
|
||||
|
||||
export class CompilerHost implements AotCompilerHost {
|
||||
protected metadataCollector = new MetadataCollector();
|
||||
protected context: CompilerHostContext;
|
||||
private isGenDirChildOfRootDir: boolean;
|
||||
protected basePath: string;
|
||||
private genDir: string;
|
||||
private resolverCache = new Map<string, ModuleMetadata[]>();
|
||||
|
||||
constructor(
|
||||
protected program: ts.Program, protected compilerHost: ts.CompilerHost,
|
||||
protected options: AngularCompilerOptions, context?: CompilerHostContext) {
|
||||
protected program: ts.Program, protected options: AngularCompilerOptions,
|
||||
protected context: CompilerHostContext) {
|
||||
// normalize the path so that it never ends with '/'.
|
||||
this.basePath = path.normalize(path.join(this.options.basePath, '.')).replace(/\\/g, '/');
|
||||
this.genDir = path.normalize(path.join(this.options.genDir, '.')).replace(/\\/g, '/');
|
||||
|
||||
this.context = context || new NodeCompilerHostContext(compilerHost);
|
||||
const genPath: string = path.relative(this.basePath, this.genDir);
|
||||
this.isGenDirChildOfRootDir = genPath === '' || !genPath.startsWith('..');
|
||||
}
|
||||
|
@ -81,7 +76,7 @@ export class CompilerHost implements AotCompilerHost {
|
|||
fileNameToModuleName(importedFile: string, containingFile: string): string {
|
||||
// If a file does not yet exist (because we compile it later), we still need to
|
||||
// assume it exists it so that the `resolve` method works!
|
||||
if (!this.compilerHost.fileExists(importedFile)) {
|
||||
if (!this.context.fileExists(importedFile)) {
|
||||
this.context.assumeFileExists(importedFile);
|
||||
}
|
||||
|
||||
|
@ -181,8 +176,8 @@ export class CompilerHost implements AotCompilerHost {
|
|||
const metadatas = metadataOrMetadatas ?
|
||||
(Array.isArray(metadataOrMetadatas) ? metadataOrMetadatas : [metadataOrMetadatas]) :
|
||||
[];
|
||||
const v1Metadata = metadatas.find(m => m['version'] === 1);
|
||||
let v2Metadata = metadatas.find(m => m['version'] === 2);
|
||||
const v1Metadata = metadatas.find((m: any) => m['version'] === 1);
|
||||
let v2Metadata = metadatas.find((m: any) => m['version'] === 2);
|
||||
if (!v2Metadata && v1Metadata) {
|
||||
// patch up v1 to v2 by merging the metadata with metadata collected from the d.ts file
|
||||
// as the only difference between the versions is whether all exports are contained in
|
||||
|
@ -216,15 +211,44 @@ export class CompilerHost implements AotCompilerHost {
|
|||
loadResource(filePath: string): Promise<string> { return this.context.readResource(filePath); }
|
||||
}
|
||||
|
||||
export class NodeCompilerHostContext implements CompilerHostContext {
|
||||
constructor(private host: ts.CompilerHost) {}
|
||||
export class CompilerHostContextAdapter {
|
||||
protected assumedExists: {[fileName: string]: boolean} = {};
|
||||
|
||||
private assumedExists: {[fileName: string]: boolean} = {};
|
||||
assumeFileExists(fileName: string): void { this.assumedExists[fileName] = true; }
|
||||
}
|
||||
|
||||
export class ModuleResolutionHostAdapter extends CompilerHostContextAdapter implements
|
||||
CompilerHostContext {
|
||||
public directoryExists: ((directoryName: string) => boolean)|undefined;
|
||||
|
||||
constructor(private host: ts.ModuleResolutionHost) {
|
||||
super();
|
||||
if (host.directoryExists) {
|
||||
this.directoryExists = (directoryName: string) => host.directoryExists(directoryName);
|
||||
}
|
||||
}
|
||||
|
||||
fileExists(fileName: string): boolean {
|
||||
return this.assumedExists[fileName] || this.host.fileExists(fileName);
|
||||
}
|
||||
|
||||
readFile(fileName: string): string { return this.host.readFile(fileName); }
|
||||
|
||||
readResource(s: string) {
|
||||
if (!this.host.fileExists(s)) {
|
||||
// TODO: We should really have a test for error cases like this!
|
||||
throw new Error(`Compilation failed. Resource file not found: ${s}`);
|
||||
}
|
||||
return Promise.resolve(this.host.readFile(s));
|
||||
}
|
||||
}
|
||||
|
||||
export class NodeCompilerHostContext extends CompilerHostContextAdapter implements
|
||||
CompilerHostContext {
|
||||
fileExists(fileName: string): boolean {
|
||||
return this.assumedExists[fileName] || fs.existsSync(fileName);
|
||||
}
|
||||
|
||||
directoryExists(directoryName: string): boolean {
|
||||
try {
|
||||
return fs.statSync(directoryName).isDirectory();
|
||||
|
@ -236,12 +260,10 @@ export class NodeCompilerHostContext implements CompilerHostContext {
|
|||
readFile(fileName: string): string { return fs.readFileSync(fileName, 'utf8'); }
|
||||
|
||||
readResource(s: string) {
|
||||
if (!this.host.fileExists(s)) {
|
||||
if (!this.fileExists(s)) {
|
||||
// TODO: We should really have a test for error cases like this!
|
||||
throw new Error(`Compilation failed. Resource file not found: ${s}`);
|
||||
}
|
||||
return Promise.resolve(this.host.readFile(s));
|
||||
return Promise.resolve(this.readFile(s));
|
||||
}
|
||||
|
||||
assumeFileExists(fileName: string): void { this.assumedExists[fileName] = true; }
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ import * as tsc from '@angular/tsc-wrapped';
|
|||
import * as ts from 'typescript';
|
||||
|
||||
import {excludeFilePattern} from './codegen';
|
||||
import {CompilerHost} from './compiler_host';
|
||||
import {CompilerHost, ModuleResolutionHostAdapter} from './compiler_host';
|
||||
|
||||
export class Extractor {
|
||||
constructor(
|
||||
|
@ -32,8 +32,10 @@ export class Extractor {
|
|||
|
||||
static create(
|
||||
options: tsc.AngularCompilerOptions, translationsFormat: string, program: ts.Program,
|
||||
tsCompilerHost: ts.CompilerHost, ngCompilerHost?: CompilerHost): Extractor {
|
||||
if (!ngCompilerHost) ngCompilerHost = new CompilerHost(program, tsCompilerHost, options);
|
||||
moduleResolverHost: ts.ModuleResolutionHost, ngCompilerHost?: CompilerHost): Extractor {
|
||||
if (!ngCompilerHost)
|
||||
ngCompilerHost =
|
||||
new CompilerHost(program, options, new ModuleResolutionHostAdapter(moduleResolverHost));
|
||||
const {extractor: ngExtractor} = compiler.Extractor.create(
|
||||
ngCompilerHost, {excludeFilePattern: excludeFilePattern(options)});
|
||||
return new Extractor(ngExtractor, ngCompilerHost, program);
|
||||
|
|
|
@ -25,10 +25,8 @@ const DTS = /\.d\.ts$/;
|
|||
* loader what to do.
|
||||
*/
|
||||
export class PathMappedCompilerHost extends CompilerHost {
|
||||
constructor(
|
||||
program: ts.Program, compilerHost: ts.CompilerHost, options: AngularCompilerOptions,
|
||||
context?: CompilerHostContext) {
|
||||
super(program, compilerHost, options, context);
|
||||
constructor(program: ts.Program, options: AngularCompilerOptions, context: CompilerHostContext) {
|
||||
super(program, options, context);
|
||||
}
|
||||
|
||||
getCanonicalFileName(fileName: string): string {
|
||||
|
@ -119,7 +117,7 @@ export class PathMappedCompilerHost extends CompilerHost {
|
|||
getMetadataFor(filePath: string): ModuleMetadata[] {
|
||||
for (const root of this.options.rootDirs || []) {
|
||||
const rootedPath = path.join(root, filePath);
|
||||
if (!this.compilerHost.fileExists(rootedPath)) {
|
||||
if (!this.context.fileExists(rootedPath)) {
|
||||
// If the file doesn't exists then we cannot return metadata for the file.
|
||||
// This will occur if the user refernced a declared module for which no file
|
||||
// exists for the module (i.e. jQuery or angularjs).
|
||||
|
|
|
@ -14,14 +14,13 @@ import {Directory, Entry, MockAotContext, MockCompilerHost} from './mocks';
|
|||
|
||||
describe('CompilerHost', () => {
|
||||
let context: MockAotContext;
|
||||
let host: ts.CompilerHost;
|
||||
let program: ts.Program;
|
||||
let hostNestedGenDir: CompilerHost;
|
||||
let hostSiblingGenDir: CompilerHost;
|
||||
|
||||
beforeEach(() => {
|
||||
context = new MockAotContext('/tmp/src', clone(FILES));
|
||||
host = new MockCompilerHost(context);
|
||||
const host = new MockCompilerHost(context);
|
||||
program = ts.createProgram(
|
||||
['main.ts'], {
|
||||
module: ts.ModuleKind.CommonJS,
|
||||
|
@ -33,7 +32,7 @@ describe('CompilerHost', () => {
|
|||
throw new Error('Expected no errors');
|
||||
}
|
||||
hostNestedGenDir = new CompilerHost(
|
||||
program, host, {
|
||||
program, {
|
||||
genDir: '/tmp/project/src/gen/',
|
||||
basePath: '/tmp/project/src',
|
||||
skipMetadataEmit: false,
|
||||
|
@ -43,7 +42,7 @@ describe('CompilerHost', () => {
|
|||
},
|
||||
context);
|
||||
hostSiblingGenDir = new CompilerHost(
|
||||
program, host, {
|
||||
program, {
|
||||
genDir: '/tmp/project/gen',
|
||||
basePath: '/tmp/project/src/',
|
||||
skipMetadataEmit: false,
|
||||
|
|
Loading…
Reference in New Issue