RuntimeAgent.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. // node-inspector version of on webkit-inspector/InspectorRuntimeAgent.cpp
  2. var convert = require('./convert.js'),
  3. util = require('util'),
  4. CallFramesProvider = require('./CallFramesProvider.js').CallFramesProvider;
  5. /**
  6. * @param {Object} config
  7. * @param {DebuggerClient} debuggerClient
  8. * @constructor
  9. */
  10. function RuntimeAgent(config, debuggerClient) {
  11. this._debuggerClient = debuggerClient;
  12. this._callFramesProvider = new CallFramesProvider(config, debuggerClient);
  13. }
  14. RuntimeAgent.prototype = {
  15. enable: function(params, done) {
  16. done();
  17. },
  18. evaluate: function(params, done) {
  19. var self = this;
  20. self._debuggerClient.request(
  21. 'evaluate',
  22. {
  23. expression: params.expression,
  24. global: true
  25. },
  26. function(err, result) {
  27. // Errors from V8 are actually just messages, so we need to fill them out a bit.
  28. if (err) {
  29. err = convert.v8ErrorToInspectorError(err);
  30. }
  31. done(null, {
  32. result: err || convert.v8ResultToInspectorResult(result),
  33. wasThrown: !!err
  34. });
  35. }
  36. );
  37. },
  38. callFunctionOn: function(params, done) {
  39. function callFunctionWithParams(err, evaluateParams) {
  40. if (err) {
  41. done(err);
  42. return;
  43. }
  44. var callback = this._handleCallFunctionOnObjectResponse
  45. .bind(this, done, params.returnByValue);
  46. this._debuggerClient.request(
  47. 'evaluate',
  48. evaluateParams,
  49. callback
  50. );
  51. }
  52. this._createEvaluateParamsForFunctionCall(
  53. params.objectId,
  54. params.functionDeclaration,
  55. params.arguments,
  56. callFunctionWithParams.bind(this)
  57. );
  58. },
  59. _createEvaluateParamsForFunctionCall:
  60. function(selfId, declaration, args, done) {
  61. args = args || [];
  62. try {
  63. var argsData = args.map(this._getFunctionCallArgsData.bind(this));
  64. var params = this._buildEvaluateParamsFromArgsData(
  65. selfId,
  66. declaration,
  67. argsData);
  68. done(null, params);
  69. } catch (err) {
  70. done(err);
  71. }
  72. },
  73. _buildEvaluateParamsFromArgsData: function(selfId, declaration, argsData) {
  74. argsData.unshift(this._getSelfArgData(selfId));
  75. var argNames = argsData.map(function(a) { return a.code; });
  76. var argContexts = argsData
  77. .map(function(a) { return a.context; })
  78. // filter out empty contexts (value types are context-less)
  79. .filter(function(c) { return !!c; });
  80. var expression = util.format(
  81. '(%s).call(%s)',
  82. declaration,
  83. argNames.join(', '));
  84. return {
  85. expression: expression,
  86. global: true,
  87. additional_context: argContexts
  88. };
  89. },
  90. _getSelfArgData: function(selfId) {
  91. var SELF_CONTEXT_NAME = '__node_inspector_self__';
  92. return {
  93. code: SELF_CONTEXT_NAME,
  94. context: {
  95. name: SELF_CONTEXT_NAME,
  96. handle: Number(selfId)
  97. }
  98. };
  99. },
  100. _getFunctionCallArgsData: function(arg, index) {
  101. var uniqueId = '__node_inspector_arg' + index;
  102. switch (arg.type) {
  103. case undefined:
  104. case 'string':
  105. return { code: util.format('"%s"', arg.value) };
  106. case 'number':
  107. return { code: arg.value };
  108. case 'null':
  109. case 'undefined':
  110. return { code: arg.type };
  111. case 'object':
  112. case 'function':
  113. return {
  114. code: uniqueId,
  115. context: {
  116. name: uniqueId,
  117. handle: Number(arg.objectId)
  118. }
  119. };
  120. default:
  121. throw new Error(util.format(
  122. 'Function arguments of type "%s" are not supported',
  123. arg.type
  124. ));
  125. }
  126. },
  127. _handleCallFunctionOnObjectResponse:
  128. function(done, returnByValue, err, response) {
  129. if (err) {
  130. done(null, {
  131. err: err,
  132. wasThrown: true
  133. });
  134. return;
  135. }
  136. var value = {};
  137. if (returnByValue && response.properties) {
  138. for (var i = 0; i < response.properties.length; i++) {
  139. value[response.properties[i].name] = true;
  140. }
  141. }
  142. done(null, {
  143. result: { value: value },
  144. wasThrown: false
  145. });
  146. },
  147. getProperties: function(params, done) {
  148. // TODO implement the new way of getting object properties
  149. //
  150. // Front-end sends the following two requests for Object properties:
  151. // "params": {"objectId":"78","ownProperties":false,"accessorPropertiesOnly":true}
  152. // "params":{"objectId":"78","ownProperties":true,"accessorPropertiesOnly":false}
  153. //
  154. // Or the following request for Scope properties:
  155. // "params":{"objectId":"scope:0:2","ownProperties":false,"accessorPropertiesOnly":false}
  156. // See getProperties() and getInjectedProperties() in
  157. // http://src.chromium.org/blink/branches/chromium/1625/Source/core/
  158. // inspector/InjectedScriptSource.js
  159. // for more details.
  160. var options = {
  161. ownProperties: params.ownProperties,
  162. accessorPropertiesOnly: params.accessorPropertiesOnly
  163. };
  164. if (this._callFramesProvider.isScopeId(params.objectId)) {
  165. this._getPropertiesOfScopeId(params.objectId, options, done);
  166. } else {
  167. this._getPropertiesOfObjectId(params.objectId, options, done);
  168. }
  169. },
  170. _getPropertiesOfScopeId: function(scopeId, options, done) {
  171. this._callFramesProvider.resolveScopeId(
  172. scopeId,
  173. function(err, result) {
  174. if (err) {
  175. done(err);
  176. } else {
  177. this._getPropertiesOfObjectId(result, options, done);
  178. }
  179. }.bind(this)
  180. );
  181. },
  182. _getPropertiesOfObjectId: function(objectId, options, done) {
  183. var handle = parseInt(objectId, 10);
  184. var request = { handles: [handle], includeSource: false };
  185. this._debuggerClient.request(
  186. 'lookup',
  187. request,
  188. function(error, responseBody, responseRefs) {
  189. if (error) {
  190. done(error);
  191. return;
  192. }
  193. var obj = responseBody[handle],
  194. props = convert.v8ObjectToInspectorProperties(obj, responseRefs, options);
  195. done(null, { result: props });
  196. }
  197. );
  198. },
  199. releaseObjectGroup: function(params, done) {
  200. // V8 debugger protocol does not support object groups
  201. done();
  202. },
  203. releaseObject: function(params, done) {
  204. // V8 debugger protocol does not support manual release
  205. done();
  206. }
  207. };
  208. exports.RuntimeAgent = RuntimeAgent;