wtf.ts 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. /**
  2. * @license
  3. * Copyright Google Inc. All Rights Reserved.
  4. *
  5. * Use of this source code is governed by an MIT-style license that can be
  6. * found in the LICENSE file at https://angular.io/license
  7. */
  8. /**
  9. * @fileoverview
  10. * @suppress {missingRequire}
  11. */
  12. (function(global: any) {
  13. interface Wtf {
  14. trace: WtfTrace;
  15. }
  16. interface WtfScope {}
  17. interface WtfRange {}
  18. interface WtfTrace {
  19. events: WtfEvents;
  20. leaveScope(scope: WtfScope, returnValue?: any): void;
  21. beginTimeRange(rangeType: string, action: string): WtfRange;
  22. endTimeRange(range: WtfRange): void;
  23. }
  24. interface WtfEvents {
  25. createScope(signature: string, flags?: any): WtfScopeFn;
  26. createInstance(signature: string, flags?: any): WtfEventFn;
  27. }
  28. type WtfScopeFn = (...args: any[]) => WtfScope;
  29. type WtfEventFn = (...args: any[]) => any;
  30. // Detect and setup WTF.
  31. let wtfTrace: WtfTrace = null;
  32. let wtfEvents: WtfEvents = null;
  33. const wtfEnabled: boolean = (function(): boolean {
  34. const wtf: Wtf = global['wtf'];
  35. if (wtf) {
  36. wtfTrace = wtf.trace;
  37. if (wtfTrace) {
  38. wtfEvents = wtfTrace.events;
  39. return true;
  40. }
  41. }
  42. return false;
  43. })();
  44. class WtfZoneSpec implements ZoneSpec {
  45. name: string = 'WTF';
  46. static forkInstance =
  47. wtfEnabled && wtfEvents.createInstance('Zone:fork(ascii zone, ascii newZone)');
  48. static scheduleInstance: {[key: string]: WtfEventFn} = {};
  49. static cancelInstance: {[key: string]: WtfEventFn} = {};
  50. static invokeScope: {[key: string]: WtfEventFn} = {};
  51. static invokeTaskScope: {[key: string]: WtfEventFn} = {};
  52. onFork(
  53. parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone,
  54. zoneSpec: ZoneSpec): Zone {
  55. const retValue = parentZoneDelegate.fork(targetZone, zoneSpec);
  56. WtfZoneSpec.forkInstance(zonePathName(targetZone), retValue.name);
  57. return retValue;
  58. }
  59. onInvoke(
  60. parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, delegate: Function,
  61. applyThis: any, applyArgs: any[], source: string): any {
  62. let scope = WtfZoneSpec.invokeScope[source];
  63. if (!scope) {
  64. scope = WtfZoneSpec.invokeScope[source] =
  65. wtfEvents.createScope(`Zone:invoke:${source}(ascii zone)`);
  66. }
  67. return wtfTrace.leaveScope(
  68. scope(zonePathName(targetZone)),
  69. parentZoneDelegate.invoke(targetZone, delegate, applyThis, applyArgs, source));
  70. }
  71. onHandleError(
  72. parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone,
  73. error: any): boolean {
  74. return parentZoneDelegate.handleError(targetZone, error);
  75. }
  76. onScheduleTask(
  77. parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, task: Task): any {
  78. const key = task.type + ':' + task.source;
  79. let instance = WtfZoneSpec.scheduleInstance[key];
  80. if (!instance) {
  81. instance = WtfZoneSpec.scheduleInstance[key] =
  82. wtfEvents.createInstance(`Zone:schedule:${key}(ascii zone, any data)`);
  83. }
  84. const retValue = parentZoneDelegate.scheduleTask(targetZone, task);
  85. instance(zonePathName(targetZone), shallowObj(task.data, 2));
  86. return retValue;
  87. }
  88. onInvokeTask(
  89. parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, task: Task,
  90. applyThis: any, applyArgs: any[]): any {
  91. const source = task.source;
  92. let scope = WtfZoneSpec.invokeTaskScope[source];
  93. if (!scope) {
  94. scope = WtfZoneSpec.invokeTaskScope[source] =
  95. wtfEvents.createScope(`Zone:invokeTask:${source}(ascii zone)`);
  96. }
  97. return wtfTrace.leaveScope(
  98. scope(zonePathName(targetZone)),
  99. parentZoneDelegate.invokeTask(targetZone, task, applyThis, applyArgs));
  100. }
  101. onCancelTask(parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, task: Task):
  102. any {
  103. const key = task.source;
  104. let instance = WtfZoneSpec.cancelInstance[key];
  105. if (!instance) {
  106. instance = WtfZoneSpec.cancelInstance[key] =
  107. wtfEvents.createInstance(`Zone:cancel:${key}(ascii zone, any options)`);
  108. }
  109. const retValue = parentZoneDelegate.cancelTask(targetZone, task);
  110. instance(zonePathName(targetZone), shallowObj(task.data, 2));
  111. return retValue;
  112. }
  113. }
  114. function shallowObj(obj: {[k: string]: any}, depth: number): any {
  115. if (!depth) return null;
  116. const out: {[k: string]: any} = {};
  117. for (const key in obj) {
  118. if (obj.hasOwnProperty(key)) {
  119. let value = obj[key];
  120. switch (typeof value) {
  121. case 'object':
  122. const name = value && value.constructor && (<any>value.constructor).name;
  123. value = name == (<any>Object).name ? shallowObj(value, depth - 1) : name;
  124. break;
  125. case 'function':
  126. value = value.name || undefined;
  127. break;
  128. }
  129. out[key] = value;
  130. }
  131. }
  132. return out;
  133. }
  134. function zonePathName(zone: Zone) {
  135. let name: string = zone.name;
  136. zone = zone.parent;
  137. while (zone != null) {
  138. name = zone.name + '::' + name;
  139. zone = zone.parent;
  140. }
  141. return name;
  142. }
  143. (Zone as any)['wtfZoneSpec'] = !wtfEnabled ? null : new WtfZoneSpec();
  144. })(typeof window === 'object' && window || typeof self === 'object' && self || global);