feat(change_detection): do not reparse AST when using generated detectors

This commit is contained in:
vsavkin
2015-08-19 11:26:45 -07:00
parent b986c54079
commit d2d0715568
31 changed files with 423 additions and 279 deletions
@@ -30,12 +30,12 @@ export function main() {
var map = {'id': (def) => proto};
var cd = new PreGeneratedChangeDetection(map);
expect(cd.createProtoChangeDetector(def)).toBe(proto)
expect(cd.getProtoChangeDetector('id', def)).toBe(proto)
});
it("should delegate to dynamic change detection otherwise", () => {
var cd = new PreGeneratedChangeDetection({});
expect(cd.createProtoChangeDetector(def)).toBeAnInstanceOf(DynamicProtoChangeDetector);
expect(cd.getProtoChangeDetector('id', def)).toBeAnInstanceOf(DynamicProtoChangeDetector);
});
});
}
@@ -1135,8 +1135,8 @@ class TestDispatcher implements ChangeDispatcher {
this.onAllChangesDoneCalled = true;
}
notifyOnBinding(binding, value) {
this.log.push(`${binding.propertyName}=${this._asString(value)}`);
notifyOnBinding(target, value) {
this.log.push(`${target.name}=${this._asString(value)}`);
this.loggedValues.push(value);
}
@@ -21,8 +21,7 @@ export function main() {
if (isBlank(argumentToPureFunction)) argumentToPureFunction = false;
return new ProtoRecord(mode, name, funcOrValue, args, null, contextIndex, directiveIndex,
selfIndex, null, null, lastInBinding, false, argumentToPureFunction,
false);
selfIndex, null, lastInBinding, false, argumentToPureFunction, false, 0);
}
describe("change detection - coalesce", () => {
@@ -64,7 +63,7 @@ export function main() {
[r("user", [], 0, 1, {lastInBinding: true}), r("user", [], 0, 2, {lastInBinding: true})]);
expect(rs[1]).toEqual(new ProtoRecord(RecordType.SELF, "self", null, [], null, 1, null, 2,
null, null, true, false, false, false));
null, true, false, false, false, 0));
});
it("should set referencedBySelf", () => {
@@ -19,7 +19,7 @@ export function main() {
it('should set argumentToPureFunction flag', inject([Parser], (p: Parser) => {
var builder = new ProtoRecordBuilder();
var ast = p.parseBinding("[1,2]", "location"); // collection literal is a pure function
builder.add(BindingRecord.createForElementProperty(ast, 0, "property"), []);
builder.add(BindingRecord.createForElementProperty(ast, 0, "property"), [], 0);
var isPureFunc = builder.records.map(r => r.argumentToPureFunction);
expect(isPureFunc).toEqual([true, true, false]);
@@ -29,7 +29,7 @@ export function main() {
inject([Parser], (p: Parser) => {
var builder = new ProtoRecordBuilder();
var ast = p.parseBinding("f(1,2)", "location");
builder.add(BindingRecord.createForElementProperty(ast, 0, "property"), []);
builder.add(BindingRecord.createForElementProperty(ast, 0, "property"), [], 0);
var isPureFunc = builder.records.map(r => r.argumentToPureFunction);
expect(isPureFunc).toEqual([false, false, false]);
@@ -20,8 +20,8 @@ export function main() {
if (isBlank(argumentToPureFunction)) argumentToPureFunction = false;
if (isBlank(referencedBySelf)) referencedBySelf = false;
return new ProtoRecord(mode, name, null, [], null, 0, directiveIndex, 0, null, null,
lastInBinding, false, argumentToPureFunction, referencedBySelf);
return new ProtoRecord(mode, name, null, [], null, 0, directiveIndex, 0, null, lastInBinding,
false, argumentToPureFunction, referencedBySelf, 0);
}
describe("ProtoRecord", () => {
@@ -980,7 +980,7 @@ export function main() {
});
it("should inject ChangeDetectorRef of the component's view into the component", () => {
var cd = new DynamicChangeDetector(null, null, null, [], [], []);
var cd = new DynamicChangeDetector(null, null, 0, [], [], null, [], [], []);
var view = <any>new DummyView();
var childView = new DummyView();
childView.changeDetector = cd;
@@ -993,7 +993,7 @@ export function main() {
});
it("should inject ChangeDetectorRef of the containing component into directives", () => {
var cd = new DynamicChangeDetector(null, null, null, [], [], []);
var cd = new DynamicChangeDetector(null, null, 0, [], [], null, [], [], []);
var view = <any>new DummyView();
view.changeDetector =cd;
var binding = DirectiveBinding.createFromType(DirectiveNeedsChangeDetectorRef, new DirectiveMetadata());
@@ -20,7 +20,8 @@ import {
ChangeDetection,
ChangeDetectorDefinition,
BindingRecord,
DirectiveIndex
DirectiveIndex,
Parser
} from 'angular2/src/change_detection/change_detection';
import {
BindingRecordsCreator,
@@ -177,39 +178,44 @@ export function main() {
beforeEach(() => { creator = new BindingRecordsCreator(); });
describe('getEventBindingRecords', () => {
it("should return template event records", () => {
var rec = creator.getEventBindingRecords(
[
new RenderElementBinder(
{eventBindings: [new EventBinding("a", null)], directives: []}),
new RenderElementBinder(
{eventBindings: [new EventBinding("b", null)], directives: []})
],
[]);
it("should return template event records", inject([Parser], (p: Parser) => {
var ast1 = p.parseAction("1", null);
var ast2 = p.parseAction("2", null);
expect(rec).toEqual([
BindingRecord.createForEvent(null, "a", 0),
BindingRecord.createForEvent(null, "b", 1)
]);
});
var rec = creator.getEventBindingRecords(
[
new RenderElementBinder(
{eventBindings: [new EventBinding("a", ast1)], directives: []}),
new RenderElementBinder(
{eventBindings: [new EventBinding("b", ast2)], directives: []})
],
[]);
it('should return host event records', () => {
var rec = creator.getEventBindingRecords(
[
new RenderElementBinder({
eventBindings: [],
directives: [
new DirectiveBinder(
{directiveIndex: 0, eventBindings: [new EventBinding("a", null)]})
]
})
],
[RenderDirectiveMetadata.create({id: 'some-id'})]);
expect(rec).toEqual([
BindingRecord.createForEvent(ast1, "a", 0),
BindingRecord.createForEvent(ast2, "b", 1)
]);
}));
expect(rec.length).toEqual(1);
expect(rec[0].eventName).toEqual("a");
expect(rec[0].implicitReceiver).toBeAnInstanceOf(DirectiveIndex);
});
it('should return host event records', inject([Parser], (p: Parser) => {
var ast1 = p.parseAction("1", null);
var rec = creator.getEventBindingRecords(
[
new RenderElementBinder({
eventBindings: [],
directives: [
new DirectiveBinder(
{directiveIndex: 0, eventBindings: [new EventBinding("a", ast1)]})
]
})
],
[RenderDirectiveMetadata.create({id: 'some-id'})]);
expect(rec.length).toEqual(1);
expect(rec[0].target.name).toEqual("a");
expect(rec[0].implicitReceiver).toBeAnInstanceOf(DirectiveIndex);
}));
});
});
});
@@ -253,6 +259,7 @@ function createRenderViewportElementBinder(nestedProtoView) {
class ChangeDetectionSpy extends SpyObject {
constructor() { super(ChangeDetection); }
noSuchMethod(m) { return super.noSuchMethod(m) }
get generateDetectors() { return true; }
}
@Component({selector: 'main-comp'})
@@ -90,6 +90,18 @@ export function main() {
it('should return null for an empty list',
() => { expect(ListWrapper.maximum([], x => x)).toEqual(null); });
});
describe('forEachWithIndex', () => {
var l;
beforeEach(() => { l = ["a", "b"]; });
it('should iterate over an array passing values and indices', () => {
var record = [];
ListWrapper.forEachWithIndex(l, (value, index) => record.push([value, index]));
expect(record).toEqual([["a", 0], ["b", 1]]);
});
});
});
describe('StringMapWrapper', () => {
@@ -13,12 +13,10 @@ void initReflector() {
if (_visited) return;
_visited = true;
_ngRef.reflector
..registerType(
MyComponent,
new _ngRef.ReflectionInfo(const [
const Component(selector: '[soup]'),
const View(template: 'Salad: {{myNum}} is awesome')
], const [], () => new MyComponent()))
..registerType(MyComponent, new _ngRef.ReflectionInfo(const [
const Component(selector: '[soup]'),
const View(template: 'Salad: {{myNum}} is awesome')
], const [], () => new MyComponent()))
..registerGetters({'myNum': (o) => o.myNum});
_gen.preGeneratedProtoDetectors['MyComponent_comp_0'] =
_MyComponent_ChangeDetector0.newProtoChangeDetector;
@@ -28,19 +26,23 @@ class _MyComponent_ChangeDetector0
extends _gen.AbstractChangeDetector<MyComponent> {
var myNum0, interpolate1;
_MyComponent_ChangeDetector0(dispatcher, protos, directiveRecords)
: super("MyComponent_comp_0", dispatcher, protos, directiveRecords,
'ALWAYS_CHECK') {
_MyComponent_ChangeDetector0(dispatcher) : super(
"MyComponent_comp_0", dispatcher, 2,
_MyComponent_ChangeDetector0.gen_propertyBindingTargets,
_MyComponent_ChangeDetector0.gen_directiveIndices, 'ALWAYS_CHECK') {
dehydrateDirectives(false);
}
void detectChangesInRecordsInternal(throwOnChange) {
var l_context = this.context, l_myNum0, c_myNum0, l_interpolate1;
var l_context = this.context,
l_myNum0,
c_myNum0,
l_interpolate1;
c_myNum0 = false;
var isChanged = false;
var changes = null;
this.firstProtoInCurrentBinding = 1;
this.propertyBindingIndex = 0;
l_myNum0 = l_context.myNum;
if (_gen.looseNotIdentical(l_myNum0, this.myNum0)) {
c_myNum0 = true;
@@ -75,9 +77,16 @@ class _MyComponent_ChangeDetector0
this.myNum0 = this.interpolate1 = _gen.ChangeDetectionUtil.uninitialized;
}
static var gen_propertyBindingTargets = [
_gen.ChangeDetectionUtil.bindingTarget("textNode", 0, null, null,
"Salad: {{myNum}} is awesome in MyComponent: <template>")
];
static var gen_directiveIndices = [];
static _gen.ProtoChangeDetector newProtoChangeDetector(
_gen.ChangeDetectorDefinition def) {
return new _gen.PregenProtoChangeDetector(
(a, b, c) => new _MyComponent_ChangeDetector0(a, b, c), def);
(a) => new _MyComponent_ChangeDetector0(a), def);
}
}
}