fix(change_detection): throw ChangeDetectionError in JIT mode
This commit is contained in:
parent
d2774421e8
commit
c2efa23e94
|
@ -2,6 +2,8 @@ import {isPresent} 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 {ChangeDetector} from './interfaces';
|
||||||
|
import {ChangeDetectionError} from './exceptions';
|
||||||
|
import {ProtoRecord} from './proto_record';
|
||||||
import {Locals} from './parser/locals';
|
import {Locals} from './parser/locals';
|
||||||
import {CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED, ON_PUSH} from './constants';
|
import {CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED, ON_PUSH} from './constants';
|
||||||
|
|
||||||
|
@ -79,4 +81,8 @@ export class AbstractChangeDetector implements ChangeDetector {
|
||||||
c = c.parent;
|
c = c.parent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throwError(proto: ProtoRecord, exception: any, stack: any): void {
|
||||||
|
throw new ChangeDetectionError(proto, exception, stack);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ var IS_CHANGED_LOCAL = "isChanged";
|
||||||
var CHANGES_LOCAL = "changes";
|
var CHANGES_LOCAL = "changes";
|
||||||
var LOCALS_ACCESSOR = "this.locals";
|
var LOCALS_ACCESSOR = "this.locals";
|
||||||
var MODE_ACCESSOR = "this.mode";
|
var MODE_ACCESSOR = "this.mode";
|
||||||
var CURRENT_PROTO = "currentProto";
|
var CURRENT_PROTO = "this.currentProto";
|
||||||
var ALREADY_CHECKED_ACCESSOR = "this.alreadyChecked";
|
var ALREADY_CHECKED_ACCESSOR = "this.alreadyChecked";
|
||||||
|
|
||||||
|
|
||||||
|
@ -74,6 +74,7 @@ export class ChangeDetectorJITGenerator {
|
||||||
${PROTOS_ACCESSOR} = protos;
|
${PROTOS_ACCESSOR} = protos;
|
||||||
${DIRECTIVES_ACCESSOR} = directiveRecords;
|
${DIRECTIVES_ACCESSOR} = directiveRecords;
|
||||||
${LOCALS_ACCESSOR} = null;
|
${LOCALS_ACCESSOR} = null;
|
||||||
|
${CURRENT_PROTO} = null;
|
||||||
${ALREADY_CHECKED_ACCESSOR} = false;
|
${ALREADY_CHECKED_ACCESSOR} = false;
|
||||||
${this._genFieldDefinitions()}
|
${this._genFieldDefinitions()}
|
||||||
}
|
}
|
||||||
|
@ -84,10 +85,19 @@ export class ChangeDetectorJITGenerator {
|
||||||
if (!this.hydrated()) {
|
if (!this.hydrated()) {
|
||||||
${UTIL}.throwDehydrated();
|
${UTIL}.throwDehydrated();
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
this.__detectChangesInRecords(throwOnChange);
|
||||||
|
} catch (e) {
|
||||||
|
this.throwError(${CURRENT_PROTO}, e, e.stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
${typeName}.prototype.__detectChangesInRecords = function(throwOnChange) {
|
||||||
|
${CURRENT_PROTO} = null;
|
||||||
|
|
||||||
${this._genLocalDefinitions()}
|
${this._genLocalDefinitions()}
|
||||||
${this._genChangeDefinitions()}
|
${this._genChangeDefinitions()}
|
||||||
var ${IS_CHANGED_LOCAL} = false;
|
var ${IS_CHANGED_LOCAL} = false;
|
||||||
var ${CURRENT_PROTO};
|
|
||||||
var ${CHANGES_LOCAL} = null;
|
var ${CHANGES_LOCAL} = null;
|
||||||
|
|
||||||
context = ${CONTEXT_ACCESSOR};
|
context = ${CONTEXT_ACCESSOR};
|
||||||
|
|
|
@ -10,8 +10,6 @@ import {ChangeDetectionUtil, SimpleChange, uninitialized} from './change_detecti
|
||||||
|
|
||||||
import {ProtoRecord, RecordType} from './proto_record';
|
import {ProtoRecord, RecordType} from './proto_record';
|
||||||
|
|
||||||
import {ExpressionChangedAfterItHasBeenChecked, ChangeDetectionError} from './exceptions';
|
|
||||||
|
|
||||||
export class DynamicChangeDetector extends AbstractChangeDetector {
|
export class DynamicChangeDetector extends AbstractChangeDetector {
|
||||||
locals: Locals = null;
|
locals: Locals = null;
|
||||||
values: List<any>;
|
values: List<any>;
|
||||||
|
@ -149,7 +147,7 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
|
||||||
return this._referenceCheck(proto, throwOnChange);
|
return this._referenceCheck(proto, throwOnChange);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new ChangeDetectionError(proto, e);
|
this.throwError(proto, e, e.stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,29 +2,20 @@ import {ProtoRecord} from './proto_record';
|
||||||
import {BaseException} from "angular2/src/facade/lang";
|
import {BaseException} from "angular2/src/facade/lang";
|
||||||
|
|
||||||
export class ExpressionChangedAfterItHasBeenChecked extends BaseException {
|
export class ExpressionChangedAfterItHasBeenChecked extends BaseException {
|
||||||
message: string;
|
|
||||||
|
|
||||||
constructor(proto: ProtoRecord, change: any) {
|
constructor(proto: ProtoRecord, change: any) {
|
||||||
super();
|
super(`Expression '${proto.expressionAsString}' has changed after it was checked. ` +
|
||||||
this.message =
|
`Previous value: '${change.previousValue}'. Current value: '${change.currentValue}'`);
|
||||||
`Expression '${proto.expressionAsString}' has changed after it was checked. ` +
|
|
||||||
`Previous value: '${change.previousValue}'. Current value: '${change.currentValue}'`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toString(): string { return this.message; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ChangeDetectionError extends BaseException {
|
export class ChangeDetectionError extends BaseException {
|
||||||
message: string;
|
|
||||||
location: string;
|
location: string;
|
||||||
|
|
||||||
constructor(proto: ProtoRecord, public originalException: any) {
|
constructor(proto: ProtoRecord, originalException: any, originalStack: any) {
|
||||||
super();
|
super(`${originalException} in [${proto.expressionAsString}]`, originalException,
|
||||||
|
originalStack);
|
||||||
this.location = proto.expressionAsString;
|
this.location = proto.expressionAsString;
|
||||||
this.message = `${this.originalException} in [${this.location}]`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toString(): string { return this.message; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DehydratedException extends BaseException {
|
export class DehydratedException extends BaseException {
|
||||||
|
|
|
@ -131,6 +131,7 @@ class _CodegenState {
|
||||||
$_DIRECTIVES_ACCESSOR;
|
$_DIRECTIVES_ACCESSOR;
|
||||||
dynamic $_LOCALS_ACCESSOR = null;
|
dynamic $_LOCALS_ACCESSOR = null;
|
||||||
dynamic $_ALREADY_CHECKED_ACCESSOR = false;
|
dynamic $_ALREADY_CHECKED_ACCESSOR = false;
|
||||||
|
dynamic $_CURRENT_PROTO = null;
|
||||||
${_allFields().map((f) {
|
${_allFields().map((f) {
|
||||||
if (f == _CONTEXT_ACCESSOR) {
|
if (f == _CONTEXT_ACCESSOR) {
|
||||||
return '$_contextTypeName $f = null;';
|
return '$_contextTypeName $f = null;';
|
||||||
|
@ -148,10 +149,18 @@ class _CodegenState {
|
||||||
if (!hydrated()) {
|
if (!hydrated()) {
|
||||||
$_UTIL.throwDehydrated();
|
$_UTIL.throwDehydrated();
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
this.__detectChangesInRecords(throwOnChange);
|
||||||
|
} catch (e, s) {
|
||||||
|
this.throwError($_CURRENT_PROTO, e, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __detectChangesInRecords(throwOnChange) {
|
||||||
${_genLocalDefinitions()}
|
${_genLocalDefinitions()}
|
||||||
${_genChangeDefinitons()}
|
${_genChangeDefinitons()}
|
||||||
var $_IS_CHANGED_LOCAL = false;
|
var $_IS_CHANGED_LOCAL = false;
|
||||||
var $_CURRENT_PROTO;
|
$_CURRENT_PROTO = null;
|
||||||
var $_CHANGES_LOCAL = null;
|
var $_CHANGES_LOCAL = null;
|
||||||
|
|
||||||
context = $_CONTEXT_ACCESSOR;
|
context = $_CONTEXT_ACCESSOR;
|
||||||
|
|
|
@ -309,5 +309,6 @@ var _availableDefinitions = [
|
||||||
'sayHi("Jim")',
|
'sayHi("Jim")',
|
||||||
'a()(99)',
|
'a()(99)',
|
||||||
'a.sayHi("Jim")',
|
'a.sayHi("Jim")',
|
||||||
'passThrough([12])'
|
'passThrough([12])',
|
||||||
|
'invalidFn(1)'
|
||||||
];
|
];
|
||||||
|
|
|
@ -542,16 +542,15 @@ export function main() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO vsavkin: implement it
|
|
||||||
describe('error handling', () => {
|
describe('error handling', () => {
|
||||||
xit('should wrap exceptions into ChangeDetectionError', () => {
|
it('should wrap exceptions into ChangeDetectionError', () => {
|
||||||
var val = _createChangeDetector('invalidProp');
|
var val = _createChangeDetector('invalidFn(1)');
|
||||||
try {
|
try {
|
||||||
val.changeDetector.detectChanges();
|
val.changeDetector.detectChanges();
|
||||||
throw new BaseException('fail');
|
throw new BaseException('fail');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
expect(e).toBeAnInstanceOf(ChangeDetectionError);
|
expect(e).toBeAnInstanceOf(ChangeDetectionError);
|
||||||
expect(e.location).toEqual('invalidProp in someComponent');
|
expect(e.location).toEqual('invalidFn(1) in location');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -32,6 +32,7 @@ class _MyComponent_ChangeDetector0 extends _gen.AbstractChangeDetector {
|
||||||
final _gen.List<_gen.DirectiveRecord> _directiveRecords;
|
final _gen.List<_gen.DirectiveRecord> _directiveRecords;
|
||||||
dynamic _locals = null;
|
dynamic _locals = null;
|
||||||
dynamic _alreadyChecked = false;
|
dynamic _alreadyChecked = false;
|
||||||
|
dynamic currentProto = null;
|
||||||
MyComponent _context = null;
|
MyComponent _context = null;
|
||||||
dynamic _myNum0 = _gen.ChangeDetectionUtil.uninitialized();
|
dynamic _myNum0 = _gen.ChangeDetectionUtil.uninitialized();
|
||||||
dynamic _interpolate1 = _gen.ChangeDetectionUtil.uninitialized();
|
dynamic _interpolate1 = _gen.ChangeDetectionUtil.uninitialized();
|
||||||
|
@ -44,6 +45,14 @@ class _MyComponent_ChangeDetector0 extends _gen.AbstractChangeDetector {
|
||||||
if (!hydrated()) {
|
if (!hydrated()) {
|
||||||
_gen.ChangeDetectionUtil.throwDehydrated();
|
_gen.ChangeDetectionUtil.throwDehydrated();
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
this.__detectChangesInRecords(throwOnChange);
|
||||||
|
} catch (e, s) {
|
||||||
|
this.throwError(currentProto, e, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __detectChangesInRecords(throwOnChange) {
|
||||||
var context = null;
|
var context = null;
|
||||||
var myNum0 = null;
|
var myNum0 = null;
|
||||||
var interpolate1 = null;
|
var interpolate1 = null;
|
||||||
|
@ -51,7 +60,7 @@ class _MyComponent_ChangeDetector0 extends _gen.AbstractChangeDetector {
|
||||||
var change_myNum0 = false;
|
var change_myNum0 = false;
|
||||||
var change_interpolate1 = false;
|
var change_interpolate1 = false;
|
||||||
var isChanged = false;
|
var isChanged = false;
|
||||||
var currentProto;
|
currentProto = null;
|
||||||
var changes = null;
|
var changes = null;
|
||||||
|
|
||||||
context = _context;
|
context = _context;
|
||||||
|
|
Loading…
Reference in New Issue