refactor(proto_view_factory): expose data for generating change detectors

Also consolidates metadata handling in `ElementInjector`

BREAKING CHANGE:
- renames `DirectiveMetadataReader` into `DirectiveResolver`
  and removes `src/core/compiler/directive_metadata`.

Fixes #1712
Fixes #1713
This commit is contained in:
Tobias Bosch
2015-05-11 17:59:39 -07:00
parent 5114411749
commit ecb068019b
33 changed files with 685 additions and 436 deletions
+1 -2
View File
@@ -11,7 +11,6 @@ import {
xit,
} from 'angular2/test_lib';
import {bootstrap} from 'angular2/src/core/application';
import {appComponentAnnotatedTypeToken} from 'angular2/src/core/application_tokens';
import {Component, Directive} from 'angular2/src/core/annotations_impl/annotations';
import {DOM} from 'angular2/src/dom/dom_adapter';
import {ListWrapper} from 'angular2/src/facade/collection';
@@ -114,7 +113,7 @@ export function main() {
it('should resolve an injector promise and contain bindings', inject([AsyncTestCompleter], (async) => {
var refPromise = bootstrap(HelloRootCmp, testBindings);
refPromise.then((ref) => {
expect(ref.injector.get(appComponentAnnotatedTypeToken).type).toBe(HelloRootCmp);
expect(ref.injector.get(HelloRootCmp)).toBeAnInstanceOf(HelloRootCmp);
async.done();
});
}));
+35 -32
View File
@@ -20,7 +20,7 @@ import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
import {AppProtoView} from 'angular2/src/core/compiler/view';
import {ElementBinder} from 'angular2/src/core/compiler/element_binder';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver';
import {Component, Directive} from 'angular2/src/core/annotations_impl/annotations';
import {Attribute} from 'angular2/src/core/annotations_impl/di';
import {View} from 'angular2/src/core/annotations_impl/view';
@@ -37,10 +37,10 @@ import {RenderCompiler} from 'angular2/src/render/api';
export function main() {
describe('compiler', function() {
var reader, tplResolver, renderCompiler, protoViewFactory, cmpUrlMapper, renderCompileRequests;
var directiveResolver, tplResolver, renderCompiler, protoViewFactory, cmpUrlMapper, renderCompileRequests;
beforeEach(() => {
reader = new DirectiveMetadataReader();
directiveResolver = new DirectiveResolver();
tplResolver = new FakeTemplateResolver();
cmpUrlMapper = new RuntimeComponentUrlMapper();
renderCompiler = new SpyRenderCompiler();
@@ -56,7 +56,7 @@ export function main() {
protoViewFactory = new FakeProtoViewFactory(protoViewFactoryResults)
return new Compiler(
reader,
directiveResolver,
new CompilerCache(),
tplResolver,
cmpUrlMapper,
@@ -70,7 +70,7 @@ export function main() {
function captureTemplate(template:View):Promise<renderApi.ViewDefinition> {
tplResolver.setView(MainComponent, template);
var compiler = createCompiler([createRenderProtoView()], [createProtoView()]);
var compiler = createCompiler([createRenderProtoView()], [[createProtoView()]]);
return compiler.compile(MainComponent).then( (_) => {
expect(renderCompileRequests.length).toBe(1);
return renderCompileRequests[0];
@@ -219,7 +219,7 @@ export function main() {
tplResolver.setView(MainComponent, new View({template: '<div></div>'}));
var renderProtoView = createRenderProtoView();
var expectedProtoView = createProtoView();
var compiler = createCompiler([renderProtoView], [expectedProtoView]);
var compiler = createCompiler([renderProtoView], [[expectedProtoView]]);
compiler.compile(MainComponent).then( (_) => {
var request = protoViewFactory.requests[0];
expect(request[1]).toBe(renderProtoView);
@@ -229,7 +229,7 @@ export function main() {
it('should pass the component binding', inject([AsyncTestCompleter], (async) => {
tplResolver.setView(MainComponent, new View({template: '<div></div>'}));
var compiler = createCompiler([createRenderProtoView()], [createProtoView()]);
var compiler = createCompiler([createRenderProtoView()], [[createProtoView()]]);
compiler.compile(MainComponent).then( (_) => {
var request = protoViewFactory.requests[0];
expect(request[0].key.token).toBe(MainComponent);
@@ -244,7 +244,7 @@ export function main() {
directives: [SomeDirective]
})
);
var compiler = createCompiler([createRenderProtoView()], [createProtoView()]);
var compiler = createCompiler([createRenderProtoView()], [[createProtoView()]]);
compiler.compile(MainComponent).then( (_) => {
var request = protoViewFactory.requests[0];
var binding = request[2][0];
@@ -257,7 +257,7 @@ export function main() {
tplResolver.setView(MainComponent, new View({template: '<div></div>'}));
var renderProtoView = createRenderProtoView();
var expectedProtoView = createProtoView();
var compiler = createCompiler([renderProtoView], [expectedProtoView]);
var compiler = createCompiler([renderProtoView], [[expectedProtoView]]);
compiler.compile(MainComponent).then( (protoViewRef) => {
expect(internalProtoView(protoViewRef)).toBe(expectedProtoView);
async.done();
@@ -270,7 +270,7 @@ export function main() {
tplResolver.setView(MainComponent, new View({template: '<div></div>'}));
tplResolver.setView(NestedComponent, new View({template: '<div></div>'}));
var mainProtoView = createProtoView([
createComponentElementBinder(reader, NestedComponent)
createComponentElementBinder(directiveResolver, NestedComponent)
]);
var nestedProtoView = createProtoView();
var compiler = createCompiler(
@@ -278,7 +278,7 @@ export function main() {
createRenderProtoView([createRenderComponentElementBinder(0)]),
createRenderProtoView()
],
[mainProtoView, nestedProtoView]
[[mainProtoView], [nestedProtoView]]
);
compiler.compile(MainComponent).then( (protoViewRef) => {
expect(internalProtoView(protoViewRef)).toBe(mainProtoView);
@@ -294,7 +294,7 @@ export function main() {
createViewportElementBinder(null)
]);
var viewportProtoView = createProtoView([
createComponentElementBinder(reader, NestedComponent)
createComponentElementBinder(directiveResolver, NestedComponent)
]);
var nestedProtoView = createProtoView();
var compiler = createCompiler(
@@ -303,16 +303,15 @@ export function main() {
createRenderViewportElementBinder(
createRenderProtoView([
createRenderComponentElementBinder(0)
])
], renderApi.ProtoViewDto.EMBEDDED_VIEW_TYPE)
)
]),
createRenderProtoView()
],
[mainProtoView, viewportProtoView, nestedProtoView]
[[mainProtoView, viewportProtoView], [nestedProtoView]]
);
compiler.compile(MainComponent).then( (protoViewRef) => {
expect(internalProtoView(protoViewRef)).toBe(mainProtoView);
expect(mainProtoView.elementBinders[0].nestedProtoView).toBe(viewportProtoView);
expect(viewportProtoView.elementBinders[0].nestedProtoView).toBe(nestedProtoView);
async.done();
@@ -323,7 +322,7 @@ export function main() {
tplResolver.setView(MainComponent, new View({template: '<div></div>'}));
var renderProtoView = createRenderProtoView();
var expectedProtoView = createProtoView();
var compiler = createCompiler([renderProtoView], [expectedProtoView]);
var compiler = createCompiler([renderProtoView], [[expectedProtoView]]);
compiler.compile(MainComponent).then( (protoViewRef) => {
expect(internalProtoView(protoViewRef)).toBe(expectedProtoView);
return compiler.compile(MainComponent);
@@ -337,7 +336,7 @@ export function main() {
tplResolver.setView(MainComponent, new View({template: '<div></div>'}));
var renderProtoViewCompleter = PromiseWrapper.completer();
var expectedProtoView = createProtoView();
var compiler = createCompiler([renderProtoViewCompleter.promise], [expectedProtoView]);
var compiler = createCompiler([renderProtoViewCompleter.promise], [[expectedProtoView]]);
renderProtoViewCompleter.resolve(createRenderProtoView());
PromiseWrapper.all([
compiler.compile(MainComponent),
@@ -352,13 +351,13 @@ export function main() {
it('should allow recursive components', inject([AsyncTestCompleter], (async) => {
tplResolver.setView(MainComponent, new View({template: '<div></div>'}));
var mainProtoView = createProtoView([
createComponentElementBinder(reader, MainComponent)
createComponentElementBinder(directiveResolver, MainComponent)
]);
var compiler = createCompiler(
[createRenderProtoView([
createRenderComponentElementBinder(0)
])],
[mainProtoView]
[[mainProtoView]]
);
compiler.compile(MainComponent).then( (protoViewRef) => {
expect(internalProtoView(protoViewRef)).toBe(mainProtoView);
@@ -370,19 +369,19 @@ export function main() {
it('should create host proto views', inject([AsyncTestCompleter], (async) => {
renderCompiler.spy('compileHost').andCallFake( (componentId) => {
return PromiseWrapper.resolve(
createRenderProtoView([createRenderComponentElementBinder(0)])
createRenderProtoView([createRenderComponentElementBinder(0)], renderApi.ProtoViewDto.HOST_VIEW_TYPE)
);
});
tplResolver.setView(MainComponent, new View({template: '<div></div>'}));
var rootProtoView = createProtoView([
createComponentElementBinder(reader, MainComponent)
createComponentElementBinder(directiveResolver, MainComponent)
]);
var mainProtoView = createProtoView();
var compiler = createCompiler(
[
createRenderProtoView()
],
[rootProtoView, mainProtoView]
[[rootProtoView], [mainProtoView]]
);
compiler.compileInHost(MainComponent).then( (protoViewRef) => {
expect(internalProtoView(protoViewRef)).toBe(rootProtoView);
@@ -400,13 +399,13 @@ export function main() {
});
}
function createDirectiveBinding(reader, type) {
var meta = reader.read(type);
return DirectiveBinding.createFromType(meta.type, meta.annotation);
function createDirectiveBinding(directiveResolver, type) {
var annotation = directiveResolver.resolve(type);
return DirectiveBinding.createFromType(type, annotation);
}
function createProtoView(elementBinders = null) {
var pv = new AppProtoView(null, null, null, null, null);
var pv = new AppProtoView(null, null, MapWrapper.create());
if (isBlank(elementBinders)) {
elementBinders = [];
}
@@ -414,8 +413,8 @@ function createProtoView(elementBinders = null) {
return pv;
}
function createComponentElementBinder(reader, type) {
var binding = createDirectiveBinding(reader, type);
function createComponentElementBinder(directiveResolver, type) {
var binding = createDirectiveBinding(directiveResolver, type);
return new ElementBinder(
0, null, 0,
null, binding
@@ -431,12 +430,16 @@ function createViewportElementBinder(nestedProtoView) {
return elBinder;
}
function createRenderProtoView(elementBinders = null) {
function createRenderProtoView(elementBinders = null, type:number = null) {
if (isBlank(type)) {
type = renderApi.ProtoViewDto.COMPONENT_VIEW_TYPE;
}
if (isBlank(elementBinders)) {
elementBinders = [];
}
return new renderApi.ProtoViewDto({
elementBinders: elementBinders
elementBinders: elementBinders,
type: type
});
}
@@ -549,8 +552,8 @@ class FakeProtoViewFactory extends ProtoViewFactory {
this._results = results;
}
createProtoView(parentProtoView, componentBinding:DirectiveBinding, renderProtoView: renderApi.ProtoViewDto,
directives:List<DirectiveBinding>):AppProtoView {
createAppProtoViews(componentBinding:DirectiveBinding, renderProtoView: renderApi.ProtoViewDto,
directives:List<DirectiveBinding>):List<AppProtoView> {
ListWrapper.push(this.requests, [componentBinding, renderProtoView, directives]);
return ListWrapper.removeAt(this._results, 0);
}
@@ -1,57 +1,29 @@
import {isPresent} from 'angular2/src/facade/lang';
import {ListWrapper} from 'angular2/src/facade/collection';
import {ddescribe, describe, it, iit, expect, beforeEach} from 'angular2/test_lib';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {Directive, Component} from 'angular2/src/core/annotations_impl/annotations';
import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata';
import {Injectable, Injector} from 'angular2/di';
@Injectable()
class SomeInjectable {}
import {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver';
import {Directive} from 'angular2/src/core/annotations_impl/annotations';
@Directive({selector: 'someDirective'})
class SomeDirective {}
@Component({selector: 'someComponent', injectables: [SomeInjectable]})
class SomeComponent {}
class SomeDirectiveWithoutAnnotation {
}
export function main() {
describe("DirectiveMetadataReader", () => {
describe("DirectiveResolver", () => {
var reader;
beforeEach(() => {
reader = new DirectiveMetadataReader();
reader = new DirectiveResolver();
});
it('should read out the Directive annotation', () => {
var directiveMetadata = reader.read(SomeDirective);
expect(directiveMetadata).toEqual(
new DirectiveMetadata(SomeDirective, new Directive({selector: 'someDirective'}), null));
});
it('should read out the Component annotation', () => {
var m = reader.read(SomeComponent);
// For some reason `toEqual` fails to compare ResolvedBinding objects.
// Have to decompose and compare.
expect(m.type).toEqual(SomeComponent);
expect(m.annotation)
.toEqual(new Component({selector: 'someComponent', injectables: [SomeInjectable]}));
var resolvedList = ListWrapper.reduce(m.resolvedInjectables, function(prev, elem) {
if (isPresent(elem)) {
ListWrapper.push(prev, elem);
}
return prev;
}, []);
expect(resolvedList.length).toBe(1);
expect(resolvedList[0].key.token).toBe(SomeInjectable);
var directiveMetadata = reader.resolve(SomeDirective);
expect(directiveMetadata).toEqual(new Directive({selector: 'someDirective'}));
});
it('should throw if not matching annotation is found', () => {
expect(() => {
reader.read(SomeDirectiveWithoutAnnotation);
reader.resolve(SomeDirectiveWithoutAnnotation);
}).toThrowError('No Directive annotation found on SomeDirectiveWithoutAnnotation');
});
});
@@ -506,7 +506,7 @@ export function main() {
});
it("should instantiate directives that depend on pre built objects", function () {
var protoView = new AppProtoView(null, null, null, null, null);
var protoView = new AppProtoView(null, null, null);
var inj = injector([NeedsProtoViewRef], null, false, new PreBuiltObjects(null, null, protoView));
expect(inj.get(NeedsProtoViewRef).protoViewRef).toEqual(new ProtoViewRef(protoView));
@@ -800,7 +800,7 @@ export function main() {
});
it("should inject ProtoViewRef", function () {
var protoView = new AppProtoView(null, null, null, null, null);
var protoView = new AppProtoView(null, null, null);
var inj = injector([NeedsProtoViewRef], null, false, new PreBuiltObjects(null, null, protoView));
expect(inj.get(NeedsProtoViewRef).protoViewRef).toEqual(new ProtoViewRef(protoView));
@@ -0,0 +1,109 @@
import {
AsyncTestCompleter,
beforeEach,
xdescribe,
ddescribe,
describe,
el,
expect,
iit,
inject,
IS_DARTIUM,
it,
SpyObject, proxy
} from 'angular2/test_lib';
import {isBlank} from 'angular2/src/facade/lang';
import {MapWrapper} from 'angular2/src/facade/collection';
import {ChangeDetection, ChangeDetectorDefinition} from 'angular2/change_detection';
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
import {Component, Directive} from 'angular2/src/core/annotations_impl/annotations';
import {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver';
import {DirectiveBinding} from 'angular2/src/core/compiler/element_injector';
import * as renderApi from 'angular2/src/render/api';
export function main() {
// TODO(tbosch): add missing tests
describe('ProtoViewFactory', () => {
var changeDetection;
var protoViewFactory;
var directiveResolver;
beforeEach( () => {
directiveResolver = new DirectiveResolver();
changeDetection = new ChangeDetectionSpy();
protoViewFactory = new ProtoViewFactory(changeDetection);
});
function bindDirective(type) {
return DirectiveBinding.createFromType(type, directiveResolver.resolve(type));
}
describe('getChangeDetectorDefinitions', () => {
it('should create a ChangeDetectorDefinition for the root render proto view', () => {
var renderPv = createRenderProtoView();
var defs = protoViewFactory.getChangeDetectorDefinitions(bindDirective(MainComponent).metadata,
renderPv, []);
expect(defs.length).toBe(1);
expect(defs[0].id).toEqual('MainComponent_comp_0');
});
});
describe('createAppProtoViews', () => {
it('should create an AppProtoView for the root render proto view', () => {
var renderPv = createRenderProtoView();
var pvs = protoViewFactory.createAppProtoViews(bindDirective(MainComponent),
renderPv, []);
expect(pvs.length).toBe(1);
expect(pvs[0].render).toBe(renderPv.render);
});
});
});
}
function createRenderProtoView(elementBinders = null, type:number = null) {
if (isBlank(type)) {
type = renderApi.ProtoViewDto.COMPONENT_VIEW_TYPE;
}
if (isBlank(elementBinders)) {
elementBinders = [];
}
return new renderApi.ProtoViewDto({
elementBinders: elementBinders,
type: type,
variableBindings: MapWrapper.create()
});
}
function createRenderComponentElementBinder(directiveIndex) {
return new renderApi.ElementBinder({
directives: [new renderApi.DirectiveBinder({
directiveIndex: directiveIndex
})]
});
}
function createRenderViewportElementBinder(nestedProtoView) {
return new renderApi.ElementBinder({
nestedProtoView: nestedProtoView
});
}
@proxy
@IMPLEMENTS(ChangeDetection)
class ChangeDetectionSpy extends SpyObject {
constructor(){super(ChangeDetection);}
noSuchMethod(m){return super.noSuchMethod(m)}
}
@Component({
selector: 'main-comp'
})
class MainComponent {}
@@ -37,7 +37,7 @@ export function main() {
}
function createProtoView() {
return new AppProtoView(null, null, null, null, null);
return new AppProtoView(null, null, null);
}
function createView() {
+6 -6
View File
@@ -24,7 +24,7 @@ import {ElementRef} from 'angular2/src/core/compiler/element_ref';
import {Renderer, RenderViewRef, RenderProtoViewRef, RenderViewContainerRef} from 'angular2/src/render/api';
import {ElementBinder} from 'angular2/src/core/compiler/element_binder';
import {DirectiveBinding, ElementInjector} from 'angular2/src/core/compiler/element_injector';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver';
import {Component} from 'angular2/src/core/annotations_impl/annotations';
import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
import {AppViewManagerUtils} from 'angular2/src/core/compiler/view_manager_utils';
@@ -38,7 +38,7 @@ export function main() {
var utils;
var viewPool;
var manager;
var reader;
var directiveResolver;
var createdViews;
var createdRenderViews;
@@ -55,8 +55,8 @@ export function main() {
}
function createDirectiveBinding(type) {
var meta = reader.read(type);
return DirectiveBinding.createFromType(meta.type, meta.annotation);
var annotation = directiveResolver.resolve(type);
return DirectiveBinding.createFromType(type, annotation);
}
function createEmptyElBinder() {
@@ -80,7 +80,7 @@ export function main() {
staticChildComponentCount++;
}
}
var res = new AppProtoView(new MockProtoViewRef(staticChildComponentCount), null, null, null, null);
var res = new AppProtoView(new MockProtoViewRef(staticChildComponentCount), null, null);
res.elementBinders = binders;
return res;
}
@@ -117,7 +117,7 @@ export function main() {
}
beforeEach( () => {
reader = new DirectiveMetadataReader();
directiveResolver = new DirectiveResolver();
renderer = new SpyRenderer();
utils = new SpyAppViewManagerUtils();
viewPool = new SpyAppViewPool();
@@ -24,7 +24,7 @@ import {AppProtoView, AppView} from 'angular2/src/core/compiler/view';
import {ChangeDetector} from 'angular2/change_detection';
import {ElementBinder} from 'angular2/src/core/compiler/element_binder';
import {DirectiveBinding, ElementInjector, PreBuiltObjects} from 'angular2/src/core/compiler/element_injector';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver';
import {Component} from 'angular2/src/core/annotations_impl/annotations';
import {AppViewManagerUtils} from 'angular2/src/core/compiler/view_manager_utils';
@@ -34,7 +34,7 @@ export function main() {
describe('AppViewManagerUtils', () => {
var metadataReader;
var directiveResolver;
var utils;
function createInjector() {
@@ -42,8 +42,8 @@ export function main() {
}
function createDirectiveBinding(type) {
var meta = metadataReader.read(type);
return DirectiveBinding.createFromType(meta.type, meta.annotation);
var annotation = directiveResolver.resolve(type);
return DirectiveBinding.createFromType(type, annotation);
}
function createEmptyElBinder() {
@@ -61,7 +61,7 @@ export function main() {
if (isBlank(binders)) {
binders = [];
}
var res = new AppProtoView(null, null, null, null, null);
var res = new AppProtoView(null, null, null);
res.elementBinders = binders;
return res;
}
@@ -100,8 +100,8 @@ export function main() {
}
beforeEach( () => {
metadataReader = new DirectiveMetadataReader();
utils = new AppViewManagerUtils(metadataReader);
directiveResolver = new DirectiveResolver();
utils = new AppViewManagerUtils(directiveResolver);
});
describe('hydrateDynamicComponentInElementInjector', () => {
+1 -1
View File
@@ -26,7 +26,7 @@ export function main() {
}
function createProtoView() {
return new AppProtoView(null, null, null, null, null);
return new AppProtoView(null, null, null);
}
function createView(pv) {
@@ -41,99 +41,126 @@ export function runCompilerCommonTests() {
return new DomCompiler(mockStepFactory, tplLoader);
}
it('should run the steps and build the AppProtoView of the root element', inject([AsyncTestCompleter], (async) => {
var compiler = createCompiler((parent, current, control) => {
current.inheritedProtoView.bindVariable('b', 'a');
});
compiler.compile(new ViewDefinition({
componentId: 'someComponent',
template: '<div></div>'
})).then( (protoView) => {
expect(protoView.variableBindings).toEqual(MapWrapper.createFromStringMap({
'a': 'b'
}));
async.done();
});
}));
describe('compile', () => {
it('should run the steps and build the proto view', inject([AsyncTestCompleter], (async) => {
var compiler = createCompiler((parent, current, control) => {
current.inheritedProtoView.bindVariable('b', 'a');
});
var dirMetadata = new DirectiveMetadata({id: 'id', selector: 'CUSTOM', type: DirectiveMetadata.COMPONENT_TYPE});
compiler.compileHost(dirMetadata).then( (protoView) => {
expect(DOM.tagName(resolveInternalDomProtoView(protoView.render).element)).toEqual('CUSTOM')
expect(mockStepFactory.viewDef.directives).toEqual([dirMetadata]);
expect(protoView.variableBindings).toEqual(MapWrapper.createFromStringMap({
'a': 'b'
}));
async.done();
});
}));
it('should use the inline template and compile in sync', inject([AsyncTestCompleter], (async) => {
var compiler = createCompiler(EMPTY_STEP);
compiler.compile(new ViewDefinition({
componentId: 'someId',
template: 'inline component'
})).then( (protoView) => {
expect(DOM.getInnerHTML(resolveInternalDomProtoView(protoView.render).element)).toEqual('inline component');
async.done();
});
}));
it('should load url templates', inject([AsyncTestCompleter], (async) => {
var urlData = MapWrapper.createFromStringMap({
'someUrl': 'url component'
});
var compiler = createCompiler(EMPTY_STEP, urlData);
compiler.compile(new ViewDefinition({
componentId: 'someId',
absUrl: 'someUrl'
})).then( (protoView) => {
expect(DOM.getInnerHTML(resolveInternalDomProtoView(protoView.render).element)).toEqual('url component');
async.done();
});
}));
it('should report loading errors', inject([AsyncTestCompleter], (async) => {
var compiler = createCompiler(EMPTY_STEP, MapWrapper.create());
PromiseWrapper.catchError(compiler.compile(new ViewDefinition({
componentId: 'someId',
absUrl: 'someUrl'
})), (e) => {
expect(e.message).toContain(`Failed to load the template "someId"`);
async.done();
});
}));
it('should wait for async subtasks to be resolved', inject([AsyncTestCompleter], (async) => {
var subTasksCompleted = false;
var completer = PromiseWrapper.completer();
var compiler = createCompiler( (parent, current, control) => {
ListWrapper.push(mockStepFactory.subTaskPromises, completer.promise.then((_) => {
subTasksCompleted = true;
}));
});
// It should always return a Promise because the subtask is async
var pvPromise = compiler.compile(new ViewDefinition({
componentId: 'someId',
template: 'some component'
it('should run the steps and build the AppProtoView of the root element', inject([AsyncTestCompleter], (async) => {
var compiler = createCompiler((parent, current, control) => {
current.inheritedProtoView.bindVariable('b', 'a');
});
compiler.compile(new ViewDefinition({
componentId: 'someComponent',
template: '<div></div>'
})).then( (protoView) => {
expect(protoView.variableBindings).toEqual(MapWrapper.createFromStringMap({
'a': 'b'
}));
async.done();
});
}));
expect(pvPromise).toBePromise();
expect(subTasksCompleted).toEqual(false);
// The Promise should resolve after the subtask is ready
completer.resolve(null);
pvPromise.then((protoView) => {
expect(subTasksCompleted).toEqual(true);
async.done();
});
}));
it('should run the steps and build the proto view', inject([AsyncTestCompleter], (async) => {
var compiler = createCompiler((parent, current, control) => {
current.inheritedProtoView.bindVariable('b', 'a');
});
var dirMetadata = new DirectiveMetadata({id: 'id', selector: 'CUSTOM', type: DirectiveMetadata.COMPONENT_TYPE});
compiler.compileHost(dirMetadata).then( (protoView) => {
expect(DOM.tagName(resolveInternalDomProtoView(protoView.render).element)).toEqual('CUSTOM')
expect(mockStepFactory.viewDef.directives).toEqual([dirMetadata]);
expect(protoView.variableBindings).toEqual(MapWrapper.createFromStringMap({
'a': 'b'
}));
async.done();
});
}));
it('should use the inline template and compile in sync', inject([AsyncTestCompleter], (async) => {
var compiler = createCompiler(EMPTY_STEP);
compiler.compile(new ViewDefinition({
componentId: 'someId',
template: 'inline component'
})).then( (protoView) => {
expect(DOM.getInnerHTML(resolveInternalDomProtoView(protoView.render).element)).toEqual('inline component');
async.done();
});
}));
it('should load url templates', inject([AsyncTestCompleter], (async) => {
var urlData = MapWrapper.createFromStringMap({
'someUrl': 'url component'
});
var compiler = createCompiler(EMPTY_STEP, urlData);
compiler.compile(new ViewDefinition({
componentId: 'someId',
absUrl: 'someUrl'
})).then( (protoView) => {
expect(DOM.getInnerHTML(resolveInternalDomProtoView(protoView.render).element)).toEqual('url component');
async.done();
});
}));
it('should report loading errors', inject([AsyncTestCompleter], (async) => {
var compiler = createCompiler(EMPTY_STEP, MapWrapper.create());
PromiseWrapper.catchError(compiler.compile(new ViewDefinition({
componentId: 'someId',
absUrl: 'someUrl'
})), (e) => {
expect(e.message).toContain(`Failed to load the template "someId"`);
async.done();
});
}));
it('should wait for async subtasks to be resolved', inject([AsyncTestCompleter], (async) => {
var subTasksCompleted = false;
var completer = PromiseWrapper.completer();
var compiler = createCompiler( (parent, current, control) => {
ListWrapper.push(mockStepFactory.subTaskPromises, completer.promise.then((_) => {
subTasksCompleted = true;
}));
});
// It should always return a Promise because the subtask is async
var pvPromise = compiler.compile(new ViewDefinition({
componentId: 'someId',
template: 'some component'
}));
expect(pvPromise).toBePromise();
expect(subTasksCompleted).toEqual(false);
// The Promise should resolve after the subtask is ready
completer.resolve(null);
pvPromise.then((protoView) => {
expect(subTasksCompleted).toEqual(true);
async.done();
});
}));
it('should return ProtoViews of type COMPONENT_VIEW_TYPE', inject([AsyncTestCompleter], (async) => {
var compiler = createCompiler(EMPTY_STEP);
compiler.compile(new ViewDefinition({
componentId: 'someId',
template: 'inline component'
})).then( (protoView) => {
expect(protoView.type).toEqual(ProtoViewDto.COMPONENT_VIEW_TYPE);
async.done();
});
}));
});
describe('compileHost', () => {
it('should return ProtoViews of type HOST_VIEW_TYPE', inject([AsyncTestCompleter], (async) => {
var compiler = createCompiler(EMPTY_STEP);
compiler.compileHost(someComponent).then( (protoView) => {
expect(protoView.type).toEqual(ProtoViewDto.HOST_VIEW_TYPE);
async.done();
});
}));
});
});
@@ -195,3 +222,9 @@ class FakeTemplateLoader extends TemplateLoader {
return PromiseWrapper.reject('Load failed');
}
}
var someComponent = new DirectiveMetadata({
selector: 'some-comp',
id: 'someComponent',
type: DirectiveMetadata.COMPONENT_TYPE
});
@@ -204,6 +204,14 @@ export function main() {
);
}).toThrowError(new RegExp('Only one component directive is allowed per element' ));
});
it('should sort the directives and store the component as the first directive', () => {
var results = process(
el('<some-comp some-decor></some-comp>')
);
expect(annotatedDirectives[results[0].directives[0].directiveIndex].id).toEqual('someComponent');
expect(annotatedDirectives[results[0].directives[1].directiveIndex].id).toEqual('someDirective');
});
});
});
}
@@ -239,6 +247,7 @@ var someComponent2 = new DirectiveMetadata({
var someDirective = new DirectiveMetadata({
selector: '[some-decor]',
id: 'someDirective',
type: DirectiveMetadata.DIRECTIVE_TYPE
});
@@ -303,4 +312,4 @@ var componentWithNonElementSelector = new DirectiveMetadata({
id: 'componentWithNonElementSelector',
selector: '[attr]',
type: DirectiveMetadata.COMPONENT_TYPE
});
});
+2 -1
View File
@@ -9,6 +9,7 @@ import {CompileStep} from 'angular2/src/render/dom/compiler/compile_step'
import {CompileControl} from 'angular2/src/render/dom/compiler/compile_control';
import {ProtoViewBuilder} from 'angular2/src/render/dom/view/proto_view_builder';
import {ProtoViewDto} from 'angular2/src/render/api';
export function main() {
describe('compile_pipeline', () => {
@@ -39,7 +40,7 @@ export function main() {
var element = el('<div><div><span viewroot><span></span></span></div></div>');
var pipeline = new CompilePipeline([new MockStep((parent, current, control) => {
if (isPresent(DOM.getAttribute(current.element, 'viewroot'))) {
current.inheritedProtoView = new ProtoViewBuilder(current.element);
current.inheritedProtoView = new ProtoViewBuilder(current.element, ProtoViewDto.EMBEDDED_VIEW_TYPE);
}
})]);
var results = pipeline.process(element);
@@ -3,6 +3,7 @@ import {MapWrapper} from 'angular2/src/facade/collection';
import {ViewSplitter} from 'angular2/src/render/dom/compiler/view_splitter';
import {CompilePipeline} from 'angular2/src/render/dom/compiler/compile_pipeline';
import {ProtoViewDto} from 'angular2/src/render/api';
import {DOM} from 'angular2/src/dom/dom_adapter';
import {Lexer, Parser} from 'angular2/change_detection';
@@ -56,6 +57,7 @@ export function main() {
var results = createPipeline().process(rootElement);
expect(results[2].inheritedProtoView).not.toBe(null);
expect(results[2].inheritedProtoView).toBe(results[1].inheritedElementBinder.nestedProtoView);
expect(results[2].inheritedProtoView.type).toBe(ProtoViewDto.EMBEDDED_VIEW_TYPE);
expect(DOM.getOuterHTML(results[2].inheritedProtoView.rootElement)).toEqual('<template>a</template>');
});
+2 -2
View File
@@ -29,7 +29,7 @@ import {DOM} from 'angular2/src/dom/dom_adapter';
import {SpyLocation} from 'angular2/src/mock/location_mock';
import {Location} from 'angular2/src/router/location';
import {RouteRegistry} from 'angular2/src/router/route_registry';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver';
var teamCmpCount;
@@ -41,7 +41,7 @@ export function main() {
beforeEachBindings(() => [
Pipeline,
RouteRegistry,
DirectiveMetadataReader,
DirectiveResolver,
bind(Location).toClass(SpyLocation),
bind(Router).toFactory((registry, pipeline, location) => {
return new RootRouter(registry, pipeline, location, MyComp);
+2 -2
View File
@@ -16,7 +16,7 @@ import {SpyLocation} from 'angular2/src/mock/location_mock'
import {Location} from 'angular2/src/router/location';
import {RouteRegistry} from 'angular2/src/router/route_registry';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver';
import {bind} from 'angular2/di';
@@ -28,7 +28,7 @@ export function main() {
beforeEachBindings(() => [
Pipeline,
RouteRegistry,
DirectiveMetadataReader,
DirectiveResolver,
bind(Location).toClass(SpyLocation),
bind(Router).toFactory((registry, pipeline, location) => {
return new RootRouter(registry, pipeline, location, AppCmp);