refactor(change_detect): Move common fields to AbstractChangeDetector

Move fields common to Dynamic, Jit, and Pregen change detectors into the
`AbstractChangeDetector` superclass to save on codegen size and reduce
code duplication.

Update to #3248, closes #3243
This commit is contained in:
Tim Blasi 2015-07-28 12:43:41 -07:00
parent d894aa9101
commit 192cf9ddf5
10 changed files with 224 additions and 199 deletions

View File

@ -1,10 +1,12 @@
import {isPresent, BaseException} from 'angular2/src/facade/lang'; import {isPresent, BaseException} from 'angular2/src/facade/lang';
import {List, ListWrapper} from 'angular2/src/facade/collection'; import {List, ListWrapper} from 'angular2/src/facade/collection';
import {ChangeDetectorRef} from './change_detector_ref'; import {ChangeDetectorRef} from './change_detector_ref';
import {ChangeDetector} from './interfaces'; import {DirectiveRecord} from './directive_record';
import {ChangeDetector, ChangeDispatcher} from './interfaces';
import {ChangeDetectionError} from './exceptions'; import {ChangeDetectionError} from './exceptions';
import {ProtoRecord} from './proto_record'; import {ProtoRecord} from './proto_record';
import {Locals} from './parser/locals'; import {Locals} from './parser/locals';
import {Pipes} from './pipes/pipes';
import {CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED, ON_PUSH} from './constants'; import {CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED, ON_PUSH} from './constants';
class _Context { class _Context {
@ -13,14 +15,31 @@ class _Context {
public expression: any) {} public expression: any) {}
} }
export class AbstractChangeDetector implements ChangeDetector { export class AbstractChangeDetector<T> implements ChangeDetector {
lightDomChildren: List<any> = []; lightDomChildren: List<any> = [];
shadowDomChildren: List<any> = []; shadowDomChildren: List<any> = [];
parent: ChangeDetector; parent: ChangeDetector;
mode: string = null;
ref: ChangeDetectorRef; ref: ChangeDetectorRef;
constructor(public id: string, public dispatcher: any) { this.ref = new ChangeDetectorRef(this); } // The names of the below fields must be kept in sync with codegen_name_util.ts or
// change detection will fail.
alreadyChecked: any = false;
context: T;
currentProto: ProtoRecord = null;
directiveRecords: List<DirectiveRecord>;
dispatcher: ChangeDispatcher;
locals: Locals = null;
mode: string = null;
pipes: Pipes = null;
protos: List<ProtoRecord>;
constructor(public id: string, dispatcher: ChangeDispatcher, protos: List<ProtoRecord>,
directiveRecords: List<DirectiveRecord>) {
this.ref = new ChangeDetectorRef(this);
this.directiveRecords = directiveRecords;
this.dispatcher = dispatcher;
this.protos = protos;
}
addChild(cd: ChangeDetector): void { addChild(cd: ChangeDetector): void {
this.lightDomChildren.push(cd); this.lightDomChildren.push(cd);
@ -58,7 +77,7 @@ export class AbstractChangeDetector implements ChangeDetector {
detectChangesInRecords(throwOnChange: boolean): void {} detectChangesInRecords(throwOnChange: boolean): void {}
hydrate(context: any, locals: Locals, directives: any, pipes: any): void {} hydrate(context: T, locals: Locals, directives: any, pipes: any): void {}
hydrateDirectives(directives: any): void {} hydrateDirectives(directives: any): void {}

View File

@ -42,7 +42,8 @@ export {
ChangeDetector, ChangeDetector,
ChangeDispatcher, ChangeDispatcher,
ChangeDetection, ChangeDetection,
ChangeDetectorDefinition ChangeDetectorDefinition,
DebugContext
} from './interfaces'; } from './interfaces';
export {CHECK_ONCE, CHECK_ALWAYS, DETACHED, CHECKED, ON_PUSH, DEFAULT} from './constants'; export {CHECK_ONCE, CHECK_ALWAYS, DETACHED, CHECKED, ON_PUSH, DEFAULT} from './constants';
export {DynamicProtoChangeDetector} from './proto_change_detector'; export {DynamicProtoChangeDetector} from './proto_change_detector';

View File

@ -6,7 +6,7 @@ import {ChangeDetectionUtil} from './change_detection_util';
import {DirectiveIndex, DirectiveRecord} from './directive_record'; import {DirectiveIndex, DirectiveRecord} from './directive_record';
import {ProtoRecord, RecordType} from './proto_record'; import {ProtoRecord, RecordType} from './proto_record';
import {CodegenNameUtil, sanitizeName} from './codegen_name_util'; import {CONTEXT_INDEX, CodegenNameUtil, sanitizeName} from './codegen_name_util';
/** /**
@ -20,16 +20,8 @@ import {CodegenNameUtil, sanitizeName} from './codegen_name_util';
*/ */
var ABSTRACT_CHANGE_DETECTOR = "AbstractChangeDetector"; var ABSTRACT_CHANGE_DETECTOR = "AbstractChangeDetector";
var UTIL = "ChangeDetectionUtil"; var UTIL = "ChangeDetectionUtil";
var DISPATCHER_ACCESSOR = "this.dispatcher";
var PIPES_ACCESSOR = "this.pipes";
var PROTOS_ACCESSOR = "this.protos";
var DIRECTIVES_ACCESSOR = "this.directiveRecords";
var IS_CHANGED_LOCAL = "isChanged"; var IS_CHANGED_LOCAL = "isChanged";
var CHANGES_LOCAL = "changes"; var CHANGES_LOCAL = "changes";
var LOCALS_ACCESSOR = "this.locals";
var MODE_ACCESSOR = "this.mode";
var CURRENT_PROTO = "this.currentProto";
var ALREADY_CHECKED_ACCESSOR = "this.alreadyChecked";
export class ChangeDetectorJITGenerator { export class ChangeDetectorJITGenerator {
_names: CodegenNameUtil; _names: CodegenNameUtil;
@ -38,20 +30,14 @@ export class ChangeDetectorJITGenerator {
constructor(public id: string, public changeDetectionStrategy: string, constructor(public id: string, public changeDetectionStrategy: string,
public records: List<ProtoRecord>, public directiveRecords: List<any>, public records: List<ProtoRecord>, public directiveRecords: List<any>,
private generateCheckNoChanges: boolean) { private generateCheckNoChanges: boolean) {
this._names = new CodegenNameUtil(this.records, this.directiveRecords, 'this._', UTIL); this._names = new CodegenNameUtil(this.records, this.directiveRecords, UTIL);
this._typeName = sanitizeName(`ChangeDetector_${this.id}`); this._typeName = sanitizeName(`ChangeDetector_${this.id}`);
} }
generate(): Function { generate(): Function {
var classDefinition = ` var classDefinition = `
var ${this._typeName} = function ${this._typeName}(dispatcher, protos, directiveRecords) { var ${this._typeName} = function ${this._typeName}(dispatcher, protos, directiveRecords) {
${ABSTRACT_CHANGE_DETECTOR}.call(this, ${JSON.stringify(this.id)}, dispatcher); ${ABSTRACT_CHANGE_DETECTOR}.call(this, ${JSON.stringify(this.id)}, dispatcher, protos, directiveRecords);
${PROTOS_ACCESSOR} = protos;
${DIRECTIVES_ACCESSOR} = directiveRecords;
${LOCALS_ACCESSOR} = null;
${CURRENT_PROTO} = null;
${PIPES_ACCESSOR} = null;
${ALREADY_CHECKED_ACCESSOR} = false;
this.dehydrateDirectives(false); this.dehydrateDirectives(false);
} }
@ -64,22 +50,20 @@ export class ChangeDetectorJITGenerator {
try { try {
this.__detectChangesInRecords(throwOnChange); this.__detectChangesInRecords(throwOnChange);
} catch (e) { } catch (e) {
this.throwError(${CURRENT_PROTO}, e, e.stack); this.throwError(${this._names.getCurrentProtoName()}, e, e.stack);
} }
} }
${this._typeName}.prototype.__detectChangesInRecords = function(throwOnChange) { ${this._typeName}.prototype.__detectChangesInRecords = function(throwOnChange) {
${CURRENT_PROTO} = null; ${this._names.getCurrentProtoName()} = null;
${this._names.genInitLocals()} ${this._names.genInitLocals()}
var ${IS_CHANGED_LOCAL} = false; var ${IS_CHANGED_LOCAL} = false;
var ${CHANGES_LOCAL} = null; var ${CHANGES_LOCAL} = null;
context = ${this._names.getContextName()};
${this.records.map((r) => this._genRecord(r)).join("\n")} ${this.records.map((r) => this._genRecord(r)).join("\n")}
${ALREADY_CHECKED_ACCESSOR} = true; ${this._names.getAlreadyCheckedName()} = true;
} }
${this._genCheckNoChanges()} ${this._genCheckNoChanges()}
@ -89,26 +73,27 @@ export class ChangeDetectorJITGenerator {
} }
${this._typeName}.prototype.hydrate = function(context, locals, directives, pipes) { ${this._typeName}.prototype.hydrate = function(context, locals, directives, pipes) {
${MODE_ACCESSOR} = "${ChangeDetectionUtil.changeDetectionMode(this.changeDetectionStrategy)}"; ${this._names.getModeName()} =
${this._names.getContextName()} = context; "${ChangeDetectionUtil.changeDetectionMode(this.changeDetectionStrategy)}";
${LOCALS_ACCESSOR} = locals; ${this._names.getFieldName(CONTEXT_INDEX)} = context;
${this._names.getLocalsAccessorName()} = locals;
this.hydrateDirectives(directives); this.hydrateDirectives(directives);
${PIPES_ACCESSOR} = pipes; ${this._names.getPipesAccessorName()} = pipes;
${ALREADY_CHECKED_ACCESSOR} = false; ${this._names.getAlreadyCheckedName()} = false;
} }
${this._maybeGenHydrateDirectives()} ${this._maybeGenHydrateDirectives()}
${this._typeName}.prototype.dehydrate = function() { ${this._typeName}.prototype.dehydrate = function() {
this.dehydrateDirectives(true); this.dehydrateDirectives(true);
${LOCALS_ACCESSOR} = null; ${this._names.getLocalsAccessorName()} = null;
${PIPES_ACCESSOR} = null; ${this._names.getPipesAccessorName()} = null;
} }
${this._maybeGenDehydrateDirectives()} ${this._maybeGenDehydrateDirectives()}
${this._typeName}.prototype.hydrated = function() { ${this._typeName}.prototype.hydrated = function() {
return ${this._names.getContextName()} !== null; return ${this._names.getFieldName(CONTEXT_INDEX)} !== null;
} }
return function(dispatcher) { return function(dispatcher) {
@ -148,8 +133,8 @@ export class ChangeDetectorJITGenerator {
var directiveFieldNames = this._names.getAllDirectiveNames(); var directiveFieldNames = this._names.getAllDirectiveNames();
var lines = ListWrapper.createFixedSize(directiveFieldNames.length); var lines = ListWrapper.createFixedSize(directiveFieldNames.length);
for (var i = 0, iLen = directiveFieldNames.length; i < iLen; ++i) { for (var i = 0, iLen = directiveFieldNames.length; i < iLen; ++i) {
lines[i] = lines[i] = `${directiveFieldNames[i]} = directives.getDirectiveFor(
`${directiveFieldNames[i]} = directives.getDirectiveFor(${DIRECTIVES_ACCESSOR}[${i}].directiveIndex);`; ${this._names.getDirectivesAccessorName()}[${i}].directiveIndex);`;
} }
return lines.join('\n'); return lines.join('\n');
} }
@ -158,8 +143,8 @@ export class ChangeDetectorJITGenerator {
var detectorFieldNames = this._names.getAllDetectorNames(); var detectorFieldNames = this._names.getAllDetectorNames();
var lines = ListWrapper.createFixedSize(detectorFieldNames.length); var lines = ListWrapper.createFixedSize(detectorFieldNames.length);
for (var i = 0, iLen = detectorFieldNames.length; i < iLen; ++i) { for (var i = 0, iLen = detectorFieldNames.length; i < iLen; ++i) {
lines[i] = `${detectorFieldNames[i]} = lines[i] = `${detectorFieldNames[i]} = directives.getDetectorFor(
directives.getDetectorFor(${DIRECTIVES_ACCESSOR}[${i}].directiveIndex);`; ${this._names.getDirectivesAccessorName()}[${i}].directiveIndex);`;
} }
return lines.join('\n'); return lines.join('\n');
} }
@ -179,7 +164,7 @@ export class ChangeDetectorJITGenerator {
var directiveNotifications = notifications.join("\n"); var directiveNotifications = notifications.join("\n");
return ` return `
this.dispatcher.notifyOnAllChangesDone(); ${this._names.getDispatcherName()}.notifyOnAllChangesDone();
${directiveNotifications} ${directiveNotifications}
`; `;
} }
@ -223,12 +208,12 @@ export class ChangeDetectorJITGenerator {
var pipeType = r.name; var pipeType = r.name;
return ` return `
${CURRENT_PROTO} = ${PROTOS_ACCESSOR}[${protoIndex}]; ${this._names.getCurrentProtoName()} = ${this._names.getProtosName()}[${protoIndex}];
if (${pipe} === ${UTIL}.uninitialized) { if (${pipe} === ${UTIL}.uninitialized) {
${pipe} = ${PIPES_ACCESSOR}.get('${pipeType}', ${context}, ${cdRef}); ${pipe} = ${this._names.getPipesAccessorName()}.get('${pipeType}', ${context}, ${cdRef});
} else if (!${pipe}.supports(${context})) { } else if (!${pipe}.supports(${context})) {
${pipe}.onDestroy(); ${pipe}.onDestroy();
${pipe} = ${PIPES_ACCESSOR}.get('${pipeType}', ${context}, ${cdRef}); ${pipe} = ${this._names.getPipesAccessorName()}.get('${pipeType}', ${context}, ${cdRef});
} }
${newValue} = ${pipe}.transform(${context}, [${argString}]); ${newValue} = ${pipe}.transform(${context}, [${argString}]);
@ -248,7 +233,7 @@ export class ChangeDetectorJITGenerator {
var protoIndex = r.selfIndex - 1; var protoIndex = r.selfIndex - 1;
var check = ` var check = `
${CURRENT_PROTO} = ${PROTOS_ACCESSOR}[${protoIndex}]; ${this._names.getCurrentProtoName()} = ${this._names.getProtosName()}[${protoIndex}];
${this._genUpdateCurrentValue(r)} ${this._genUpdateCurrentValue(r)}
if (${newValue} !== ${oldValue}) { if (${newValue} !== ${oldValue}) {
${this._names.getChangeName(r.selfIndex)} = true; ${this._names.getChangeName(r.selfIndex)} = true;
@ -291,7 +276,7 @@ export class ChangeDetectorJITGenerator {
break; break;
case RecordType.LOCAL: case RecordType.LOCAL:
rhs = `${LOCALS_ACCESSOR}.get('${r.name}')`; rhs = `${this._names.getLocalsAccessorName()}.get('${r.name}')`;
break; break;
case RecordType.INVOKE_METHOD: case RecordType.INVOKE_METHOD:
@ -354,7 +339,8 @@ export class ChangeDetectorJITGenerator {
} else { } else {
return ` return `
${this._genThrowOnChangeCheck(oldValue, newValue)} ${this._genThrowOnChangeCheck(oldValue, newValue)}
${DISPATCHER_ACCESSOR}.notifyOnBinding(${CURRENT_PROTO}.bindingRecord, ${newValue}); ${this._names.getDispatcherName()}.notifyOnBinding(
${this._names.getCurrentProtoName()}.bindingRecord, ${newValue});
`; `;
} }
} }
@ -363,7 +349,7 @@ export class ChangeDetectorJITGenerator {
if (this.generateCheckNoChanges) { if (this.generateCheckNoChanges) {
return ` return `
if(throwOnChange) { if(throwOnChange) {
${UTIL}.throwOnChange(${CURRENT_PROTO}, ${UTIL}.simpleChange(${oldValue}, ${newValue})); ${UTIL}.throwOnChange(${this._names.getCurrentProtoName()}, ${UTIL}.simpleChange(${oldValue}, ${newValue}));
} }
`; `;
} else { } else {
@ -385,7 +371,7 @@ export class ChangeDetectorJITGenerator {
if (!r.bindingRecord.callOnChange()) return ""; if (!r.bindingRecord.callOnChange()) return "";
return ` return `
${CHANGES_LOCAL} = ${UTIL}.addChange( ${CHANGES_LOCAL} = ${UTIL}.addChange(
${CHANGES_LOCAL}, ${CURRENT_PROTO}.bindingRecord.propertyName, ${CHANGES_LOCAL}, ${this._names.getCurrentProtoName()}.bindingRecord.propertyName,
${UTIL}.simpleChange(${oldValue}, ${newValue})); ${UTIL}.simpleChange(${oldValue}, ${newValue}));
`; `;
} }
@ -406,7 +392,7 @@ export class ChangeDetectorJITGenerator {
_genOnInit(r: ProtoRecord): string { _genOnInit(r: ProtoRecord): string {
var br = r.bindingRecord; var br = r.bindingRecord;
return `if (!throwOnChange && !${ALREADY_CHECKED_ACCESSOR}) ${this._names.getDirectiveName(br.directiveRecord.directiveIndex)}.onInit();`; return `if (!throwOnChange && !${this._names.getAlreadyCheckedName()}) ${this._names.getDirectiveName(br.directiveRecord.directiveIndex)}.onInit();`;
} }
_genOnChange(r: ProtoRecord): string { _genOnChange(r: ProtoRecord): string {

View File

@ -5,8 +5,21 @@ import {DirectiveIndex} from './directive_record';
import {ProtoRecord} from './proto_record'; import {ProtoRecord} from './proto_record';
// `context` is always the first field. // The names of these fields must be kept in sync with abstract_change_detector.ts or change
var _CONTEXT_IDX = 0; // detection will fail.
const _ALREADY_CHECKED_ACCESSOR = "alreadyChecked";
const _CONTEXT_ACCESSOR = "context";
const _CURRENT_PROTO = "currentProto";
const _DIRECTIVES_ACCESSOR = "directiveRecords";
const _DISPATCHER_ACCESSOR = "dispatcher";
const _LOCALS_ACCESSOR = "locals";
const _MODE_ACCESSOR = "mode";
const _PIPES_ACCESSOR = "pipes";
const _PROTOS_ACCESSOR = "protos";
// `context` is always first.
export const CONTEXT_INDEX = 0;
const _FIELD_PREFIX = 'this.';
var _whiteSpaceRegExp = RegExpWrapper.create("\\W", "g"); var _whiteSpaceRegExp = RegExpWrapper.create("\\W", "g");
@ -29,18 +42,34 @@ export class CodegenNameUtil {
*/ */
_sanitizedNames: List<string>; _sanitizedNames: List<string>;
constructor(public records: List<ProtoRecord>, public directiveRecords: List<any>, constructor(private records: List<ProtoRecord>, private directiveRecords: List<any>,
public fieldPrefix: string, public utilName: string) { private utilName: string) {
this._sanitizedNames = ListWrapper.createFixedSize(this.records.length + 1); this._sanitizedNames = ListWrapper.createFixedSize(this.records.length + 1);
this._sanitizedNames[_CONTEXT_IDX] = 'context'; this._sanitizedNames[CONTEXT_INDEX] = _CONTEXT_ACCESSOR;
for (var i = 0, iLen = this.records.length; i < iLen; ++i) { for (var i = 0, iLen = this.records.length; i < iLen; ++i) {
this._sanitizedNames[i + 1] = sanitizeName(`${this.records[i].name}${i}`); this._sanitizedNames[i + 1] = sanitizeName(`${this.records[i].name}${i}`);
} }
} }
getContextName(): string { return this.getFieldName(_CONTEXT_IDX); } _addFieldPrefix(name: string): string { return `${_FIELD_PREFIX}${name}`; }
getLocalName(idx: int): string { return this._sanitizedNames[idx]; } getDispatcherName(): string { return this._addFieldPrefix(_DISPATCHER_ACCESSOR); }
getPipesAccessorName(): string { return this._addFieldPrefix(_PIPES_ACCESSOR); }
getProtosName(): string { return this._addFieldPrefix(_PROTOS_ACCESSOR); }
getDirectivesAccessorName(): string { return this._addFieldPrefix(_DIRECTIVES_ACCESSOR); }
getLocalsAccessorName(): string { return this._addFieldPrefix(_LOCALS_ACCESSOR); }
getAlreadyCheckedName(): string { return this._addFieldPrefix(_ALREADY_CHECKED_ACCESSOR); }
getModeName(): string { return this._addFieldPrefix(_MODE_ACCESSOR); }
getCurrentProtoName(): string { return this._addFieldPrefix(_CURRENT_PROTO); }
getLocalName(idx: int): string { return `l_${this._sanitizedNames[idx]}`; }
getChangeName(idx: int): string { return `c_${this._sanitizedNames[idx]}`; } getChangeName(idx: int): string { return `c_${this._sanitizedNames[idx]}`; }
@ -51,17 +80,22 @@ export class CodegenNameUtil {
var declarations = []; var declarations = [];
var assignments = []; var assignments = [];
for (var i = 0, iLen = this.getFieldCount(); i < iLen; ++i) { for (var i = 0, iLen = this.getFieldCount(); i < iLen; ++i) {
var changeName = this.getChangeName(i); if (i == CONTEXT_INDEX) {
declarations.push(`${this.getLocalName(i)},${changeName}`); declarations.push(`${this.getLocalName(i)} = ${this.getFieldName(i)}`);
assignments.push(changeName); } else {
var changeName = this.getChangeName(i);
declarations.push(`${this.getLocalName(i)},${changeName}`);
assignments.push(changeName);
}
} }
return `var ${ListWrapper.join(declarations, ',')};` + var assignmentsCode =
`${ListWrapper.join(assignments, '=')} = false;`; ListWrapper.isEmpty(assignments) ? '' : `${ListWrapper.join(assignments, '=')} = false;`;
return `var ${ListWrapper.join(declarations, ',')};${assignmentsCode}`;
} }
getFieldCount(): int { return this._sanitizedNames.length; } getFieldCount(): int { return this._sanitizedNames.length; }
getFieldName(idx: int): string { return `${this.fieldPrefix}${this._sanitizedNames[idx]}`; } getFieldName(idx: int): string { return this._addFieldPrefix(this._sanitizedNames[idx]); }
getAllFieldNames(): List<string> { getAllFieldNames(): List<string> {
var fieldList = []; var fieldList = [];
@ -84,27 +118,17 @@ export class CodegenNameUtil {
return fieldList; return fieldList;
} }
/**
* Generates a statement which declares all fields.
* This is only necessary for Dart change detectors.
*/
genDeclareFields(): string {
var fields = this.getAllFieldNames();
ListWrapper.removeAt(fields, _CONTEXT_IDX);
return ListWrapper.isEmpty(fields) ? '' : `var ${ListWrapper.join(fields, ', ')};`;
}
/** /**
* Generates statements which clear all fields so that the change detector is dehydrated. * Generates statements which clear all fields so that the change detector is dehydrated.
*/ */
genDehydrateFields(): string { genDehydrateFields(): string {
var fields = this.getAllFieldNames(); var fields = this.getAllFieldNames();
ListWrapper.removeAt(fields, _CONTEXT_IDX); ListWrapper.removeAt(fields, CONTEXT_INDEX);
if (!ListWrapper.isEmpty(fields)) { if (!ListWrapper.isEmpty(fields)) {
// At least one assignment. // At least one assignment.
fields.push(`${this.utilName}.uninitialized;`); fields.push(`${this.utilName}.uninitialized;`);
} }
return `${this.getContextName()} = null; ${ListWrapper.join(fields, ' = ')}`; return `${this.getFieldName(CONTEXT_INDEX)} = null; ${ListWrapper.join(fields, ' = ')}`;
} }
/** /**
@ -116,13 +140,17 @@ export class CodegenNameUtil {
}), (r) => { return `${this.getPipeName(r.selfIndex)}.onDestroy();`; }), '\n'); }), (r) => { return `${this.getPipeName(r.selfIndex)}.onDestroy();`; }), '\n');
} }
getPipeName(idx: int): string { return `${this.fieldPrefix}${this._sanitizedNames[idx]}_pipe`; } getPipeName(idx: int): string {
return this._addFieldPrefix(`${this._sanitizedNames[idx]}_pipe`);
}
getAllDirectiveNames(): List<string> { getAllDirectiveNames(): List<string> {
return ListWrapper.map(this.directiveRecords, d => this.getDirectiveName(d.directiveIndex)); return ListWrapper.map(this.directiveRecords, d => this.getDirectiveName(d.directiveIndex));
} }
getDirectiveName(d: DirectiveIndex): string { return `${this.fieldPrefix}directive_${d.name}`; } getDirectiveName(d: DirectiveIndex): string {
return this._addFieldPrefix(`directive_${d.name}`);
}
getAllDetectorNames(): List<string> { getAllDetectorNames(): List<string> {
return ListWrapper.map( return ListWrapper.map(
@ -130,5 +158,5 @@ export class CodegenNameUtil {
(d) => this.getDetectorName(d.directiveIndex)); (d) => this.getDetectorName(d.directiveIndex));
} }
getDetectorName(d: DirectiveIndex): string { return `${this.fieldPrefix}detector_${d.name}`; } getDetectorName(d: DirectiveIndex): string { return this._addFieldPrefix(`detector_${d.name}`); }
} }

View File

@ -10,19 +10,16 @@ import {ChangeDetectionUtil, SimpleChange} from './change_detection_util';
import {ProtoRecord, RecordType} from './proto_record'; import {ProtoRecord, RecordType} from './proto_record';
export class DynamicChangeDetector extends AbstractChangeDetector { export class DynamicChangeDetector extends AbstractChangeDetector<any> {
locals: Locals = null;
values: List<any>; values: List<any>;
changes: List<any>; changes: List<any>;
localPipes: List<any>; localPipes: List<any>;
prevContexts: List<any>; prevContexts: List<any>;
directives: any = null; directives: any = null;
alreadyChecked: boolean = false;
private pipes: Pipes = null;
constructor(id: string, private changeControlStrategy: string, dispatcher: any, constructor(id: string, private changeControlStrategy: string, dispatcher: any,
private protos: List<ProtoRecord>, private directiveRecords: List<any>) { protos: List<ProtoRecord>, directiveRecords: List<any>) {
super(id, dispatcher); super(id, dispatcher, protos, directiveRecords);
this.values = ListWrapper.createFixedSize(protos.length + 1); this.values = ListWrapper.createFixedSize(protos.length + 1);
this.localPipes = ListWrapper.createFixedSize(protos.length + 1); this.localPipes = ListWrapper.createFixedSize(protos.length + 1);
this.prevContexts = ListWrapper.createFixedSize(protos.length + 1); this.prevContexts = ListWrapper.createFixedSize(protos.length + 1);

View File

@ -2,7 +2,7 @@ import {List} from 'angular2/src/facade/collection';
import {CONST} from 'angular2/src/facade/lang'; import {CONST} from 'angular2/src/facade/lang';
import {Locals} from './parser/locals'; import {Locals} from './parser/locals';
import {BindingRecord} from './binding_record'; import {BindingRecord} from './binding_record';
import {DirectiveRecord} from './directive_record'; import {DirectiveIndex, DirectiveRecord} from './directive_record';
/** /**
* Interface used by Angular to control the change detection strategy for an application. * Interface used by Angular to control the change detection strategy for an application.
@ -36,7 +36,13 @@ export class ChangeDetection {
} }
} }
export class DebugContext {
constructor(public element: any, public componentElement: any, public directive: any,
public context: any, public locals: any, public injector: any) {}
}
export interface ChangeDispatcher { export interface ChangeDispatcher {
getDebugContext(elementIndex: number, directiveIndex: DirectiveIndex): DebugContext;
notifyOnBinding(bindingRecord: BindingRecord, value: any): void; notifyOnBinding(bindingRecord: BindingRecord, value: any): void;
notifyOnAllChangesDone(): void; notifyOnAllChangesDone(): void;
} }
@ -58,7 +64,7 @@ export interface ChangeDetector {
checkNoChanges(): void; checkNoChanges(): void;
} }
export interface ProtoChangeDetector { instantiate(dispatcher: any): ChangeDetector; } export interface ProtoChangeDetector { instantiate(dispatcher: ChangeDispatcher): ChangeDetector; }
export class ChangeDetectorDefinition { export class ChangeDetectorDefinition {
constructor(public id: string, public strategy: string, public variableNames: List<string>, constructor(public id: string, public strategy: string, public variableNames: List<string>,

View File

@ -8,15 +8,16 @@ import {
} from 'angular2/src/facade/collection'; } from 'angular2/src/facade/collection';
import { import {
AST, AST,
Locals,
ChangeDispatcher,
ProtoChangeDetector,
ChangeDetector,
BindingRecord, BindingRecord,
DirectiveRecord, ChangeDetector,
ChangeDetectorRef,
ChangeDispatcher,
DirectiveIndex, DirectiveIndex,
ChangeDetectorRef DirectiveRecord,
Locals,
ProtoChangeDetector
} from 'angular2/src/change_detection/change_detection'; } from 'angular2/src/change_detection/change_detection';
import {DebugContext} from 'angular2/src/change_detection/interfaces';
import { import {
ProtoElementInjector, ProtoElementInjector,
@ -31,6 +32,8 @@ import {RenderEventDispatcher} from 'angular2/src/render/api';
import {ViewRef, ProtoViewRef, internalView} from './view_ref'; import {ViewRef, ProtoViewRef, internalView} from './view_ref';
import {ElementRef} from './element_ref'; import {ElementRef} from './element_ref';
export {DebugContext} from 'angular2/src/change_detection/interfaces';
export class AppProtoViewMergeMapping { export class AppProtoViewMergeMapping {
renderProtoViewRef: renderApi.RenderProtoViewRef; renderProtoViewRef: renderApi.RenderProtoViewRef;
renderFragmentCount: number; renderFragmentCount: number;
@ -301,11 +304,6 @@ function _localsToStringMap(locals: Locals): StringMap<string, any> {
return res; return res;
} }
export class DebugContext {
constructor(public element: any, public componentElement: any, public directive: any,
public context: any, public locals: any, public injector: any) {}
}
/** /**
* Error context included when an event handler throws an exception. * Error context included when an event handler throws an exception.
*/ */

View File

@ -82,7 +82,7 @@ class _CodegenState {
this._generateCheckNoChanges) this._generateCheckNoChanges)
: _records = records, : _records = records,
_directiveRecords = directiveRecords, _directiveRecords = directiveRecords,
_names = new CodegenNameUtil(records, directiveRecords, '_', _UTIL), _names = new CodegenNameUtil(records, directiveRecords, _UTIL),
_changeDetectionMode = ChangeDetectionUtil _changeDetectionMode = ChangeDetectionUtil
.changeDetectionMode(changeDetectionStrategy); .changeDetectionMode(changeDetectionStrategy);
@ -99,22 +99,12 @@ class _CodegenState {
void _writeToBuf(StringBuffer buf) { void _writeToBuf(StringBuffer buf) {
buf.write('''\n buf.write('''\n
class $_changeDetectorTypeName extends $_BASE_CLASS { class $_changeDetectorTypeName extends $_BASE_CLASS<$_contextTypeName> {
$_GEN_PREFIX.Pipes $_PIPES_ACCESSOR; ${_genDeclareFields()}
final $_GEN_PREFIX.List<$_GEN_PREFIX.ProtoRecord> $_PROTOS_ACCESSOR;
final $_GEN_PREFIX.List<$_GEN_PREFIX.DirectiveRecord>
$_DIRECTIVES_ACCESSOR;
dynamic $_LOCALS_ACCESSOR = null;
dynamic $_ALREADY_CHECKED_ACCESSOR = false;
dynamic $_CURRENT_PROTO = null;
$_contextTypeName ${_names.getContextName()};
${_names.genDeclareFields()}
$_changeDetectorTypeName( $_changeDetectorTypeName(dispatcher, protos, directiveRecords)
dynamic $_DISPATCHER_ACCESSOR, : super(${_encodeValue(_changeDetectorDefId)},
this.$_PROTOS_ACCESSOR, dispatcher, protos, directiveRecords) {
this.$_DIRECTIVES_ACCESSOR)
: super(${_encodeValue(_changeDetectorDefId)}, $_DISPATCHER_ACCESSOR) {
dehydrateDirectives(false); dehydrateDirectives(false);
} }
@ -125,20 +115,20 @@ class _CodegenState {
try { try {
__detectChangesInRecords(throwOnChange); __detectChangesInRecords(throwOnChange);
} catch (e, s) { } catch (e, s) {
throwError($_CURRENT_PROTO, e, s); throwError(${_names.getCurrentProtoName()}, e, s);
} }
} }
void __detectChangesInRecords(throwOnChange) { void __detectChangesInRecords(throwOnChange) {
${_names.getCurrentProtoName()} = null;
${_names.genInitLocals()} ${_names.genInitLocals()}
var $_IS_CHANGED_LOCAL = false; var $_IS_CHANGED_LOCAL = false;
$_CURRENT_PROTO = null;
var $_CHANGES_LOCAL = null; var $_CHANGES_LOCAL = null;
context = ${_names.getContextName()};
${_records.map(_genRecord).join('')} ${_records.map(_genRecord).join('')}
$_ALREADY_CHECKED_ACCESSOR = true; ${_names.getAlreadyCheckedName()} = true;
} }
${_genCheckNoChanges()} ${_genCheckNoChanges()}
@ -147,26 +137,27 @@ class _CodegenState {
${_getCallOnAllChangesDoneBody()} ${_getCallOnAllChangesDoneBody()}
} }
void hydrate($_contextTypeName context, locals, directives, pipes) { void hydrate(
$_MODE_ACCESSOR = '$_changeDetectionMode'; $_contextTypeName context, locals, directives, pipes) {
${_names.getContextName()} = context; ${_names.getModeName()} = '$_changeDetectionMode';
$_LOCALS_ACCESSOR = locals; ${_names.getFieldName(CONTEXT_INDEX)} = context;
${_names.getLocalsAccessorName()} = locals;
hydrateDirectives(directives); hydrateDirectives(directives);
$_ALREADY_CHECKED_ACCESSOR = false; ${_names.getAlreadyCheckedName()} = false;
$_PIPES_ACCESSOR = pipes; ${_names.getPipesAccessorName()} = pipes;
} }
${_maybeGenHydrateDirectives()} ${_maybeGenHydrateDirectives()}
void dehydrate() { void dehydrate() {
dehydrateDirectives(true); dehydrateDirectives(true);
$_LOCALS_ACCESSOR = null; ${_names.getLocalsAccessorName()} = null;
$_PIPES_ACCESSOR = null; ${_names.getPipesAccessorName()} = null;
} }
${_maybeGenDehydrateDirectives()} ${_maybeGenDehydrateDirectives()}
hydrated() => ${_names.getContextName()} != null; hydrated() => ${_names.getFieldName(CONTEXT_INDEX)} != null;
static $_GEN_PREFIX.ProtoChangeDetector static $_GEN_PREFIX.ProtoChangeDetector
$PROTO_CHANGE_DETECTOR_FACTORY_METHOD( $PROTO_CHANGE_DETECTOR_FACTORY_METHOD(
@ -190,16 +181,12 @@ class _CodegenState {
var destroyPipesParamName = 'destroyPipes'; var destroyPipesParamName = 'destroyPipes';
var destroyPipesCode = _names.genPipeOnDestroy(); var destroyPipesCode = _names.genPipeOnDestroy();
if (destroyPipesCode.isNotEmpty) { if (destroyPipesCode.isNotEmpty) {
destroyPipesCode = 'if (${destroyPipesParamName}) { ' destroyPipesCode = 'if (${destroyPipesParamName}) {${destroyPipesCode}}';
'${destroyPipesCode}'
'}';
} }
var dehydrateFieldsCode = _names.genDehydrateFields(); var dehydrateFieldsCode = _names.genDehydrateFields();
if (destroyPipesCode.isEmpty && dehydrateFieldsCode.isEmpty) return ''; if (destroyPipesCode.isEmpty && dehydrateFieldsCode.isEmpty) return '';
return 'void dehydrateDirectives(${destroyPipesParamName}) {' return 'void dehydrateDirectives(${destroyPipesParamName}) '
'${destroyPipesCode}' '{ ${destroyPipesCode} ${dehydrateFieldsCode} }';
'${dehydrateFieldsCode}'
'}';
} }
String _maybeGenHydrateDirectives() { String _maybeGenHydrateDirectives() {
@ -208,10 +195,8 @@ class _CodegenState {
if (hydrateDirectivesCode.isEmpty && hydrateDetectorsCode.isEmpty) { if (hydrateDirectivesCode.isEmpty && hydrateDetectorsCode.isEmpty) {
return ''; return '';
} }
return 'void hydrateDirectives(directives) { ' return 'void hydrateDirectives(directives) '
'$hydrateDirectivesCode' '{ $hydrateDirectivesCode $hydrateDetectorsCode }';
'$hydrateDetectorsCode'
'}';
} }
String _genHydrateDirectives() { String _genHydrateDirectives() {
@ -219,7 +204,7 @@ class _CodegenState {
var directiveFieldNames = _names.getAllDirectiveNames(); var directiveFieldNames = _names.getAllDirectiveNames();
for (var i = 0; i < directiveFieldNames.length; ++i) { for (var i = 0; i < directiveFieldNames.length; ++i) {
buf.writeln('${directiveFieldNames[i]} = directives.getDirectiveFor(' buf.writeln('${directiveFieldNames[i]} = directives.getDirectiveFor('
'$_DIRECTIVES_ACCESSOR[$i].directiveIndex);'); '${_names.getDirectivesAccessorName()}[$i].directiveIndex);');
} }
return '$buf'; return '$buf';
} }
@ -229,7 +214,7 @@ class _CodegenState {
var detectorFieldNames = _names.getAllDetectorNames(); var detectorFieldNames = _names.getAllDetectorNames();
for (var i = 0; i < detectorFieldNames.length; ++i) { for (var i = 0; i < detectorFieldNames.length; ++i) {
buf.writeln('${detectorFieldNames[i]} = directives.getDetectorFor(' buf.writeln('${detectorFieldNames[i]} = directives.getDetectorFor('
'$_DIRECTIVES_ACCESSOR[$i].directiveIndex);'); '${_names.getDirectivesAccessorName()}[$i].directiveIndex);');
} }
return '$buf'; return '$buf';
} }
@ -244,11 +229,22 @@ class _CodegenState {
'${_names.getDirectiveName(rec.directiveIndex)}.onAllChangesDone();') '${_names.getDirectiveName(rec.directiveIndex)}.onAllChangesDone();')
.join(''); .join('');
return ''' return '''
$_DISPATCHER_ACCESSOR.notifyOnAllChangesDone(); ${_names.getDispatcherName()}.notifyOnAllChangesDone();
${directiveNotifications} ${directiveNotifications}
'''; ''';
} }
String _genDeclareFields() {
var fields = _names.getAllFieldNames();
// If there's only one field, it's `context`, declared in the superclass.
if (fields.length == 1) return '';
fields.removeAt(CONTEXT_INDEX);
var toRemove = 'this.';
var declareNames = fields
.map((f) => f.startsWith(toRemove) ? f.substring(toRemove.length) : f);
return 'var ${declareNames.join(', ')};';
}
String _genRecord(ProtoRecord r) { String _genRecord(ProtoRecord r) {
var rec = null; var rec = null;
if (r.isLifeCycleRecord()) { if (r.isLifeCycleRecord()) {
@ -287,12 +283,12 @@ class _CodegenState {
var protoIndex = r.selfIndex - 1; var protoIndex = r.selfIndex - 1;
var pipeType = r.name; var pipeType = r.name;
return ''' return '''
$_CURRENT_PROTO = $_PROTOS_ACCESSOR[$protoIndex]; ${_names.getCurrentProtoName()} = ${_names.getProtosName()}[$protoIndex];
if ($_IDENTICAL_CHECK_FN($pipe, $_UTIL.uninitialized)) { if ($_IDENTICAL_CHECK_FN($pipe, $_UTIL.uninitialized)) {
$pipe = $_PIPES_ACCESSOR.get('$pipeType', $context, $cdRef); $pipe = ${_names.getPipesAccessorName()}.get('$pipeType', $context, $cdRef);
} else if (!$pipe.supports($context)) { } else if (!$pipe.supports($context)) {
$pipe.onDestroy(); $pipe.onDestroy();
$pipe = $_PIPES_ACCESSOR.get('$pipeType', $context, $cdRef); $pipe = ${_names.getPipesAccessorName()}.get('$pipeType', $context, $cdRef);
} }
$newValue = $pipe.transform($context, [$argString]); $newValue = $pipe.transform($context, [$argString]);
@ -312,7 +308,7 @@ class _CodegenState {
var protoIndex = r.selfIndex - 1; var protoIndex = r.selfIndex - 1;
var check = ''' var check = '''
$_CURRENT_PROTO = $_PROTOS_ACCESSOR[$protoIndex]; ${_names.getCurrentProtoName()} = ${_names.getProtosName()}[$protoIndex];
${_genUpdateCurrentValue(r)} ${_genUpdateCurrentValue(r)}
if ($_NOT_IDENTICAL_CHECK_FN($newValue, $oldValue)) { if ($_NOT_IDENTICAL_CHECK_FN($newValue, $oldValue)) {
${_names.getChangeName(r.selfIndex)} = true; ${_names.getChangeName(r.selfIndex)} = true;
@ -357,7 +353,7 @@ class _CodegenState {
break; break;
case RecordType.LOCAL: case RecordType.LOCAL:
rhs = '$_LOCALS_ACCESSOR.get("${r.name}")'; rhs = '${_names.getLocalsAccessorName()}.get("${r.name}")';
break; break;
case RecordType.INVOKE_METHOD: case RecordType.INVOKE_METHOD:
@ -421,8 +417,8 @@ class _CodegenState {
} else { } else {
return ''' return '''
${_genThrowOnChangeCheck(oldValue, newValue)} ${_genThrowOnChangeCheck(oldValue, newValue)}
$_DISPATCHER_ACCESSOR.notifyOnBinding( ${_names.getDispatcherName()}.notifyOnBinding(
$_CURRENT_PROTO.bindingRecord, ${newValue}); ${_names.getCurrentProtoName()}.bindingRecord, ${newValue});
'''; ''';
} }
} }
@ -432,7 +428,7 @@ class _CodegenState {
return ''' return '''
if(throwOnChange) { if(throwOnChange) {
$_UTIL.throwOnChange( $_UTIL.throwOnChange(
$_CURRENT_PROTO, $_UTIL.simpleChange(${oldValue}, ${newValue})); ${_names.getCurrentProtoName()}, $_UTIL.simpleChange(${oldValue}, ${newValue}));
} }
'''; ''';
} else { } else {
@ -455,7 +451,7 @@ class _CodegenState {
return ''' return '''
$_CHANGES_LOCAL = $_UTIL.addChange( $_CHANGES_LOCAL = $_UTIL.addChange(
$_CHANGES_LOCAL, $_CHANGES_LOCAL,
$_CURRENT_PROTO.bindingRecord.propertyName, ${_names.getCurrentProtoName()}.bindingRecord.propertyName,
$_UTIL.simpleChange($oldValue, $newValue)); $_UTIL.simpleChange($oldValue, $newValue));
'''; ''';
} }
@ -477,7 +473,7 @@ class _CodegenState {
String _genOnInit(ProtoRecord r) { String _genOnInit(ProtoRecord r) {
var br = r.bindingRecord; var br = r.bindingRecord;
return 'if (!throwOnChange && !$_ALREADY_CHECKED_ACCESSOR) ' return 'if (!throwOnChange && !${_names.getAlreadyCheckedName()}) '
'${_names.getDirectiveName(br.directiveRecord.directiveIndex)}.onInit();'; '${_names.getDirectiveName(br.directiveRecord.directiveIndex)}.onInit();';
} }
@ -504,21 +500,13 @@ class _CodegenState {
const PROTO_CHANGE_DETECTOR_FACTORY_METHOD = 'newProtoChangeDetector'; const PROTO_CHANGE_DETECTOR_FACTORY_METHOD = 'newProtoChangeDetector';
const _ALREADY_CHECKED_ACCESSOR = '_alreadyChecked';
const _BASE_CLASS = '$_GEN_PREFIX.AbstractChangeDetector'; const _BASE_CLASS = '$_GEN_PREFIX.AbstractChangeDetector';
const _CHANGES_LOCAL = 'changes'; const _CHANGES_LOCAL = 'changes';
const _CURRENT_PROTO = 'currentProto';
const _DIRECTIVES_ACCESSOR = '_directiveRecords';
const _DISPATCHER_ACCESSOR = 'dispatcher';
const _GEN_PREFIX = '_gen'; const _GEN_PREFIX = '_gen';
const _GEN_RECORDS_METHOD_NAME = '_createRecords'; const _GEN_RECORDS_METHOD_NAME = '_createRecords';
const _IDENTICAL_CHECK_FN = '$_GEN_PREFIX.looseIdentical'; const _IDENTICAL_CHECK_FN = '$_GEN_PREFIX.looseIdentical';
const _NOT_IDENTICAL_CHECK_FN = '$_GEN_PREFIX.looseNotIdentical'; const _NOT_IDENTICAL_CHECK_FN = '$_GEN_PREFIX.looseNotIdentical';
const _IS_CHANGED_LOCAL = 'isChanged'; const _IS_CHANGED_LOCAL = 'isChanged';
const _LOCALS_ACCESSOR = '_locals';
const _MODE_ACCESSOR = 'mode';
const _PREGEN_PROTO_CHANGE_DETECTOR_IMPORT = const _PREGEN_PROTO_CHANGE_DETECTOR_IMPORT =
'package:angular2/src/change_detection/pregen_proto_change_detector.dart'; 'package:angular2/src/change_detection/pregen_proto_change_detector.dart';
const _PIPES_ACCESSOR = '_pipes';
const _PROTOS_ACCESSOR = '_protos';
const _UTIL = '$_GEN_PREFIX.ChangeDetectionUtil'; const _UTIL = '$_GEN_PREFIX.ChangeDetectionUtil';

View File

@ -23,19 +23,12 @@ void initReflector() {
_gen.preGeneratedProtoDetectors['MyComponent_comp_0'] = _gen.preGeneratedProtoDetectors['MyComponent_comp_0'] =
_MyComponent_ChangeDetector0.newProtoChangeDetector; _MyComponent_ChangeDetector0.newProtoChangeDetector;
} }
class _MyComponent_ChangeDetector0 extends _gen.AbstractChangeDetector { class _MyComponent_ChangeDetector0
_gen.Pipes _pipes; extends _gen.AbstractChangeDetector<MyComponent> {
final _gen.List<_gen.ProtoRecord> _protos; var myNum0, interpolate1;
final _gen.List<_gen.DirectiveRecord> _directiveRecords;
dynamic _locals = null;
dynamic _alreadyChecked = false;
dynamic currentProto = null;
MyComponent _context;
var _myNum0, _interpolate1;
_MyComponent_ChangeDetector0( _MyComponent_ChangeDetector0(dispatcher, protos, directiveRecords)
dynamic dispatcher, this._protos, this._directiveRecords) : super("MyComponent_comp_0", dispatcher, protos, directiveRecords) {
: super("MyComponent_comp_0", dispatcher) {
dehydrateDirectives(false); dehydrateDirectives(false);
} }
@ -46,48 +39,53 @@ class _MyComponent_ChangeDetector0 extends _gen.AbstractChangeDetector {
try { try {
__detectChangesInRecords(throwOnChange); __detectChangesInRecords(throwOnChange);
} catch (e, s) { } catch (e, s) {
throwError(currentProto, e, s); throwError(this.currentProto, e, s);
} }
} }
void __detectChangesInRecords(throwOnChange) { void __detectChangesInRecords(throwOnChange) {
var context, c_context, myNum0, c_myNum0, interpolate1, c_interpolate1; this.currentProto = null;
c_context = c_myNum0 = c_interpolate1 = false; var l_context = this.context,
l_myNum0,
c_myNum0,
l_interpolate1,
c_interpolate1;
c_myNum0 = c_interpolate1 = false;
var isChanged = false; var isChanged = false;
currentProto = null;
var changes = null; var changes = null;
context = _context; this.currentProto = this.protos[0];
currentProto = _protos[0]; l_myNum0 = l_context.myNum;
myNum0 = context.myNum; if (_gen.looseNotIdentical(l_myNum0, this.myNum0)) {
if (_gen.looseNotIdentical(myNum0, _myNum0)) {
c_myNum0 = true; c_myNum0 = true;
_myNum0 = myNum0; this.myNum0 = l_myNum0;
} }
if (c_myNum0) { if (c_myNum0) {
currentProto = _protos[1]; this.currentProto = this.protos[1];
interpolate1 = "Salad: " "${myNum0 == null ? "" : myNum0}" " is awesome"; l_interpolate1 =
if (_gen.looseNotIdentical(interpolate1, _interpolate1)) { "Salad: " "${l_myNum0 == null ? "" : l_myNum0}" " is awesome";
if (_gen.looseNotIdentical(l_interpolate1, this.interpolate1)) {
c_interpolate1 = true; c_interpolate1 = true;
if (throwOnChange) { if (throwOnChange) {
_gen.ChangeDetectionUtil.throwOnChange(currentProto, _gen.ChangeDetectionUtil.throwOnChange(this.currentProto,
_gen.ChangeDetectionUtil.simpleChange( _gen.ChangeDetectionUtil.simpleChange(
_interpolate1, interpolate1)); this.interpolate1, l_interpolate1));
} }
dispatcher.notifyOnBinding(currentProto.bindingRecord, interpolate1); this.dispatcher.notifyOnBinding(
this.currentProto.bindingRecord, l_interpolate1);
_interpolate1 = interpolate1; this.interpolate1 = l_interpolate1;
} }
} else { } else {
interpolate1 = _interpolate1; l_interpolate1 = this.interpolate1;
} }
changes = null; changes = null;
isChanged = false; isChanged = false;
_alreadyChecked = true; this.alreadyChecked = true;
} }
void checkNoChanges() { void checkNoChanges() {
@ -95,30 +93,30 @@ class _MyComponent_ChangeDetector0 extends _gen.AbstractChangeDetector {
} }
void callOnAllChangesDone() { void callOnAllChangesDone() {
dispatcher.notifyOnAllChangesDone(); this.dispatcher.notifyOnAllChangesDone();
} }
void hydrate(MyComponent context, locals, directives, pipes) { void hydrate(MyComponent context, locals, directives, pipes) {
mode = 'ALWAYS_CHECK'; this.mode = 'ALWAYS_CHECK';
_context = context; this.context = context;
_locals = locals; this.locals = locals;
hydrateDirectives(directives); hydrateDirectives(directives);
_alreadyChecked = false; this.alreadyChecked = false;
_pipes = pipes; this.pipes = pipes;
} }
void dehydrate() { void dehydrate() {
dehydrateDirectives(true); dehydrateDirectives(true);
_locals = null; this.locals = null;
_pipes = null; this.pipes = null;
} }
void dehydrateDirectives(destroyPipes) { void dehydrateDirectives(destroyPipes) {
_context = null; this.context = null;
_myNum0 = _interpolate1 = _gen.ChangeDetectionUtil.uninitialized; this.myNum0 = this.interpolate1 = _gen.ChangeDetectionUtil.uninitialized;
} }
hydrated() => _context != null; hydrated() => this.context != null;
static _gen.ProtoChangeDetector newProtoChangeDetector( static _gen.ProtoChangeDetector newProtoChangeDetector(
_gen.ChangeDetectorDefinition def) { _gen.ChangeDetectorDefinition def) {

View File

@ -8,6 +8,7 @@ import {
Parser, Parser,
ChangeDispatcher, ChangeDispatcher,
ChangeDetection, ChangeDetection,
DebugContext,
DynamicChangeDetection, DynamicChangeDetection,
JitChangeDetection, JitChangeDetection,
ChangeDetectorDefinition, ChangeDetectorDefinition,
@ -380,6 +381,9 @@ class FakeDirectives {
} }
class DummyDispatcher implements ChangeDispatcher { class DummyDispatcher implements ChangeDispatcher {
getDebugContext(elementIndex: number, directiveIndex: DirectiveIndex): DebugContext {
throw "getDebugContext not implemented.";
}
notifyOnBinding(bindingRecord, newValue) { throw "Should not be used"; } notifyOnBinding(bindingRecord, newValue) { throw "Should not be used"; }
notifyOnAllChangesDone() {} notifyOnAllChangesDone() {}
} }