refactor(compiler): add ability to produce stub .ngfactory / .ngsummary files (#16963)
These files are needed so that: - user code can compile even without real codegen - as tsc transformers cannot create but only change existing files in the transformation pipeline.
This commit is contained in:
parent
fa809ec8cf
commit
eba59aaf87
|
@ -38,8 +38,9 @@ export class CodeGenerator {
|
||||||
|
|
||||||
codegen(): Promise<any> {
|
codegen(): Promise<any> {
|
||||||
return this.compiler
|
return this.compiler
|
||||||
.compileAllAsync(this.program.getSourceFiles().map(
|
.analyzeModulesAsync(this.program.getSourceFiles().map(
|
||||||
sf => this.ngCompilerHost.getCanonicalFileName(sf.fileName)))
|
sf => this.ngCompilerHost.getCanonicalFileName(sf.fileName)))
|
||||||
|
.then(analyzedModules => this.compiler.emitAllImpls(analyzedModules))
|
||||||
.then(generatedModules => {
|
.then(generatedModules => {
|
||||||
generatedModules.forEach(generatedModule => {
|
generatedModules.forEach(generatedModule => {
|
||||||
const sourceFile = this.program.getSourceFile(generatedModule.srcFileUrl);
|
const sourceFile = this.program.getSourceFile(generatedModule.srcFileUrl);
|
||||||
|
|
|
@ -24,7 +24,7 @@ import {GeneratedFile} from './generated_file';
|
||||||
import {StaticReflector} from './static_reflector';
|
import {StaticReflector} from './static_reflector';
|
||||||
import {StaticSymbol} from './static_symbol';
|
import {StaticSymbol} from './static_symbol';
|
||||||
import {ResolvedStaticSymbol, StaticSymbolResolver} from './static_symbol_resolver';
|
import {ResolvedStaticSymbol, StaticSymbolResolver} from './static_symbol_resolver';
|
||||||
import {serializeSummaries} from './summary_serializer';
|
import {createForJitStub, serializeSummaries} from './summary_serializer';
|
||||||
import {ngfactoryFilePath, splitTypescriptSuffix, summaryFileName, summaryForJitFileName, summaryForJitName} from './util';
|
import {ngfactoryFilePath, splitTypescriptSuffix, summaryFileName, summaryForJitFileName, summaryForJitName} from './util';
|
||||||
|
|
||||||
export class AotCompiler {
|
export class AotCompiler {
|
||||||
|
@ -39,38 +39,86 @@ export class AotCompiler {
|
||||||
|
|
||||||
clearCache() { this._metadataResolver.clearCache(); }
|
clearCache() { this._metadataResolver.clearCache(); }
|
||||||
|
|
||||||
compileAllAsync(rootFiles: string[]): Promise<GeneratedFile[]> {
|
analyzeModulesSync(rootFiles: string[]): NgAnalyzedModules {
|
||||||
const programSymbols = extractProgramSymbols(this._symbolResolver, rootFiles, this._host);
|
const programSymbols = extractProgramSymbols(this._symbolResolver, rootFiles, this._host);
|
||||||
const {ngModuleByPipeOrDirective, files, ngModules} =
|
const analyzeResult =
|
||||||
analyzeAndValidateNgModules(programSymbols, this._host, this._metadataResolver);
|
analyzeAndValidateNgModules(programSymbols, this._host, this._metadataResolver);
|
||||||
return Promise
|
analyzeResult.ngModules.forEach(
|
||||||
.all(ngModules.map(
|
|
||||||
ngModule => this._metadataResolver.loadNgModuleDirectiveAndPipeMetadata(
|
|
||||||
ngModule.type.reference, false)))
|
|
||||||
.then(() => {
|
|
||||||
const sourceModules = files.map(
|
|
||||||
file => this._compileSrcFile(
|
|
||||||
file.srcUrl, ngModuleByPipeOrDirective, file.directives, file.pipes,
|
|
||||||
file.ngModules, file.injectables));
|
|
||||||
return flatten(sourceModules);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
compileAllSync(rootFiles: string[]): GeneratedFile[] {
|
|
||||||
const programSymbols = extractProgramSymbols(this._symbolResolver, rootFiles, this._host);
|
|
||||||
const {ngModuleByPipeOrDirective, files, ngModules} =
|
|
||||||
analyzeAndValidateNgModules(programSymbols, this._host, this._metadataResolver);
|
|
||||||
ngModules.forEach(
|
|
||||||
ngModule => this._metadataResolver.loadNgModuleDirectiveAndPipeMetadata(
|
ngModule => this._metadataResolver.loadNgModuleDirectiveAndPipeMetadata(
|
||||||
ngModule.type.reference, true));
|
ngModule.type.reference, true));
|
||||||
|
return analyzeResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
analyzeModulesAsync(rootFiles: string[]): Promise<NgAnalyzedModules> {
|
||||||
|
const programSymbols = extractProgramSymbols(this._symbolResolver, rootFiles, this._host);
|
||||||
|
const analyzeResult =
|
||||||
|
analyzeAndValidateNgModules(programSymbols, this._host, this._metadataResolver);
|
||||||
|
return Promise
|
||||||
|
.all(analyzeResult.ngModules.map(
|
||||||
|
ngModule => this._metadataResolver.loadNgModuleDirectiveAndPipeMetadata(
|
||||||
|
ngModule.type.reference, false)))
|
||||||
|
.then(() => analyzeResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
emitAllStubs(analyzeResult: NgAnalyzedModules): GeneratedFile[] {
|
||||||
|
const {files} = analyzeResult;
|
||||||
|
const sourceModules =
|
||||||
|
files.map(file => this._compileStubFile(file.srcUrl, file.directives, file.ngModules));
|
||||||
|
return flatten(sourceModules);
|
||||||
|
}
|
||||||
|
|
||||||
|
emitAllImpls(analyzeResult: NgAnalyzedModules): GeneratedFile[] {
|
||||||
|
const {ngModuleByPipeOrDirective, files} = analyzeResult;
|
||||||
const sourceModules = files.map(
|
const sourceModules = files.map(
|
||||||
file => this._compileSrcFile(
|
file => this._compileImplFile(
|
||||||
file.srcUrl, ngModuleByPipeOrDirective, file.directives, file.pipes, file.ngModules,
|
file.srcUrl, ngModuleByPipeOrDirective, file.directives, file.pipes, file.ngModules,
|
||||||
file.injectables));
|
file.injectables));
|
||||||
return flatten(sourceModules);
|
return flatten(sourceModules);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _compileSrcFile(
|
private _compileStubFile(
|
||||||
|
srcFileUrl: string, directives: StaticSymbol[], ngModules: StaticSymbol[]): GeneratedFile[] {
|
||||||
|
const fileSuffix = splitTypescriptSuffix(srcFileUrl, true)[1];
|
||||||
|
const generatedFiles: GeneratedFile[] = [];
|
||||||
|
|
||||||
|
const jitSummaryStmts: o.Statement[] = [];
|
||||||
|
const ngFactoryStms: o.Statement[] = [];
|
||||||
|
|
||||||
|
const ngFactoryOutputCtx = this._createOutputContext(ngfactoryFilePath(srcFileUrl, true));
|
||||||
|
const jitSummaryOutputCtx = this._createOutputContext(summaryForJitFileName(srcFileUrl, true));
|
||||||
|
|
||||||
|
// create exports that user code can reference
|
||||||
|
ngModules.forEach((ngModuleReference) => {
|
||||||
|
this._ngModuleCompiler.createStub(ngFactoryOutputCtx, ngModuleReference);
|
||||||
|
createForJitStub(jitSummaryOutputCtx, ngModuleReference);
|
||||||
|
});
|
||||||
|
// Note: we are creating stub ngfactory/ngsummary for all source files,
|
||||||
|
// as the real calculation requires almost the same logic as producing the real content for
|
||||||
|
// them.
|
||||||
|
// Our pipeline will filter out empty ones at the end.
|
||||||
|
generatedFiles.push(this._codegenSourceModule(srcFileUrl, ngFactoryOutputCtx));
|
||||||
|
generatedFiles.push(this._codegenSourceModule(srcFileUrl, jitSummaryOutputCtx));
|
||||||
|
|
||||||
|
// create stubs for external stylesheets (always empty, as users should not import anything from
|
||||||
|
// the generated code)
|
||||||
|
directives.forEach((dirType) => {
|
||||||
|
const compMeta = this._metadataResolver.getDirectiveMetadata(<any>dirType);
|
||||||
|
if (!compMeta.isComponent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Note: compMeta is a component and therefore template is non null.
|
||||||
|
compMeta.template !.externalStylesheets.forEach((stylesheetMeta) => {
|
||||||
|
generatedFiles.push(this._codegenSourceModule(
|
||||||
|
stylesheetMeta.moduleUrl !,
|
||||||
|
this._createOutputContext(_stylesModuleUrl(
|
||||||
|
stylesheetMeta.moduleUrl !, this._styleCompiler.needsStyleShim(compMeta),
|
||||||
|
fileSuffix))));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return generatedFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _compileImplFile(
|
||||||
srcFileUrl: string, ngModuleByPipeOrDirective: Map<StaticSymbol, CompileNgModuleMetadata>,
|
srcFileUrl: string, ngModuleByPipeOrDirective: Map<StaticSymbol, CompileNgModuleMetadata>,
|
||||||
directives: StaticSymbol[], pipes: StaticSymbol[], ngModules: StaticSymbol[],
|
directives: StaticSymbol[], pipes: StaticSymbol[], ngModules: StaticSymbol[],
|
||||||
injectables: StaticSymbol[]): GeneratedFile[] {
|
injectables: StaticSymbol[]): GeneratedFile[] {
|
||||||
|
@ -89,7 +137,7 @@ export class AotCompiler {
|
||||||
directives.forEach((dirType) => {
|
directives.forEach((dirType) => {
|
||||||
const compMeta = this._metadataResolver.getDirectiveMetadata(<any>dirType);
|
const compMeta = this._metadataResolver.getDirectiveMetadata(<any>dirType);
|
||||||
if (!compMeta.isComponent) {
|
if (!compMeta.isComponent) {
|
||||||
return Promise.resolve(null);
|
return;
|
||||||
}
|
}
|
||||||
const ngModule = ngModuleByPipeOrDirective.get(dirType);
|
const ngModule = ngModuleByPipeOrDirective.get(dirType);
|
||||||
if (!ngModule) {
|
if (!ngModule) {
|
||||||
|
@ -97,13 +145,12 @@ export class AotCompiler {
|
||||||
`Internal Error: cannot determine the module for component ${identifierName(compMeta.type)}!`);
|
`Internal Error: cannot determine the module for component ${identifierName(compMeta.type)}!`);
|
||||||
}
|
}
|
||||||
|
|
||||||
_assertComponent(compMeta);
|
|
||||||
|
|
||||||
// compile styles
|
// compile styles
|
||||||
const componentStylesheet = this._styleCompiler.compileComponent(outputCtx, compMeta);
|
const componentStylesheet = this._styleCompiler.compileComponent(outputCtx, compMeta);
|
||||||
// Note: compMeta is a component and therefore template is non null.
|
// Note: compMeta is a component and therefore template is non null.
|
||||||
compMeta.template !.externalStylesheets.forEach((stylesheetMeta) => {
|
compMeta.template !.externalStylesheets.forEach((stylesheetMeta) => {
|
||||||
generatedFiles.push(this._codegenStyles(srcFileUrl, compMeta, stylesheetMeta, fileSuffix));
|
generatedFiles.push(
|
||||||
|
this._codegenStyles(stylesheetMeta.moduleUrl !, compMeta, stylesheetMeta, fileSuffix));
|
||||||
});
|
});
|
||||||
|
|
||||||
// compile components
|
// compile components
|
||||||
|
@ -149,7 +196,6 @@ export class AotCompiler {
|
||||||
}))
|
}))
|
||||||
];
|
];
|
||||||
const forJitOutputCtx = this._createOutputContext(summaryForJitFileName(srcFileUrl, true));
|
const forJitOutputCtx = this._createOutputContext(summaryForJitFileName(srcFileUrl, true));
|
||||||
const forJitTargetFilePath = summaryForJitFileName(srcFileUrl, true);
|
|
||||||
const {json, exportAs} = serializeSummaries(
|
const {json, exportAs} = serializeSummaries(
|
||||||
forJitOutputCtx, this._summaryResolver, this._symbolResolver, symbolSummaries, typeData);
|
forJitOutputCtx, this._summaryResolver, this._symbolResolver, symbolSummaries, typeData);
|
||||||
exportAs.forEach((entry) => {
|
exportAs.forEach((entry) => {
|
||||||
|
@ -305,13 +351,6 @@ function _stylesModuleUrl(stylesheetUrl: string, shim: boolean, suffix: string):
|
||||||
return `${stylesheetUrl}${shim ? '.shim' : ''}.ngstyle${suffix}`;
|
return `${stylesheetUrl}${shim ? '.shim' : ''}.ngstyle${suffix}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _assertComponent(meta: CompileDirectiveMetadata) {
|
|
||||||
if (!meta.isComponent) {
|
|
||||||
throw new Error(
|
|
||||||
`Could not compile '${identifierName(meta.type)}' because it is not a component.`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface NgAnalyzedModules {
|
export interface NgAnalyzedModules {
|
||||||
ngModules: CompileNgModuleMetadata[];
|
ngModules: CompileNgModuleMetadata[];
|
||||||
ngModuleByPipeOrDirective: Map<StaticSymbol, CompileNgModuleMetadata>;
|
ngModuleByPipeOrDirective: Map<StaticSymbol, CompileNgModuleMetadata>;
|
||||||
|
|
|
@ -87,6 +87,20 @@ export function deserializeSummaries(symbolCache: StaticSymbolCache, json: strin
|
||||||
return deserializer.deserialize(json);
|
return deserializer.deserialize(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createForJitStub(outputCtx: OutputContext, reference: StaticSymbol) {
|
||||||
|
return createSummaryForJitFunction(outputCtx, reference, o.NULL_EXPR);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createSummaryForJitFunction(
|
||||||
|
outputCtx: OutputContext, reference: StaticSymbol, value: o.Expression) {
|
||||||
|
const fnName = summaryForJitName(reference.name);
|
||||||
|
outputCtx.statements.push(
|
||||||
|
o.fn([], [new o.ReturnStatement(value)], new o.ArrayType(o.DYNAMIC_TYPE)).toDeclStmt(fnName, [
|
||||||
|
o.StmtModifier.Final, o.StmtModifier.Exported
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class ToJsonSerializer extends ValueTransformer {
|
class ToJsonSerializer extends ValueTransformer {
|
||||||
// Note: This only contains symbols without members.
|
// Note: This only contains symbols without members.
|
||||||
symbols: StaticSymbol[] = [];
|
symbols: StaticSymbol[] = [];
|
||||||
|
@ -215,10 +229,9 @@ class ForJitSerializer {
|
||||||
}
|
}
|
||||||
if (!isLibrary) {
|
if (!isLibrary) {
|
||||||
const fnName = summaryForJitName(summary.type.reference.name);
|
const fnName = summaryForJitName(summary.type.reference.name);
|
||||||
this.outputCtx.statements.push(
|
createSummaryForJitFunction(
|
||||||
o.fn([], [new o.ReturnStatement(this.serializeSummaryWithDeps(summary, metadata !))],
|
this.outputCtx, summary.type.reference,
|
||||||
new o.ArrayType(o.DYNAMIC_TYPE))
|
this.serializeSummaryWithDeps(summary, metadata !));
|
||||||
.toDeclStmt(fnName, [o.StmtModifier.Final, o.StmtModifier.Exported]));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -50,21 +50,13 @@ export class NgModuleCompiler {
|
||||||
[new o.FnParam(LOG_VAR.name !)], [new o.ReturnStatement(ngModuleDef)], o.INFERRED_TYPE);
|
[new o.FnParam(LOG_VAR.name !)], [new o.ReturnStatement(ngModuleDef)], o.INFERRED_TYPE);
|
||||||
|
|
||||||
const ngModuleFactoryVar = `${identifierName(ngModuleMeta.type)}NgFactory`;
|
const ngModuleFactoryVar = `${identifierName(ngModuleMeta.type)}NgFactory`;
|
||||||
const ngModuleFactoryStmt =
|
this._createNgModuleFactory(
|
||||||
o.variable(ngModuleFactoryVar)
|
ctx, ngModuleMeta.type.reference, o.importExpr(Identifiers.createModuleFactory).callFn([
|
||||||
.set(o.importExpr(Identifiers.createModuleFactory).callFn([
|
ctx.importExpr(ngModuleMeta.type.reference),
|
||||||
ctx.importExpr(ngModuleMeta.type.reference),
|
o.literalArr(bootstrapComponents.map(id => ctx.importExpr(id.reference))),
|
||||||
o.literalArr(bootstrapComponents.map(id => ctx.importExpr(id.reference))),
|
ngModuleDefFactory
|
||||||
ngModuleDefFactory
|
]));
|
||||||
]))
|
|
||||||
.toDeclStmt(
|
|
||||||
o.importType(
|
|
||||||
Identifiers.NgModuleFactory,
|
|
||||||
[o.expressionType(ctx.importExpr(ngModuleMeta.type.reference)) !],
|
|
||||||
[o.TypeModifier.Const]),
|
|
||||||
[o.StmtModifier.Final, o.StmtModifier.Exported]);
|
|
||||||
|
|
||||||
ctx.statements.push(ngModuleFactoryStmt);
|
|
||||||
if (ngModuleMeta.id) {
|
if (ngModuleMeta.id) {
|
||||||
const registerFactoryStmt =
|
const registerFactoryStmt =
|
||||||
o.importExpr(Identifiers.RegisterModuleFactoryFn)
|
o.importExpr(Identifiers.RegisterModuleFactoryFn)
|
||||||
|
@ -75,4 +67,22 @@ export class NgModuleCompiler {
|
||||||
|
|
||||||
return new NgModuleCompileResult(ngModuleFactoryVar);
|
return new NgModuleCompileResult(ngModuleFactoryVar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createStub(ctx: OutputContext, ngModuleReference: any) {
|
||||||
|
this._createNgModuleFactory(ctx, ngModuleReference, o.NULL_EXPR);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _createNgModuleFactory(ctx: OutputContext, reference: any, value: o.Expression) {
|
||||||
|
const ngModuleFactoryVar = `${identifierName({reference: reference})}NgFactory`;
|
||||||
|
const ngModuleFactoryStmt =
|
||||||
|
o.variable(ngModuleFactoryVar)
|
||||||
|
.set(value)
|
||||||
|
.toDeclStmt(
|
||||||
|
o.importType(
|
||||||
|
Identifiers.NgModuleFactory, [o.expressionType(ctx.importExpr(reference)) !],
|
||||||
|
[o.TypeModifier.Const]),
|
||||||
|
[o.StmtModifier.Final, o.StmtModifier.Exported]);
|
||||||
|
|
||||||
|
ctx.statements.push(ngModuleFactoryStmt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
/**
|
||||||
|
* @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 {MockDirectory, compile, expectNoDiagnostics, setup, toMockFileArray} from './test_util';
|
||||||
|
|
||||||
|
describe('aot stubs', () => {
|
||||||
|
let angularFiles = setup();
|
||||||
|
|
||||||
|
it('should create empty .ngfactory and .ngsummary files for every source file', () => {
|
||||||
|
const appDir = {'app.ts': `export const x = 1;`};
|
||||||
|
const rootDir = {'app': appDir};
|
||||||
|
const {genFiles} =
|
||||||
|
compile([rootDir, angularFiles], {postCompile: expectNoDiagnostics, stubsOnly: true});
|
||||||
|
expect(genFiles.find((f) => f.genFileUrl === '/app/app.ngfactory.ts')).toBeTruthy();
|
||||||
|
expect(genFiles.find((f) => f.genFileUrl === '/app/app.ngsummary.ts')).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create empty .ngstyle files for imported css files', () => {
|
||||||
|
const appDir = {
|
||||||
|
'app.ts': `
|
||||||
|
import {Component, NgModule} from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
template: '',
|
||||||
|
styleUrls: ['./style.css']
|
||||||
|
})
|
||||||
|
export class MyComp {}
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [MyComp]
|
||||||
|
})
|
||||||
|
export class MyModule {}
|
||||||
|
export const x = 1;
|
||||||
|
`,
|
||||||
|
'style.css': ''
|
||||||
|
};
|
||||||
|
const rootDir = {'app': appDir};
|
||||||
|
const {genFiles} =
|
||||||
|
compile([rootDir, angularFiles], {postCompile: expectNoDiagnostics, stubsOnly: true});
|
||||||
|
expect(genFiles.find((f) => f.genFileUrl === '/app/style.css.shim.ngstyle.ts')).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create stub exports for NgModules of the right type', () => {
|
||||||
|
const appDir = {
|
||||||
|
'app.module.ts': `
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
|
||||||
|
@NgModule()
|
||||||
|
export class MyModule {}
|
||||||
|
`,
|
||||||
|
'app.boot.ts': `
|
||||||
|
import {NgModuleFactory} from '@angular/core';
|
||||||
|
import {MyModuleNgFactory} from './app.module.ngfactory';
|
||||||
|
import {MyModuleNgSummary} from './app.module.ngsummary';
|
||||||
|
import {MyModule} from './app.module';
|
||||||
|
|
||||||
|
export const factory: NgModuleFactory<MyModule> = MyModuleNgFactory;
|
||||||
|
export const summary: () => any[] = MyModuleNgSummary;
|
||||||
|
`
|
||||||
|
};
|
||||||
|
const rootDir = {'app': appDir};
|
||||||
|
compile([rootDir, angularFiles], {postCompile: expectNoDiagnostics, stubsOnly: true});
|
||||||
|
});
|
||||||
|
});
|
|
@ -234,15 +234,12 @@ export class MockCompilerHost implements ts.CompilerHost {
|
||||||
}
|
}
|
||||||
const effectiveName = this.getEffectiveName(fileName);
|
const effectiveName = this.getEffectiveName(fileName);
|
||||||
if (effectiveName == fileName) {
|
if (effectiveName == fileName) {
|
||||||
let result = open(fileName, this.data) != null;
|
return open(fileName, this.data) != null;
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
if (fileName.match(rxjs)) {
|
|
||||||
let result = fs.existsSync(effectiveName);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
if (fileName.match(rxjs)) {
|
||||||
|
return fs.existsSync(effectiveName);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
readFile(fileName: string): string { return this.getFileContent(fileName) !; }
|
readFile(fileName: string): string { return this.getFileContent(fileName) !; }
|
||||||
|
@ -303,18 +300,13 @@ export class MockCompilerHost implements ts.CompilerHost {
|
||||||
if (/^lib.*\.d\.ts$/.test(basename)) {
|
if (/^lib.*\.d\.ts$/.test(basename)) {
|
||||||
let libPath = ts.getDefaultLibFilePath(settings);
|
let libPath = ts.getDefaultLibFilePath(settings);
|
||||||
return fs.readFileSync(path.join(path.dirname(libPath), basename), 'utf8');
|
return fs.readFileSync(path.join(path.dirname(libPath), basename), 'utf8');
|
||||||
} else {
|
}
|
||||||
let effectiveName = this.getEffectiveName(fileName);
|
let effectiveName = this.getEffectiveName(fileName);
|
||||||
if (effectiveName === fileName) {
|
if (effectiveName === fileName) {
|
||||||
const result = open(fileName, this.data);
|
return open(fileName, this.data);
|
||||||
return result;
|
}
|
||||||
} else {
|
if (fileName.match(rxjs) && fs.existsSync(fileName)) {
|
||||||
if (fileName.match(rxjs)) {
|
return fs.readFileSync(fileName, 'utf8');
|
||||||
if (fs.existsSync(fileName)) {
|
|
||||||
return fs.readFileSync(fileName, 'utf8');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,15 +414,14 @@ export class MockMetadataBundlerHost implements MetadataBundlerHost {
|
||||||
function find(fileName: string, data: MockFileOrDirectory | undefined): MockFileOrDirectory|
|
function find(fileName: string, data: MockFileOrDirectory | undefined): MockFileOrDirectory|
|
||||||
undefined {
|
undefined {
|
||||||
if (!data) return undefined;
|
if (!data) return undefined;
|
||||||
let names = fileName.split('/');
|
const names = fileName.split('/');
|
||||||
if (names.length && !names[0].length) names.shift();
|
if (names.length && !names[0].length) names.shift();
|
||||||
let current: MockFileOrDirectory|undefined = data;
|
let current: MockFileOrDirectory|undefined = data;
|
||||||
for (let name of names) {
|
for (const name of names) {
|
||||||
if (typeof current === 'string')
|
if (typeof current !== 'object') {
|
||||||
return undefined;
|
return undefined;
|
||||||
else
|
}
|
||||||
current = (<MockDirectory>current)[name];
|
current = current[name];
|
||||||
if (!current) return undefined;
|
|
||||||
}
|
}
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
@ -603,11 +594,12 @@ export function compile(
|
||||||
useSummaries?: boolean,
|
useSummaries?: boolean,
|
||||||
preCompile?: (program: ts.Program) => void,
|
preCompile?: (program: ts.Program) => void,
|
||||||
postCompile?: (program: ts.Program) => void,
|
postCompile?: (program: ts.Program) => void,
|
||||||
|
stubsOnly?: boolean,
|
||||||
}& AotCompilerOptions = {},
|
}& AotCompilerOptions = {},
|
||||||
tsOptions: ts.CompilerOptions = {}): {genFiles: GeneratedFile[], outDir: MockDirectory} {
|
tsOptions: ts.CompilerOptions = {}): {genFiles: GeneratedFile[], outDir: MockDirectory} {
|
||||||
// when using summaries, always emit so the next step can use the results.
|
// when using summaries, always emit so the next step can use the results.
|
||||||
const emit = options.emit || options.useSummaries;
|
const emit = options.emit || options.useSummaries;
|
||||||
const preCompile = options.preCompile || expectNoDiagnostics;
|
const preCompile = options.preCompile || (() => {});
|
||||||
const postCompile = options.postCompile || expectNoDiagnostics;
|
const postCompile = options.postCompile || expectNoDiagnostics;
|
||||||
const rootDirArr = toMockFileArray(rootDirs);
|
const rootDirArr = toMockFileArray(rootDirs);
|
||||||
const scriptNames = rootDirArr.map(entry => entry.fileName).filter(isSource);
|
const scriptNames = rootDirArr.map(entry => entry.fileName).filter(isSource);
|
||||||
|
@ -620,9 +612,12 @@ export function compile(
|
||||||
}
|
}
|
||||||
const tsSettings = {...settings, ...tsOptions};
|
const tsSettings = {...settings, ...tsOptions};
|
||||||
const program = ts.createProgram(host.scriptNames.slice(0), tsSettings, host);
|
const program = ts.createProgram(host.scriptNames.slice(0), tsSettings, host);
|
||||||
if (preCompile) preCompile(program);
|
preCompile(program);
|
||||||
const {compiler, reflector} = createAotCompiler(aotHost, options);
|
const {compiler, reflector} = createAotCompiler(aotHost, options);
|
||||||
const genFiles = compiler.compileAllSync(program.getSourceFiles().map(sf => sf.fileName));
|
const analyzedModules =
|
||||||
|
compiler.analyzeModulesSync(program.getSourceFiles().map(sf => sf.fileName));
|
||||||
|
const genFiles = options.stubsOnly ? compiler.emitAllStubs(analyzedModules) :
|
||||||
|
compiler.emitAllImpls(analyzedModules);
|
||||||
genFiles.forEach((file) => {
|
genFiles.forEach((file) => {
|
||||||
const source = file.source || toTypeScript(file);
|
const source = file.source || toTypeScript(file);
|
||||||
if (isSource(file.genFileUrl)) {
|
if (isSource(file.genFileUrl)) {
|
||||||
|
@ -632,7 +627,7 @@ export function compile(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const newProgram = ts.createProgram(host.scriptNames.slice(0), tsSettings, host);
|
const newProgram = ts.createProgram(host.scriptNames.slice(0), tsSettings, host);
|
||||||
if (postCompile) postCompile(newProgram);
|
postCompile(newProgram);
|
||||||
if (emit) {
|
if (emit) {
|
||||||
newProgram.emit();
|
newProgram.emit();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue