refactor(compiler): add createAotCompiler factory

Also adds 2 more methods to the `AotCompilerHost`:
- `loadResource`
- `resolveFileToImport`
This commit is contained in:
Tobias Bosch
2016-11-15 11:13:20 -08:00
committed by Chuck Jazdzewski
parent 484119e59f
commit 2235048432
13 changed files with 174 additions and 100 deletions

View File

@ -78,17 +78,7 @@ export class CodeGenerator {
static create(
options: AngularCompilerOptions, cliOptions: NgcCliOptions, program: ts.Program,
compilerHost: ts.CompilerHost, ngHostContext?: NgHostContext,
resourceLoader?: compiler.ResourceLoader, ngHost?: NgHost): CodeGenerator {
resourceLoader = resourceLoader || {
get: (s: string) => {
if (!compilerHost.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(compilerHost.readFile(s));
}
};
compilerHost: ts.CompilerHost, ngHost?: NgHost): CodeGenerator {
const transFile = cliOptions.i18nFile;
const locale = cliOptions.locale;
let transContent: string = '';
@ -99,45 +89,13 @@ export class CodeGenerator {
}
transContent = readFileSync(transFile, 'utf8');
}
const urlResolver: compiler.UrlResolver = compiler.createOfflineCompileUrlResolver();
if (!ngHost) {
const usePathMapping = !!options.rootDirs && options.rootDirs.length > 0;
ngHost = usePathMapping ?
new PathMappedNgHost(program, compilerHost, options, ngHostContext) :
new NgHost(program, compilerHost, options, ngHostContext);
}
const staticReflector = new compiler.StaticReflector(ngHost);
compiler.StaticAndDynamicReflectionCapabilities.install(staticReflector);
const htmlParser =
new compiler.I18NHtmlParser(new compiler.HtmlParser(), transContent, cliOptions.i18nFormat);
const config = new compiler.CompilerConfig({
genDebugInfo: options.debug === true,
defaultEncapsulation: ViewEncapsulation.Emulated,
logBindingUpdate: false,
useJit: false
const {compiler: aotCompiler, reflector} = compiler.createAotCompiler(ngHost, {
debug: options.debug === true,
translations: transContent,
i18nFormat: cliOptions.i18nFormat,
locale: cliOptions.locale
});
const normalizer =
new compiler.DirectiveNormalizer(resourceLoader, urlResolver, htmlParser, config);
const expressionParser = new compiler.Parser(new compiler.Lexer());
const elementSchemaRegistry = new compiler.DomElementSchemaRegistry();
const console = new Console();
const tmplParser = new compiler.TemplateParser(
expressionParser, elementSchemaRegistry, htmlParser, console, []);
const resolver = new compiler.CompileMetadataResolver(
new compiler.NgModuleResolver(staticReflector),
new compiler.DirectiveResolver(staticReflector), new compiler.PipeResolver(staticReflector),
elementSchemaRegistry, normalizer, staticReflector);
// TODO(vicb): do not pass cliOptions.i18nFormat here
const aotCompiler = new compiler.AotCompiler(
resolver, tmplParser, new compiler.StyleCompiler(urlResolver),
new compiler.ViewCompiler(config, elementSchemaRegistry),
new compiler.DirectiveWrapperCompiler(
config, expressionParser, elementSchemaRegistry, console),
new compiler.NgModuleCompiler(), new compiler.TypeScriptEmitter(ngHost), cliOptions.locale,
cliOptions.i18nFormat, new compiler.AnimationParser(elementSchemaRegistry));
return new CodeGenerator(options, program, compilerHost, staticReflector, aotCompiler, ngHost);
return new CodeGenerator(options, program, compilerHost, reflector, aotCompiler, ngHost);
}
}

View File

@ -21,6 +21,7 @@ export interface NgHostContext {
fileExists(fileName: string): boolean;
directoryExists(directoryName: string): boolean;
readFile(fileName: string): string;
readResource(fileName: string): Promise<string>;
assumeFileExists(fileName: string): void;
}
@ -75,7 +76,7 @@ export class NgHost implements AotCompilerHost {
*
* NOTE: (*) the relative path is computed depending on `isGenDirChildOfRootDir`.
*/
getImportPath(containingFile: string, importedFile: string): string {
resolveFileToImport(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)) {
@ -176,6 +177,8 @@ export class NgHost implements AotCompilerHost {
}
}
loadResource(filePath: string): Promise<string> { return this.context.readResource(filePath); }
private getResolverMetadata(filePath: string): ModuleMetadata {
let metadata = this.resolverCache.get(filePath);
if (!metadata) {
@ -205,5 +208,13 @@ export class NodeNgHostContext implements NgHostContext {
readFile(fileName: string): string { return fs.readFileSync(fileName, 'utf8'); }
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));
}
assumeFileExists(fileName: string): void { this.assumedExists[fileName] = true; }
}

View File

@ -69,7 +69,7 @@ export class PathMappedNgHost extends NgHost {
* Relativize the paths by checking candidate prefixes of the absolute path, to see if
* they are resolvable by the moduleResolution strategy from the CompilerHost.
*/
getImportPath(containingFile: string, importedFile: string): string {
resolveFileToImport(importedFile: string, containingFile: string): string {
if (this.options.traceResolution) {
console.log(
'getImportPath from containingFile', containingFile, 'to importedFile', importedFile);

View File

@ -28,6 +28,14 @@ export class MockContext implements NgHostContext {
return undefined;
}
readResource(fileName: string): Promise<string> {
const result = this.readFile(fileName);
if (result == null) {
return Promise.reject(new Error(`Resource not found: ${fileName}`));
}
return Promise.resolve(result);
}
writeFile(fileName: string, data: string): void {
const parts = fileName.split('/');
const name = parts.pop();

View File

@ -6,7 +6,6 @@
* found in the LICENSE file at https://angular.io/license
*/
import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_internal';
import * as ts from 'typescript';
import {NgHost} from '../src/ng_host';
@ -57,87 +56,87 @@ describe('NgHost', () => {
describe('nestedGenDir', () => {
it('should import node_module from factory', () => {
expect(hostNestedGenDir.getImportPath(
'/tmp/project/src/gen/my.ngfactory.ts',
'/tmp/project/node_modules/@angular/core.d.ts'))
expect(hostNestedGenDir.resolveFileToImport(
'/tmp/project/node_modules/@angular/core.d.ts',
'/tmp/project/src/gen/my.ngfactory.ts', ))
.toEqual('@angular/core');
});
it('should import factory from factory', () => {
expect(hostNestedGenDir.getImportPath(
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/my.other.ngfactory.ts'))
expect(hostNestedGenDir.resolveFileToImport(
'/tmp/project/src/my.other.ngfactory.ts', '/tmp/project/src/my.ngfactory.ts'))
.toEqual('./my.other.ngfactory');
expect(hostNestedGenDir.getImportPath(
'/tmp/project/src/a/my.ngfactory.ts', '/tmp/project/src/my.other.css.ts'))
expect(hostNestedGenDir.resolveFileToImport(
'/tmp/project/src/my.other.css.ts', '/tmp/project/src/a/my.ngfactory.ts'))
.toEqual('../my.other.css');
expect(hostNestedGenDir.getImportPath(
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/a/my.other.css.shim.ts'))
expect(hostNestedGenDir.resolveFileToImport(
'/tmp/project/src/a/my.other.css.shim.ts', '/tmp/project/src/my.ngfactory.ts'))
.toEqual('./a/my.other.css.shim');
});
it('should import application from factory', () => {
expect(hostNestedGenDir.getImportPath(
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/my.other.ts'))
expect(hostNestedGenDir.resolveFileToImport(
'/tmp/project/src/my.other.ts', '/tmp/project/src/my.ngfactory.ts'))
.toEqual('../my.other');
expect(hostNestedGenDir.getImportPath(
'/tmp/project/src/a/my.ngfactory.ts', '/tmp/project/src/my.other.ts'))
expect(hostNestedGenDir.resolveFileToImport(
'/tmp/project/src/my.other.ts', '/tmp/project/src/a/my.ngfactory.ts'))
.toEqual('../../my.other');
expect(hostNestedGenDir.getImportPath(
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/a/my.other.ts'))
expect(hostNestedGenDir.resolveFileToImport(
'/tmp/project/src/a/my.other.ts', '/tmp/project/src/my.ngfactory.ts'))
.toEqual('../a/my.other');
});
});
describe('nestedGenDir', () => {
describe('siblingGenDir', () => {
it('should import node_module from factory', () => {
expect(hostSiblingGenDir.getImportPath(
'/tmp/project/src/gen/my.ngfactory.ts',
'/tmp/project/node_modules/@angular/core.d.ts'))
expect(hostSiblingGenDir.resolveFileToImport(
'/tmp/project/node_modules/@angular/core.d.ts',
'/tmp/project/src/gen/my.ngfactory.ts'))
.toEqual('@angular/core');
});
it('should import factory from factory', () => {
expect(hostSiblingGenDir.getImportPath(
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/my.other.ngfactory.ts'))
expect(hostSiblingGenDir.resolveFileToImport(
'/tmp/project/src/my.other.ngfactory.ts', '/tmp/project/src/my.ngfactory.ts'))
.toEqual('./my.other.ngfactory');
expect(hostSiblingGenDir.getImportPath(
'/tmp/project/src/a/my.ngfactory.ts', '/tmp/project/src/my.other.css.ts'))
expect(hostSiblingGenDir.resolveFileToImport(
'/tmp/project/src/my.other.css.ts', '/tmp/project/src/a/my.ngfactory.ts'))
.toEqual('../my.other.css');
expect(hostSiblingGenDir.getImportPath(
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/a/my.other.css.shim.ts'))
expect(hostSiblingGenDir.resolveFileToImport(
'/tmp/project/src/a/my.other.css.shim.ts', '/tmp/project/src/my.ngfactory.ts'))
.toEqual('./a/my.other.css.shim');
});
it('should import application from factory', () => {
expect(hostSiblingGenDir.getImportPath(
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/my.other.ts'))
expect(hostSiblingGenDir.resolveFileToImport(
'/tmp/project/src/my.other.ts', '/tmp/project/src/my.ngfactory.ts'))
.toEqual('./my.other');
expect(hostSiblingGenDir.getImportPath(
'/tmp/project/src/a/my.ngfactory.ts', '/tmp/project/src/my.other.ts'))
expect(hostSiblingGenDir.resolveFileToImport(
'/tmp/project/src/my.other.ts', '/tmp/project/src/a/my.ngfactory.ts'))
.toEqual('../my.other');
expect(hostSiblingGenDir.getImportPath(
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/a/my.other.ts'))
expect(hostSiblingGenDir.resolveFileToImport(
'/tmp/project/src/a/my.other.ts', '/tmp/project/src/my.ngfactory.ts'))
.toEqual('./a/my.other');
});
});
it('should be able to produce an import from main @angular/core', () => {
expect(hostNestedGenDir.getImportPath(
'/tmp/project/src/main.ts', '/tmp/project/node_modules/@angular/core.d.ts'))
expect(hostNestedGenDir.resolveFileToImport(
'/tmp/project/node_modules/@angular/core.d.ts', '/tmp/project/src/main.ts'))
.toEqual('@angular/core');
});
it('should be able to produce an import from main to a sub-directory', () => {
expect(hostNestedGenDir.getImportPath('main.ts', 'lib/utils.ts')).toEqual('./lib/utils');
expect(hostNestedGenDir.resolveFileToImport('lib/utils.ts', 'main.ts')).toEqual('./lib/utils');
});
it('should be able to produce an import from to a peer file', () => {
expect(hostNestedGenDir.getImportPath('lib/utils.ts', 'lib/collections.ts'))
expect(hostNestedGenDir.resolveFileToImport('lib/collections.ts', 'lib/utils.ts'))
.toEqual('./collections');
});
it('should be able to produce an import from to a sibling directory', () => {
expect(hostNestedGenDir.getImportPath('lib2/utils2.ts', 'lib/utils.ts'))
expect(hostNestedGenDir.resolveFileToImport('lib/utils.ts', 'lib2/utils2.ts'))
.toEqual('../lib/utils');
});