Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 29 additions & 13 deletions modules/@angular/compiler/src/runtime_compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {AppModuleFactory, AppModuleMetadata, Compiler, ComponentFactory, ComponentResolver, Injectable, Provider} from '@angular/core';
import {AppModuleFactory, AppModuleMetadata, Compiler, ComponentFactory, ComponentResolver, ComponentStillLoadingError, Injectable, Injector, OptionalMetadata, Provider, SkipSelfMetadata} from '@angular/core';

import {BaseException} from '../src/facade/exceptions';
import {ConcreteType, IS_DART, Type, isBlank, isString, stringify} from '../src/facade/lang';
Expand Down Expand Up @@ -43,11 +43,13 @@ export class RuntimeCompiler implements ComponentResolver, Compiler {
private _compiledAppModuleCache = new Map<Type, AppModuleFactory<any>>();

constructor(
private _metadataResolver: CompileMetadataResolver,
private _injector: Injector, private _metadataResolver: CompileMetadataResolver,
private _templateNormalizer: DirectiveNormalizer, private _templateParser: TemplateParser,
private _styleCompiler: StyleCompiler, private _viewCompiler: ViewCompiler,
private _appModuleCompiler: AppModuleCompiler, private _genConfig: CompilerConfig) {}

get injector(): Injector { return this._injector; }

resolveComponent(component: Type|string): Promise<ComponentFactory<any>> {
if (isString(component)) {
return PromiseWrapper.reject(
Expand Down Expand Up @@ -76,12 +78,15 @@ export class RuntimeCompiler implements ComponentResolver, Compiler {
let componentCompilePromises: Promise<any>[] = [];
if (!appModuleFactory || !useCache) {
var compileModuleMeta = this._metadataResolver.getAppModuleMetadata(moduleType, metadata);
let boundCompiler = new BoundCompiler(
let boundCompilerFactory = (parentResolver: ComponentResolver) => new BoundCompiler(
this, compileModuleMeta.directives.map(dir => dir.type.runtime),
compileModuleMeta.pipes.map((pipe) => pipe.type.runtime));
// Always provide a bound Compiler / ComponentResolver
compileModuleMeta.providers.push(this._metadataResolver.getProviderMetadata(
new Provider(Compiler, {useValue: boundCompiler})));
compileModuleMeta.pipes.map((pipe) => pipe.type.runtime), parentResolver);
// Always provide a bound Compiler and ComponentResolver
compileModuleMeta.providers.push(
this._metadataResolver.getProviderMetadata(new Provider(Compiler, {
useFactory: boundCompilerFactory,
deps: [[new OptionalMetadata(), new SkipSelfMetadata(), ComponentResolver]]
})));
compileModuleMeta.providers.push(this._metadataResolver.getProviderMetadata(
new Provider(ComponentResolver, {useExisting: Compiler})));
var compileResult = this._appModuleCompiler.compile(compileModuleMeta);
Expand Down Expand Up @@ -130,8 +135,7 @@ export class RuntimeCompiler implements ComponentResolver, Compiler {
templates.forEach((template) => {
if (template.loading) {
if (isSync) {
throw new BaseException(
`Can't compile synchronously as ${template.compType.name} is still being loaded!`);
throw new ComponentStillLoadingError(template.compType.runtime);
} else {
loadingPromises.push(template.loading);
}
Expand Down Expand Up @@ -355,12 +359,19 @@ function assertComponent(meta: CompileDirectiveMetadata) {
*/
class BoundCompiler implements Compiler, ComponentResolver {
constructor(
private _delegate: RuntimeCompiler, private _directives: any[], private _pipes: any[]) {}
private _delegate: RuntimeCompiler, private _directives: any[], private _pipes: any[],
private _parentComponentResolver: ComponentResolver) {}

get injector(): Injector { return this._delegate.injector; }

resolveComponent(component: Type|string): Promise<ComponentFactory<any>> {
if (isString(component)) {
return PromiseWrapper.reject(
new BaseException(`Cannot resolve component using '${component}'.`), null);
if (this._parentComponentResolver) {
return this._parentComponentResolver.resolveComponent(component);
} else {
return PromiseWrapper.reject(
new BaseException(`Cannot resolve component using '${component}'.`), null);
}
}
return this.compileComponentAsync(<ConcreteType<any>>component);
}
Expand Down Expand Up @@ -388,7 +399,12 @@ class BoundCompiler implements Compiler, ComponentResolver {
/**
* Clears all caches
*/
clearCache(): void { this._delegate.clearCache(); }
clearCache(): void {
this._delegate.clearCache();
if (this._parentComponentResolver) {
this._parentComponentResolver.clearCache();
}
}

/**
* Clears the cache for the given component/appModule.
Expand Down
7 changes: 4 additions & 3 deletions modules/@angular/compiler/test/directive_normalizer_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,19 @@ import {DirectiveNormalizer} from '@angular/compiler/src/directive_normalizer';
import {XHR} from '@angular/compiler/src/xhr';
import {MockXHR} from '@angular/compiler/testing/xhr_mock';
import {ViewEncapsulation} from '@angular/core/src/metadata/view';
import {configureCompiler} from '@angular/core/testing';
import {beforeEach, beforeEachProviders, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {AsyncTestCompleter} from '@angular/core/testing/testing_internal';

import {SpyXHR} from './spies';
import {TEST_PROVIDERS} from './test_bindings';
import {TEST_COMPILER_PROVIDERS} from './test_bindings';

export function main() {
describe('DirectiveNormalizer', () => {
var dirType: CompileTypeMetadata;
var dirTypeWithHttpUrl: CompileTypeMetadata;

beforeEachProviders(() => TEST_PROVIDERS);
beforeEach(() => { configureCompiler({providers: TEST_COMPILER_PROVIDERS}); });

beforeEach(() => {
dirType = new CompileTypeMetadata({moduleUrl: 'package:some/module/a.js', name: 'SomeComp'});
Expand Down Expand Up @@ -179,7 +180,7 @@ export function main() {

describe('normalizeExternalStylesheets', () => {

beforeEachProviders(() => [{provide: XHR, useClass: SpyXHR}]);
beforeEach(() => { configureCompiler({providers: [{provide: XHR, useClass: SpyXHR}]}); });

it('should load an external stylesheet',
inject(
Expand Down
19 changes: 12 additions & 7 deletions modules/@angular/compiler/test/metadata_resolver_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,18 @@
import {CompilerConfig} from '@angular/compiler/src/config';
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, ChangeDetectionStrategy, Component, Directive, DoCheck, Injectable, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewEncapsulation} from '@angular/core';
import {LIFECYCLE_HOOKS_VALUES} from '@angular/core/src/metadata/lifecycle_hooks';
import {configureCompiler} from '@angular/core/testing';
import {afterEach, beforeEach, beforeEachProviders, ddescribe, describe, expect, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';

import {IS_DART, stringify} from '../src/facade/lang';
import {CompileMetadataResolver} from '../src/metadata_resolver';

import {MalformedStylesComponent} from './metadata_resolver_fixture';
import {TEST_PROVIDERS} from './test_bindings';
import {TEST_COMPILER_PROVIDERS} from './test_bindings';

export function main() {
describe('CompileMetadataResolver', () => {
beforeEachProviders(() => TEST_PROVIDERS);
beforeEach(() => { configureCompiler({providers: TEST_COMPILER_PROVIDERS}); });

describe('getMetadata', () => {
it('should read metadata',
Expand Down Expand Up @@ -110,11 +111,15 @@ export function main() {
}));

describe('platform directives', () => {
beforeEachProviders(() => [{
provide: CompilerConfig,
useValue: new CompilerConfig(
{genDebugInfo: true, platformDirectives: [ADirective]})
}]);
beforeEach(() => {
configureCompiler({
providers: [{
provide: CompilerConfig,
useValue:
new CompilerConfig({genDebugInfo: true, platformDirectives: [ADirective]})
}]
});
});

it('should include platform directives when available',
inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => {
Expand Down
4 changes: 2 additions & 2 deletions modules/@angular/compiler/test/runtime_compiler_spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {beforeEach, ddescribe, xdescribe, describe, expect, iit, inject, beforeEachProviders, it, xit,} from '@angular/core/testing/testing_internal';
import {Injectable, Component, Input, ViewMetadata, Compiler, ComponentFactory, Injector, AppModule, AppModuleMetadata, AppModuleFactory} from '@angular/core';
import {ConcreteType, stringify} from '../src/facade/lang';
import {fakeAsync, tick, TestComponentBuilder, ComponentFixture} from '@angular/core/testing';
import {fakeAsync, tick, TestComponentBuilder, ComponentFixture, configureCompiler} from '@angular/core/testing';
import {XHR, ViewResolver} from '@angular/compiler';
import {MockViewResolver} from '@angular/compiler/testing';

Expand Down Expand Up @@ -31,7 +31,7 @@ export function main() {
let viewResolver: MockViewResolver;
let injector: Injector;

beforeEachProviders(() => [{provide: XHR, useValue: new SpyXHR()}]);
beforeEach(() => { configureCompiler({providers: [{provide: XHR, useClass: SpyXHR}]}); });

beforeEach(inject(
[Compiler, TestComponentBuilder, XHR, ViewResolver, Injector],
Expand Down
40 changes: 28 additions & 12 deletions modules/@angular/compiler/test/template_parser_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ import {TEMPLATE_TRANSFORMS, TemplateParser, splitClasses} from '@angular/compil
import {MockSchemaRegistry} from '@angular/compiler/testing';
import {SecurityContext} from '@angular/core';
import {Console} from '@angular/core/src/console';
import {configureCompiler} from '@angular/core/testing';
import {afterEach, beforeEach, beforeEachProviders, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';

import {Identifiers, identifierToken} from '../src/identifiers';
import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../src/interpolation_config';

import {unparse} from './expression_parser/unparser';
import {TEST_PROVIDERS} from './test_bindings';
import {TEST_COMPILER_PROVIDERS} from './test_bindings';

var someModuleUrl = 'package:someModule';

Expand All @@ -39,9 +40,9 @@ export function main() {
var console: ArrayConsole;

function commonBeforeEach() {
beforeEachProviders(() => {
beforeEach(() => {
console = new ArrayConsole();
return [{provide: Console, useValue: console}];
configureCompiler({providers: [{provide: Console, useValue: console}]});
});
beforeEach(inject([TemplateParser], (parser: TemplateParser) => {
var component = CompileDirectiveMetadata.create({
Expand All @@ -67,10 +68,14 @@ export function main() {
}

describe('TemplateParser template transform', () => {
beforeEachProviders(() => [TEST_PROVIDERS, MOCK_SCHEMA_REGISTRY]);
beforeEach(() => { configureCompiler({providers: TEST_COMPILER_PROVIDERS}); });

beforeEachProviders(
() => [{provide: TEMPLATE_TRANSFORMS, useValue: new FooAstTransformer(), multi: true}]);
beforeEach(() => {
configureCompiler({
providers:
[{provide: TEMPLATE_TRANSFORMS, useValue: new FooAstTransformer(), multi: true}]
});
});

describe('single', () => {
commonBeforeEach();
Expand All @@ -80,8 +85,12 @@ export function main() {
});

describe('multiple', () => {
beforeEachProviders(
() => [{provide: TEMPLATE_TRANSFORMS, useValue: new BarAstTransformer(), multi: true}]);
beforeEach(() => {
configureCompiler({
providers:
[{provide: TEMPLATE_TRANSFORMS, useValue: new BarAstTransformer(), multi: true}]
});
});

commonBeforeEach();
it('should compose transformers', () => {
Expand All @@ -93,9 +102,14 @@ export function main() {
describe('TemplateParser Security', () => {
// Semi-integration test to make sure TemplateParser properly sets the security context.
// Uses the actual DomElementSchemaRegistry.
beforeEachProviders(
() =>
[TEST_PROVIDERS, {provide: ElementSchemaRegistry, useClass: DomElementSchemaRegistry}]);
beforeEach(() => {
configureCompiler({
providers: [
TEST_COMPILER_PROVIDERS,
{provide: ElementSchemaRegistry, useClass: DomElementSchemaRegistry}
]
});
});

commonBeforeEach();

Expand Down Expand Up @@ -125,7 +139,9 @@ export function main() {
});

describe('TemplateParser', () => {
beforeEachProviders(() => [TEST_PROVIDERS, MOCK_SCHEMA_REGISTRY]);
beforeEach(() => {
configureCompiler({providers: [TEST_COMPILER_PROVIDERS, MOCK_SCHEMA_REGISTRY]});
});

commonBeforeEach();

Expand Down
2 changes: 1 addition & 1 deletion modules/@angular/compiler/test/test_bindings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {createUrlResolverWithoutPackagePrefix} from '@angular/compiler/src/url_r
import {MockSchemaRegistry} from '@angular/compiler/testing';
import {MockXHR} from '@angular/compiler/testing/xhr_mock';

export var TEST_PROVIDERS: any[] = [
export var TEST_COMPILER_PROVIDERS: any[] = [
{provide: ElementSchemaRegistry, useValue: new MockSchemaRegistry({}, {})},
{provide: XHR, useClass: MockXHR},
{provide: UrlResolver, useFactory: createUrlResolverWithoutPackagePrefix}
Expand Down
8 changes: 3 additions & 5 deletions modules/@angular/compiler/testing/test_component_builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/

import {AnimationEntryMetadata, Compiler, ComponentFactory, Injectable, Injector, NgZone, ViewMetadata} from '@angular/core';
import {ComponentFixture, ComponentFixtureNoNgZone, TestComponentBuilder} from '@angular/core/testing';
import {AnimationEntryMetadata, Compiler, ComponentFactory, Inject, Injectable, Injector, NgZone, ViewMetadata} from '@angular/core';
import {ComponentFixture, ComponentFixtureNoNgZone, TestComponentBuilder, TestInjector} from '@angular/core/testing';

import {DirectiveResolver, ViewResolver} from '../index';
import {MapWrapper} from '../src/facade/collection';
Expand Down Expand Up @@ -54,9 +54,7 @@ export class OverridingTestComponentBuilder extends TestComponentBuilder {
/** @internal */
_viewOverrides = new Map<Type, ViewMetadata>();



constructor(injector: Injector) { super(injector); }
constructor(@Inject(TestInjector) injector: Injector) { super(injector); }

/** @internal */
_clone(): OverridingTestComponentBuilder {
Expand Down
2 changes: 1 addition & 1 deletion modules/@angular/core/src/linker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
// Public API for compiler
export {AppModuleFactory, AppModuleRef} from './linker/app_module_factory';
export {AppModuleFactoryLoader} from './linker/app_module_factory_loader';
export {Compiler} from './linker/compiler';
export {Compiler, ComponentStillLoadingError} from './linker/compiler';
export {ComponentFactory, ComponentRef} from './linker/component_factory';
export {ComponentFactoryResolver, NoComponentFactoryError} from './linker/component_factory_resolver';
export {ComponentResolver} from './linker/component_resolver';
Expand Down
24 changes: 22 additions & 2 deletions modules/@angular/core/src/linker/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {Injector} from '../di';
import {BaseException} from '../facade/exceptions';
import {ConcreteType, Type, stringify} from '../facade/lang';
import {AppModuleMetadata} from '../metadata/app_module';
Expand All @@ -14,6 +15,17 @@ import {AppModuleFactory} from './app_module_factory';
import {ComponentFactory} from './component_factory';


/**
* Indicates that a component is still being loaded in a synchronous compile.
*
* @stable
*/
export class ComponentStillLoadingError extends BaseException {
constructor(public compType: Type) {
super(`Can't compile synchronously as ${stringify(compType)} is still being loaded!`);
}
}

/**
* Low-level service for running the angular compiler duirng runtime
* to create {@link ComponentFactory}s, which
Expand All @@ -25,6 +37,13 @@ import {ComponentFactory} from './component_factory';
* @stable
*/
export class Compiler {
/**
* Returns the injector with which the compiler has been created.
*/
get injector(): Injector {
throw new BaseException(`Runtime compiler is not loaded. Tried to read the injector.`);
}

/**
* Loads the template and styles of a component and returns the associated `ComponentFactory`.
*/
Expand All @@ -34,7 +53,8 @@ export class Compiler {
}
/**
* Compiles the given component. All templates have to be either inline or compiled via
* `compileComponentAsync` before.
* `compileComponentAsync` before. Otherwise throws a {@link
* CompileSyncComponentStillLoadingError}.
*/
compileComponentSync<T>(component: ConcreteType<T>): ComponentFactory<T> {
throw new BaseException(
Expand All @@ -43,7 +63,7 @@ export class Compiler {
/**
* Compiles the given App Module. All templates of the components listed in `precompile`
* have to be either inline or compiled before via `compileComponentAsync` /
* `compileAppModuleAsync`.
* `compileAppModuleAsync`. Otherwise throws a {@link CompileSyncComponentStillLoadingError}.
*/
compileAppModuleSync<T>(moduleType: ConcreteType<T>, metadata: AppModuleMetadata = null):
AppModuleFactory<T> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {DEFAULT_STATE} from '../../src/animation/animation_constants';
import {AnimationEntryMetadata, animate, group, keyframes, sequence, state, style, transition, trigger} from '../../src/animation/metadata';
import {AUTO_STYLE} from '../../src/animation/metadata';
import {IS_DART, isArray, isPresent} from '../../src/facade/lang';
import {fakeAsync, flushMicrotasks, tick} from '../../testing';
import {configureCompiler, configureModule, fakeAsync, flushMicrotasks, tick} from '../../testing';
import {AsyncTestCompleter, beforeEach, beforeEachProviders, ddescribe, describe, expect, iit, inject, it, xdescribe, xit} from '../../testing/testing_internal';

export function main() {
Expand All @@ -33,13 +33,10 @@ export function main() {

function declareTests({useJit}: {useJit: boolean}) {
describe('animation tests', function() {
beforeEachProviders(
() =>
[{
provide: CompilerConfig,
useValue: new CompilerConfig({genDebugInfo: true, useJit: useJit})
},
{provide: AnimationDriver, useClass: MockAnimationDriver}]);
beforeEachProviders(() => {
configureCompiler({useJit: useJit});
configureModule({providers: [{provide: AnimationDriver, useClass: MockAnimationDriver}]});
});

var makeAnimationCmp =
(tcb: TestComponentBuilder, tpl: string,
Expand Down
Loading