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