Permalink
Browse files

feat: add .ngsummary.ts files to support AOT unit tests

  • Loading branch information...
tbosch authored and matsko committed Apr 26, 2017
1 parent 2714644 commit 547c3634733d8fb49ff88730cc3d6f13a2ac9fb8
Showing with 1,187 additions and 197 deletions.
  1. +1 −0 packages/compiler-cli/integrationtest/src/jit_summaries.html
  2. +52 −0 packages/compiler-cli/integrationtest/src/jit_summaries.ts
  3. +3 −0 packages/compiler-cli/integrationtest/src/module.ts
  4. +2 −1 packages/compiler-cli/integrationtest/test/all_spec.ts
  5. +73 −0 packages/compiler-cli/integrationtest/test/jit_summaries_spec.ts
  6. +2 −2 packages/compiler-cli/integrationtest/test/util.ts
  7. +3 −3 packages/compiler-cli/src/compiler_host.ts
  8. +38 −16 packages/compiler/src/aot/compiler.ts
  9. +1 −8 packages/compiler/src/aot/compiler_factory.ts
  10. +0 −8 packages/compiler/src/aot/compiler_host.ts
  11. +40 −11 packages/compiler/src/aot/static_symbol_resolver.ts
  12. +4 −2 packages/compiler/src/aot/summary_resolver.ts
  13. +160 −20 packages/compiler/src/aot/summary_serializer.ts
  14. +29 −9 packages/compiler/src/aot/util.ts
  15. +67 −27 packages/compiler/src/jit/compiler.ts
  16. +8 −10 packages/compiler/src/jit/compiler_factory.ts
  17. +20 −10 packages/compiler/src/metadata_resolver.ts
  18. +19 −4 packages/compiler/src/summary_resolver.ts
  19. +347 −0 packages/compiler/test/aot/jit_summaries_spec.ts
  20. +5 −1 packages/compiler/test/aot/static_symbol_resolver_spec.ts
  21. +7 −7 packages/compiler/test/aot/summary_resolver_spec.ts
  22. +50 −31 packages/compiler/test/aot/summary_serializer_spec.ts
  23. +21 −4 packages/compiler/testing/src/testing.ts
  24. +191 −0 packages/core/test/linker/jit_summaries_integration_spec.ts
  25. +27 −18 packages/core/testing/src/test_bed.ts
  26. +13 −1 packages/core/testing/src/test_compiler.ts
  27. +2 −2 packages/language-service/src/typescript_host.ts
  28. +2 −2 tools/public_api_guard/core/testing.d.ts
