Skip to content

Commit

Permalink
fix angular#595,angular#427, refactor Error construct process
Browse files Browse the repository at this point in the history
  • Loading branch information
JiaLiPassion committed Jan 13, 2017
1 parent e1d3240 commit 82cf09d
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 31 deletions.
75 changes: 46 additions & 29 deletions lib/zone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,6 @@ const Zone: ZoneType = (function(global: any) {
}
}


scheduleMicroTask(
source: string, callback: Function, data?: TaskData,
customSchedule?: (task: Task) => void): MicroTask {
Expand Down Expand Up @@ -1330,38 +1329,52 @@ const Zone: ZoneType = (function(global: any) {
let frameParserStrategy = null;
const stackRewrite = 'stackRewrite';

const assignAll = function(to, from) {
if (!to) {
return to;
}

if (from) {
let keys = Object.getOwnPropertyNames(from);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(from, key)) {
to[key] = from[key];
const createProperty = function(key) {
return {
configurable: true,
enumerable: true,
get: function() {
return this[__symbol__('error')] && this[__symbol__('error')][key];
/*const name = __symbol__(key);
if (!this[name]) {
this[name] = this[__symbol__('error')] && this[__symbol__('error')][key];
}
return this[name];
*/
},
set: function(value) {
if (this[__symbol__('error')]) {
this[__symbol__('error')][key] = value;
}
}
};
};

// copy all properties from prototype
// in Error, property such as name/message is in Error's prototype
// but not enumerable, so we copy those properties through
// Error's prototype
const proto = Object.getPrototypeOf(from);
if (proto) {
let pKeys = Object.getOwnPropertyNames(proto);
for (let i = 0; i < pKeys.length; i++) {
const key = pKeys[i];
// skip constructor
if (key !== 'constructor') {
to[key] = from[key];
}
const createProperties = function(instance, proto) {
let props = Object.create(null);
let keys = Object.getOwnPropertyNames(instance);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(instance, key)) {
props[key] = createProperty(key);
}
}
if (proto) {
let pKeys = Object.getOwnPropertyNames(proto);
for (let i = 0; i < pKeys.length; i++) {
const key = pKeys[i];
// skip constructor
if (key !== 'constructor' && key !== 'toString') {
props[key] = createProperty(key);
}
}
}
return to;

props['originalStack'] = createProperty('originalStack');
props['zoneAwareStack'] = createProperty('zoneAwareStack');

return props;
};

/**
Expand All @@ -1378,6 +1391,7 @@ const Zone: ZoneType = (function(global: any) {
}
// Create an Error.
let error: Error = NativeError.apply(this, arguments);
this[__symbol__('error')] = error;

// Save original stack trace
error.originalStack = error.stack;
Expand Down Expand Up @@ -1414,11 +1428,14 @@ const Zone: ZoneType = (function(global: any) {
}
error.stack = error.zoneAwareStack = frames.join('\n');
}
return assignAll(this, error);
this.toString = error.toString;
return this;
}

// Copy the prototype so that instanceof operator works as expected
ZoneAwareError.prototype = NativeError.prototype;
ZoneAwareError.prototype = Object.create(
NativeError.prototype, createProperties(new NativeError(), NativeError.prototype));

ZoneAwareError[Zone.__symbol__('blacklistedStackFrames')] = blackListedStackFrames;
ZoneAwareError[stackRewrite] = false;

Expand Down
40 changes: 40 additions & 0 deletions test/common/Error.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,46 @@ describe('ZoneAwareError', () => {
}
});

it('should not use child Error class get/set in ZoneAwareError constructor', () => {
// simulate @angular/facade/src/error.ts
class BaseError extends Error {
/** @internal **/
_nativeError: Error;

constructor(message: string) {
super(message);
const nativeError = new Error(message) as any as Error;
this._nativeError = nativeError;
}

get message() {
return this._nativeError.message;
}
set message(message) {
this._nativeError.message = message;
}
get name() {
return this._nativeError.name;
}
get stack() {
return (this._nativeError as any).stack;
}
set stack(value) {
(this._nativeError as any).stack = value;
}
toString() {
return this._nativeError.toString();
}
}

const func = () => {
const error = new BaseError('test');
expect(error.message).toEqual('test');
};

expect(func).not.toThrow();
});

it('should show zone names in stack frames and remove extra frames', () => {
const rootZone = getRootZone();
const innerZone = rootZone.fork({name: 'InnerZone'});
Expand Down
9 changes: 7 additions & 2 deletions test/zone-spec/fake-async-test.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,14 @@ describe('FakeAsyncTestZoneSpec', () => {
Promise.resolve(null).then((_) => {
throw new Error('async');
});
expect(() => {
try {
testZoneSpec.flushMicrotasks();
}).toThrowError(/Uncaught \(in promise\): Error: async/);
} catch (err) {
console.log('rethrow', err.toString());
}
// expect(() => {
// testZoneSpec.flushMicrotasks();
//}).toThrowError(/Uncaught \(in promise\): Error: async/);
});
});

Expand Down

0 comments on commit 82cf09d

Please sign in to comment.