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:

committed by
Chuck Jazdzewski

parent
fa809ec8cf
commit
eba59aaf87
69
packages/compiler/test/aot/emit_stubs_spec.ts
Normal file
69
packages/compiler/test/aot/emit_stubs_spec.ts
Normal file
@ -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);
|
||||
if (effectiveName == fileName) {
|
||||
let result = open(fileName, this.data) != null;
|
||||
return result;
|
||||
} else {
|
||||
if (fileName.match(rxjs)) {
|
||||
let result = fs.existsSync(effectiveName);
|
||||
return result;
|
||||
}
|
||||
return false;
|
||||
return open(fileName, this.data) != null;
|
||||
}
|
||||
if (fileName.match(rxjs)) {
|
||||
return fs.existsSync(effectiveName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
readFile(fileName: string): string { return this.getFileContent(fileName) !; }
|
||||
@ -303,18 +300,13 @@ export class MockCompilerHost implements ts.CompilerHost {
|
||||
if (/^lib.*\.d\.ts$/.test(basename)) {
|
||||
let libPath = ts.getDefaultLibFilePath(settings);
|
||||
return fs.readFileSync(path.join(path.dirname(libPath), basename), 'utf8');
|
||||
} else {
|
||||
let effectiveName = this.getEffectiveName(fileName);
|
||||
if (effectiveName === fileName) {
|
||||
const result = open(fileName, this.data);
|
||||
return result;
|
||||
} else {
|
||||
if (fileName.match(rxjs)) {
|
||||
if (fs.existsSync(fileName)) {
|
||||
return fs.readFileSync(fileName, 'utf8');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let effectiveName = this.getEffectiveName(fileName);
|
||||
if (effectiveName === fileName) {
|
||||
return open(fileName, this.data);
|
||||
}
|
||||
if (fileName.match(rxjs) && 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|
|
||||
undefined {
|
||||
if (!data) return undefined;
|
||||
let names = fileName.split('/');
|
||||
const names = fileName.split('/');
|
||||
if (names.length && !names[0].length) names.shift();
|
||||
let current: MockFileOrDirectory|undefined = data;
|
||||
for (let name of names) {
|
||||
if (typeof current === 'string')
|
||||
for (const name of names) {
|
||||
if (typeof current !== 'object') {
|
||||
return undefined;
|
||||
else
|
||||
current = (<MockDirectory>current)[name];
|
||||
if (!current) return undefined;
|
||||
}
|
||||
current = current[name];
|
||||
}
|
||||
return current;
|
||||
}
|
||||
@ -603,11 +594,12 @@ export function compile(
|
||||
useSummaries?: boolean,
|
||||
preCompile?: (program: ts.Program) => void,
|
||||
postCompile?: (program: ts.Program) => void,
|
||||
stubsOnly?: boolean,
|
||||
}& AotCompilerOptions = {},
|
||||
tsOptions: ts.CompilerOptions = {}): {genFiles: GeneratedFile[], outDir: MockDirectory} {
|
||||
// when using summaries, always emit so the next step can use the results.
|
||||
const emit = options.emit || options.useSummaries;
|
||||
const preCompile = options.preCompile || expectNoDiagnostics;
|
||||
const preCompile = options.preCompile || (() => {});
|
||||
const postCompile = options.postCompile || expectNoDiagnostics;
|
||||
const rootDirArr = toMockFileArray(rootDirs);
|
||||
const scriptNames = rootDirArr.map(entry => entry.fileName).filter(isSource);
|
||||
@ -620,9 +612,12 @@ export function compile(
|
||||
}
|
||||
const tsSettings = {...settings, ...tsOptions};
|
||||
const program = ts.createProgram(host.scriptNames.slice(0), tsSettings, host);
|
||||
if (preCompile) preCompile(program);
|
||||
preCompile(program);
|
||||
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) => {
|
||||
const source = file.source || toTypeScript(file);
|
||||
if (isSource(file.genFileUrl)) {
|
||||
@ -632,7 +627,7 @@ export function compile(
|
||||
}
|
||||
});
|
||||
const newProgram = ts.createProgram(host.scriptNames.slice(0), tsSettings, host);
|
||||
if (postCompile) postCompile(newProgram);
|
||||
postCompile(newProgram);
|
||||
if (emit) {
|
||||
newProgram.emit();
|
||||
}
|
||||
|
Reference in New Issue
Block a user