scopeYLT.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /**
  2. * Overwritting the original spying functions in scope.js
  3. * This is done so we now have a before AND an after callback on the spy
  4. *
  5. * @see http://code.jquery.com/jquery-1.10.2.js
  6. * @see http://code.jquery.com/jquery-2.0.3.js
  7. */
  8. /* global document: true, window: true */
  9. 'use strict';
  10. exports.version = '0.1';
  11. exports.module = function(phantomas) {
  12. phantomas.once('init', function() {
  13. phantomas.evaluate(function(deepAnalysis) {
  14. (function(phantomas) {
  15. // Overwritting phantomas spy function
  16. (function() {
  17. var enabled = true;
  18. // turn off spying to not include internal phantomas actions
  19. function spyEnabled(state, reason) {
  20. enabled = (state === true);
  21. phantomas.log('Spying ' + (enabled ? 'enabled' : 'disabled') + (reason ? ' - ' + reason : ''));
  22. }
  23. phantomas.log('Overwritting phantomas spy function');
  24. function spy(obj, fn, callbackBefore, callbackAfter) {
  25. var origFn = obj[fn];
  26. if (typeof origFn !== 'function') {
  27. return false;
  28. }
  29. phantomas.log('Attaching a spy to "' + fn + '" function...');
  30. obj[fn] = function() {
  31. var result;
  32. // Before
  33. if (enabled) {
  34. var args = Array.prototype.slice.call(arguments);
  35. callbackBefore.apply(this, args);
  36. }
  37. // Execute
  38. try {
  39. result = origFn.apply(this, arguments);
  40. } catch(e) {
  41. phantomas.log('Error catched on spyed function "' + fn + '"": ' + e);
  42. } finally {
  43. // After
  44. if (enabled && callbackAfter) {
  45. var args = Array.prototype.slice.call(arguments);
  46. callbackAfter.apply(this, args);
  47. }
  48. }
  49. return result;
  50. };
  51. // copy custom properties of original function to the mocked one
  52. Object.keys(origFn).forEach(function(key) {
  53. obj[fn][key] = origFn[key];
  54. });
  55. obj[fn].prototype = origFn.prototype;
  56. return true;
  57. }
  58. phantomas.spyEnabled = spyEnabled;
  59. phantomas.spy = spy;
  60. })();
  61. // Adding some code for the Javascript execution tree construction
  62. (function() {
  63. var root = new ContextTreeNode(null, {type: 'main'});
  64. var currentContext = root;
  65. if (deepAnalysis) {
  66. phantomas.log('Entering deep Javascript analysis mode');
  67. }
  68. var depth = 0;
  69. // Add a child but don't enter his context
  70. function pushContext(data) {
  71. if (depth === 0 || deepAnalysis) {
  72. data.timestamp = Date.now();
  73. currentContext.addChild(data);
  74. }
  75. }
  76. // Add a child to the current context and enter his context
  77. function enterContext(data) {
  78. if (depth === 0 || deepAnalysis) {
  79. data.timestamp = Date.now();
  80. currentContext = currentContext.addChild(data);
  81. }
  82. depth ++;
  83. }
  84. // Save given data in the current context and jump change current context to its parent
  85. function leaveContext() {
  86. if (depth === 1 || deepAnalysis) {
  87. currentContext.time = Date.now() - currentContext.data.timestamp;
  88. var parent = currentContext.parent;
  89. if (parent === null) {
  90. console.error('Error: trying to close root context in ContextTree');
  91. } else {
  92. currentContext = parent;
  93. }
  94. }
  95. depth --;
  96. }
  97. function getContextData() {
  98. return currentContext.data;
  99. }
  100. // Returns a clean object, without the parent which causes recursive loops
  101. function readFullTree() {
  102. // Return null if the contextTree is not correctly closed
  103. if (root !== currentContext) {
  104. return null;
  105. }
  106. var current = currentContext;
  107. function recusiveRead(node) {
  108. if (node.children.length === 0) {
  109. delete node.children;
  110. } else {
  111. for (var i=0, max=node.children.length ; i<max ; i++) {
  112. recusiveRead(node.children[i]);
  113. }
  114. }
  115. delete node.parent;
  116. }
  117. recusiveRead(root);
  118. return root;
  119. }
  120. function ContextTreeNode(parent, data) {
  121. this.data = data;
  122. this.parent = parent;
  123. this.children = [];
  124. this.addChild = function(data) {
  125. var child = new ContextTreeNode(this, data);
  126. this.children.push(child);
  127. return child;
  128. }
  129. }
  130. phantomas.log('Adding some contextTree functions to phantomas');
  131. phantomas.pushContext = pushContext;
  132. phantomas.enterContext = enterContext;
  133. phantomas.leaveContext = leaveContext;
  134. phantomas.getContextData = getContextData;
  135. phantomas.readFullTree = readFullTree;
  136. })();
  137. })(window.__phantomas);
  138. }, phantomas.getParam('js-deep-analysis'));
  139. });
  140. };