@@ -0,0 +1 @@
Hello world!
@@ -0,0 +1,52 @@
/**
* @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 {Component, Directive, Injectable, NgModule, Pipe} from '@angular/core';
const instances = new Map<any, Base>();
export function expectInstanceCreated(type: any) {
const instance = instances.get(type) !;
expect(instance).toBeDefined();
expect(instance.dep instanceof SomeDep).toBe(true);
}
export class SomeDep {}
export class Base {
constructor(public dep: SomeDep) { instances.set(Object.getPrototypeOf(this).constructor, this); }
}
@Component({templateUrl: './jit_summaries.html'})
export class SomePrivateComponent extends Base {
}
@Component({templateUrl: './jit_summaries.html'})
export class SomePublicComponent extends Base {
}
@Directive({selector: '[someDir]'})
export class SomeDirective extends Base {
}
@Pipe({name: 'somePipe'})
export class SomePipe extends Base {
transform(value: any) { return value; }
}
@Injectable()
export class SomeService extends Base {
}
@NgModule({
declarations: [SomePublicComponent, SomePrivateComponent, SomeDirective, SomePipe],
exports: [SomeDirective, SomePipe, SomePublicComponent],
providers: [SomeService]
})
export class SomeModule extends Base {
}
@@ -28,6 +28,9 @@ import {CompUsingRootModuleDirectiveAndPipe, SomeDirectiveInRootModule, SomeLibM
import {CompWithNgContent, ProjectingComp} from './projection';
import {CompForChildQuery, CompWithChildQuery, CompWithDirectiveChild, DirectiveForQuery} from './queries';
// Adding an export here so that TypeScript compiles the file as well
export {SomeModule as JitSummariesSomeModule} from './jit_summaries';
@NgModule({
declarations: [
AnimateCmp,
@@ -16,4 +16,5 @@ import './i18n_spec';
import './ng_module_spec';
import './projection_spec';
import './query_spec';
import './source_map_spec';
import './source_map_spec';
import './jit_summaries_spec';
@@ -0,0 +1,73 @@
/**
* @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 {Component} from '@angular/core';
import {TestBed} from '@angular/core/testing';
import {ServerTestingModule, platformServerTesting} from '@angular/platform-server/testing';
import {SomeDep, SomeDirective, SomeModule, SomePipe, SomePrivateComponent, SomeService, expectInstanceCreated} from '../src/jit_summaries';
import {SomeModuleNgSummary} from '../src/jit_summaries.ngsummary';
describe('Jit Summaries', () => {
beforeEach(() => {
TestBed.initTestEnvironment(ServerTestingModule, platformServerTesting(), SomeModuleNgSummary);
});
afterEach(() => { TestBed.resetTestEnvironment(); });
it('should use directive metadata from summaries', () => {
@Component({template: '<div someDir></div>'})
class TestComp {
}
TestBed.configureTestingModule({providers: [SomeDep], declarations: [TestComp, SomeDirective]})
.createComponent(TestComp);
expectInstanceCreated(SomeDirective);
});
it('should use pipe metadata from summaries', () => {
@Component({template: '{{1 | somePipe}}'})
class TestComp {
}
TestBed.configureTestingModule({providers: [SomeDep], declarations: [TestComp, SomePipe]})
.createComponent(TestComp);
expectInstanceCreated(SomePipe);
});
it('should use Service metadata from summaries', () => {
TestBed.configureTestingModule({
providers: [SomeService, SomeDep],
});
TestBed.get(SomeService);
expectInstanceCreated(SomeService);
});
it('should use NgModule metadata from summaries', () => {
@Component({template: '<div someDir>{{1 | somePipe}}</div>'})
class TestComp {
constructor(service: SomeService) {}
}
TestBed
.configureTestingModule(
{providers: [SomeDep], declarations: [TestComp], imports: [SomeModule]})
.createComponent(TestComp);
expectInstanceCreated(SomeModule);
expectInstanceCreated(SomeDirective);
expectInstanceCreated(SomePipe);
expectInstanceCreated(SomeService);
});
it('should allow to create private components from imported NgModule summaries', () => {
TestBed.configureTestingModule({providers: [SomeDep], imports: [SomeModule]})
.createComponent(SomePrivateComponent);
expectInstanceCreated(SomePrivateComponent);
});
});
@@ -8,14 +8,14 @@
import {NgModuleRef} from '@angular/core';
import {ComponentFixture} from '@angular/core/testing';
import {platformServer} from '@angular/platform-server';
import {platformServerTesting} from '@angular/platform-server/testing';
import {MainModule} from '../src/module';
import {MainModuleNgFactory} from '../src/module.ngfactory';
let mainModuleRef: NgModuleRef<MainModule> = null !;
beforeEach((done) => {
platformServer().bootstrapModuleFactory(MainModuleNgFactory).then((moduleRef: any) => {
platformServerTesting().bootstrapModuleFactory(MainModuleNgFactory).then((moduleRef: any) => {
mainModuleRef = moduleRef;
done();
});
@@ -15,9 +15,9 @@ import * as ts from 'typescript';
const EXT = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
const DTS = /\.d\.ts$/;
const NODE_MODULES = '/node_modules/';
const IS_GENERATED = /\.(ngfactory|ngstyle)$/;
const GENERATED_FILES = /\.ngfactory\.ts$|\.ngstyle\.ts$/;
const GENERATED_OR_DTS_FILES = /\.d\.ts$|\.ngfactory\.ts$|\.ngstyle\.ts$/;
const IS_GENERATED = /\.(ngfactory|ngstyle|ngsummary)$/;
const GENERATED_FILES = /\.ngfactory\.ts$|\.ngstyle\.ts$|\.ngsummary\.ts$/;
const GENERATED_OR_DTS_FILES = /\.d\.ts$|\.ngfactory\.ts$|\.ngstyle\.ts$|\.ngsummary\.ts$/;
const SHALLOW_IMPORT = /^((\w|-)+|(@(\w|-)+(\/(\w|-)+)+))$/;
export interface CompilerHostContext extends ts.ModuleResolutionHost {
@@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompileProviderMetadata, CompileTypeSummary, componentFactoryName, createHostComponentMeta, flatten, identifierName, sourceUrl, templateSourceUrl} from '../compile_metadata';
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompileIdentifierMetadata, CompileNgModuleMetadata, CompileNgModuleSummary, CompilePipeMetadata, CompileProviderMetadata, CompileSummaryKind, CompileTypeMetadata, CompileTypeSummary, componentFactoryName, createHostComponentMeta, flatten, identifierName, sourceUrl, templateSourceUrl} from '../compile_metadata';
import {CompilerConfig} from '../config';
import {Identifiers, createIdentifier, createIdentifierToken} from '../identifiers';
import {CompileMetadataResolver} from '../metadata_resolver';
@@ -22,9 +22,9 @@ import {ViewCompiler} from '../view_compiler/view_compiler';
import {AotCompilerHost} from './compiler_host';
import {GeneratedFile} from './generated_file';
import {StaticSymbol} from './static_symbol';
import {StaticSymbolResolver} from './static_symbol_resolver';
import {ResolvedStaticSymbol, StaticSymbolResolver} from './static_symbol_resolver';
import {serializeSummaries} from './summary_serializer';
import {ngfactoryFilePath, splitTypescriptSuffix, summaryFileName} from './util';
import {ngfactoryFilePath, splitTypescriptSuffix, summaryFileName, summaryForJitFileName, summaryForJitName} from './util';
export class AotCompiler {
constructor(
@@ -59,12 +59,12 @@ export class AotCompiler {
srcFileUrl: string, ngModuleByPipeOrDirective: Map<StaticSymbol, CompileNgModuleMetadata>,
directives: StaticSymbol[], pipes: StaticSymbol[], ngModules: StaticSymbol[],
injectables: StaticSymbol[]): GeneratedFile[] {
const fileSuffix = splitTypescriptSuffix(srcFileUrl)[1];
const fileSuffix = splitTypescriptSuffix(srcFileUrl, true)[1];
const statements: o.Statement[] = [];
const exportedVars: string[] = [];
const generatedFiles: GeneratedFile[] = [];
generatedFiles.push(this._createSummary(
generatedFiles.push(...this._createSummary(
srcFileUrl, directives, pipes, ngModules, injectables, statements, exportedVars));
// compile all ng modules
@@ -101,7 +101,7 @@ export class AotCompiler {
});
if (statements.length > 0) {
const srcModule = this._codegenSourceModule(
srcFileUrl, ngfactoryFilePath(srcFileUrl), statements, exportedVars);
srcFileUrl, ngfactoryFilePath(srcFileUrl, true), statements, exportedVars);
generatedFiles.unshift(srcModule);
}
return generatedFiles;
@@ -110,23 +110,45 @@ export class AotCompiler {
private _createSummary(
srcFileUrl: string, directives: StaticSymbol[], pipes: StaticSymbol[],
ngModules: StaticSymbol[], injectables: StaticSymbol[], targetStatements: o.Statement[],
targetExportedVars: string[]): GeneratedFile {
targetExportedVars: string[]): GeneratedFile[] {
const symbolSummaries = this._symbolResolver.getSymbolsOf(srcFileUrl)
.map(symbol => this._symbolResolver.resolveSymbol(symbol));
const typeSummaries: CompileTypeSummary[] = [
...ngModules.map(ref => this._metadataResolver.getNgModuleSummary(ref) !),
...directives.map(ref => this._metadataResolver.getDirectiveSummary(ref) !),
...pipes.map(ref => this._metadataResolver.getPipeSummary(ref) !),
...injectables.map(ref => this._metadataResolver.getInjectableSummary(ref) !)
];
const {json, exportAs} = serializeSummaries(
this._summaryResolver, this._symbolResolver, symbolSummaries, typeSummaries);
const typeData: {
summary: CompileTypeSummary,
metadata: CompileNgModuleMetadata | CompileDirectiveMetadata | CompilePipeMetadata |
CompileTypeMetadata
}[] =
[
...ngModules.map(ref => ({
summary: this._metadataResolver.getNgModuleSummary(ref) !,
metadata: this._metadataResolver.getNgModuleMetadata(ref) !
})),
...directives.map(ref => ({
summary: this._metadataResolver.getDirectiveSummary(ref) !,
metadata: this._metadataResolver.getDirectiveMetadata(ref) !
})),
...pipes.map(ref => ({
summary: this._metadataResolver.getPipeSummary(ref) !,
metadata: this._metadataResolver.getPipeMetadata(ref) !
})),
...injectables.map(ref => ({
summary: this._metadataResolver.getInjectableSummary(ref) !,
metadata: this._metadataResolver.getInjectableSummary(ref) !.type
}))
];
const {json, exportAs, forJit} =
serializeSummaries(this._summaryResolver, this._symbolResolver, symbolSummaries, typeData);
exportAs.forEach((entry) => {
targetStatements.push(
o.variable(entry.exportAs).set(o.importExpr({reference: entry.symbol})).toDeclStmt());
targetExportedVars.push(entry.exportAs);
});
return new GeneratedFile(srcFileUrl, summaryFileName(srcFileUrl), json);
return [
new GeneratedFile(srcFileUrl, summaryFileName(srcFileUrl), json),
this._codegenSourceModule(
srcFileUrl, summaryForJitFileName(srcFileUrl, true), forJit.statements,
forJit.exportedVars)
];
}
private _compileModule(ngModuleType: StaticSymbol, targetStatements: o.Statement[]): string {
@@ -35,7 +35,6 @@ import {StaticSymbolResolver} from './static_symbol_resolver';
import {AotSummaryResolver} from './summary_resolver';
/**
* Creates a new AotCompiler based on options and a host.
*/
@@ -69,16 +68,10 @@ export function createAotCompiler(compilerHost: AotCompilerHost, options: AotCom
new PipeResolver(staticReflector), summaryResolver, elementSchemaRegistry, normalizer,
console, symbolCache, staticReflector);
// TODO(vicb): do not pass options.i18nFormat here
const importResolver = {
getImportAs: (symbol: StaticSymbol) => symbolResolver.getImportAs(symbol) !,
fileNameToModuleName: (fileName: string, containingFilePath: string) =>
compilerHost.fileNameToModuleName(fileName, containingFilePath),
getTypeArity: (symbol: StaticSymbol) => symbolResolver.getTypeArity(symbol) !
};
const viewCompiler = new ViewCompiler(config, elementSchemaRegistry);
const compiler = new AotCompiler(
config, compilerHost, resolver, tmplParser, new StyleCompiler(urlResolver), viewCompiler,
new NgModuleCompiler(), new TypeScriptEmitter(importResolver), summaryResolver,
new NgModuleCompiler(), new TypeScriptEmitter(symbolResolver), summaryResolver,
options.locale || null, options.i18nFormat || null, options.genFilePreamble || null,
symbolResolver);
return {compiler, reflector: staticReflector};
@@ -14,14 +14,6 @@ import {AotSummaryResolverHost} from './summary_resolver';
* services and from underlying file systems.
*/
export interface AotCompilerHost extends StaticSymbolResolverHost, AotSummaryResolverHost {
/**
* Converts a file path to a module name that can be used as an `import.
* I.e. `path/to/importedFile.ts` should be imported by `path/to/containingFile.ts`.
*
* See ImportResolver.
*/
fileNameToModuleName(importedFilePath: string, containingFilePath: string): string|null;
/**
* Loads a resource (e.g. html / css)
*/
Oops, something went wrong.

0 comments on commit 547c363

Please sign in to comment.