feat(change_detection): do not reparse AST when using generated detectors
This commit is contained in:
@@ -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', () => {
|
||||
|
||||
+22
-13
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user