@@ -136,6 +136,151 @@ function captureStackTraces(stackTraces: string[][], count: number): void {
136
136
}
137
137
}
138
138
139
+ const zoneAwareStackFrames = { } ;
140
+ Zone [ '__symbol__' ] [ ( 'zoneAwareStackFrames' ) ] = zoneAwareStackFrames ;
141
+ const zoneAwareFunctionNames = [
142
+ 'Zone' , 'drainMicrotask' , 'getStacktraceWithUncaughtError' , 'new LongStackTrace' ,
143
+ 'Object.onScheduleTask'
144
+ ] ;
145
+
146
+ function handleDetectError ( error : Error ) {
147
+ let frames = error . stack ? error . stack . split ( / \n / ) : [ ] ;
148
+ while ( frames . length ) {
149
+ let frame = frames . shift ( ) ;
150
+ // On safari it is possible to have stack frame with no line number.
151
+ // This check makes sure that we don't filter frames on name only (must have
152
+ // linenumber)
153
+ if ( / : \d + : \d + / . test ( frame ) ) {
154
+ const f = frame . split ( ' [' ) [ 0 ] ;
155
+ if ( zoneAwareFunctionNames . filter ( zf => f . toLowerCase ( ) . indexOf ( f . toLowerCase ( ) ) !== - 1 )
156
+ . length > 0 ) {
157
+ zoneAwareStackFrames [ f ] = f ;
158
+ }
159
+ }
160
+ }
161
+ }
162
+
163
+ const detectEmptyZone = Zone . root . fork ( Zone [ 'longStackTraceZoneSpec' ] ) . fork ( {
164
+ name : 'detectEmptyZone' ,
165
+ onHandleError ( parentDelegate , currentZone , targetZone , error ) {
166
+ parentDelegate . handleError ( targetZone , error ) ;
167
+ handleDetectError ( error ) ;
168
+ return false ;
169
+ }
170
+ } ) ;
171
+
172
+ const detectZoneWithCallbacks = Zone . root . fork ( Zone [ 'longStackTraceZoneSpec' ] ) . fork ( {
173
+ name : 'detectCallbackZone' ,
174
+ onFork : ( parentDelegate , currentZone , targetZone , zoneSpec ) => {
175
+ return parentDelegate . fork ( targetZone , zoneSpec ) ;
176
+ } ,
177
+ onIntercept : ( parentDelegate , currentZone , targetZone , delegate , source ) => {
178
+ return parentDelegate . intercept ( targetZone , delegate , source ) ;
179
+ } ,
180
+ onInvoke :
181
+ ( parentZoneDelegate , currentZone , targetZone , delegate , applyThis , applyArgs , source ) => {
182
+ return parentZoneDelegate . invoke ( targetZone , delegate , applyThis , applyArgs , source ) ;
183
+ } ,
184
+ onScheduleTask : ( parentZoneDelegate , currentZone , targetZone , task ) => {
185
+ return parentZoneDelegate . scheduleTask ( targetZone , task ) ;
186
+ } ,
187
+ onInvokeTask : ( parentZoneDelegate , currentZone , targetZone , task , applyThis , applyArgs ) => {
188
+ return parentZoneDelegate . invokeTask ( targetZone , task , applyThis , applyArgs ) ;
189
+ } ,
190
+ onCancelTask : ( parentZoneDelegate , currentZone , targetZone , task ) => {
191
+ return parentZoneDelegate . cancelTask ( targetZone , task ) ;
192
+ } ,
193
+
194
+ onHasTask : ( delegate , current , target , hasTaskState ) => {
195
+ return delegate . hasTask ( target , hasTaskState ) ;
196
+ } ,
197
+
198
+ onHandleError ( parentDelegate , currentZone , targetZone , error ) {
199
+ parentDelegate . handleError ( targetZone , error ) ;
200
+ handleDetectError ( error ) ;
201
+ return false ;
202
+ }
203
+ } ) ;
204
+
205
+ let detectFn = ( ) => {
206
+ throw new Error ( 'zoneAwareFrames' ) ;
207
+ } ;
208
+
209
+ let detectPromiseFn = ( ) => {
210
+ const p = new Promise ( ( resolve , reject ) => {
211
+ reject ( new Error ( 'zoneAwareFrames' ) ) ;
212
+ } ) ;
213
+ } ;
214
+
215
+ let detectPromiseCaughtFn = ( ) => {
216
+ const p = new Promise ( ( resolve , reject ) => {
217
+ reject ( new Error ( 'zoneAwareFrames' ) ) ;
218
+ } ) ;
219
+ p . catch ( err => {
220
+ throw err ;
221
+ } ) ;
222
+ } ;
223
+
224
+ // Cause the error to extract the stack frames.
225
+ detectEmptyZone . runTask (
226
+ detectEmptyZone . scheduleEventTask ( 'detect' , detectFn , null , ( ) => null , null ) ) ;
227
+ detectZoneWithCallbacks . runTask (
228
+ detectZoneWithCallbacks . scheduleEventTask ( 'detect' , detectFn , null , ( ) => null , null ) ) ;
229
+ detectEmptyZone . runTask (
230
+ detectEmptyZone . scheduleMacroTask ( 'detect' , detectFn , null , ( ) => null , null ) ) ;
231
+ detectZoneWithCallbacks . runTask (
232
+ detectZoneWithCallbacks . scheduleMacroTask ( 'detect' , detectFn , null , ( ) => null , null ) ) ;
233
+ detectEmptyZone . runTask ( detectEmptyZone . scheduleMicroTask ( 'detect' , detectFn , null , ( ) => null ) ) ;
234
+ detectZoneWithCallbacks . runTask (
235
+ detectZoneWithCallbacks . scheduleMicroTask ( 'detect' , detectFn , null , ( ) => null ) ) ;
236
+
237
+ detectEmptyZone . runGuarded ( ( ) => {
238
+ detectEmptyZone . run ( detectFn ) ;
239
+ } ) ;
240
+ detectZoneWithCallbacks . runGuarded ( ( ) => {
241
+ detectEmptyZone . run ( detectFn ) ;
242
+ } ) ;
243
+
244
+ detectEmptyZone . runGuarded ( detectPromiseFn ) ;
245
+ detectZoneWithCallbacks . runGuarded ( detectPromiseFn ) ;
246
+
247
+ detectEmptyZone . runGuarded ( detectPromiseCaughtFn ) ;
248
+ detectZoneWithCallbacks . runGuarded ( detectPromiseCaughtFn ) ;
249
+
250
+ // some functions are not easily to be detected here,
251
+ // for example Timeout.ZoneTask.invoke, if we want to detect those functions
252
+ // by detect zone, we have to run all patched APIs, it is too risky
253
+ // so for those functions, just check whether the stack contains the string or not.
254
+ const otherZoneAwareFunctionNames = [ 'ZoneTask.invoke' , 'ZoneAware' ] ;
255
+
256
+ Object . defineProperty ( Error , 'getNonZoneAwareStack' , {
257
+ value : function ( err : Error ) {
258
+ if ( err . stack ) {
259
+ let frames = err . stack . split ( '\n' ) ;
260
+ const simplifiedFrames : string [ ] = [ ] ;
261
+ for ( let i = 0 ; i < frames . length ; i ++ ) {
262
+ const frame = frames [ i ] . split ( ' [' ) [ 0 ] ;
263
+ const frameWithoutZone = frame . split ( ' [' ) [ 0 ] ;
264
+ if ( zoneAwareStackFrames . hasOwnProperty ( frameWithoutZone ) &&
265
+ zoneAwareStackFrames [ frameWithoutZone ] ) {
266
+ frames . splice ( i , 1 ) ;
267
+ i -- ;
268
+ } else if (
269
+ otherZoneAwareFunctionNames
270
+ . filter ( f => frame . toLowerCase ( ) . indexOf ( f . toLowerCase ( ) ) !== - 1 )
271
+ . length > 0 ) {
272
+ frames . splice ( i , 1 ) ;
273
+ i -- ;
274
+ } else {
275
+ simplifiedFrames . push ( frame ) ;
276
+ }
277
+ }
278
+ return simplifiedFrames . join ( '\n' ) ;
279
+ }
280
+ return err . stack ;
281
+ }
282
+ } ) ;
283
+
139
284
function computeIgnoreFrames ( ) {
140
285
const frames : string [ ] [ ] = [ ] ;
141
286
captureStackTraces ( frames , 2 ) ;
0 commit comments