node-inspector/lib/RuntimeAgent.js

236 строки
6.2 KiB
JavaScript

// node-inspector version of on webkit-inspector/InspectorRuntimeAgent.cpp
var convert = require('./convert.js'),
util = require('util'),
CallFramesProvider = require('./CallFramesProvider.js').CallFramesProvider;
/**
* @param {Object} config
* @param {DebuggerClient} debuggerClient
* @constructor
*/
function RuntimeAgent(config, debuggerClient) {
this._debuggerClient = debuggerClient;
this._callFramesProvider = new CallFramesProvider(config, debuggerClient);
}
RuntimeAgent.prototype = {
enable: function(params, done) {
done();
},
evaluate: function(params, done) {
var self = this;
self._debuggerClient.request(
'evaluate',
{
expression: params.expression,
global: true
},
function(err, result) {
// Errors from V8 are actually just messages, so we need to fill them out a bit.
if (err) {
err = convert.v8ErrorToInspectorError(err);
}
done(null, {
result: err || convert.v8ResultToInspectorResult(result),
wasThrown: !!err
});
}
);
},
callFunctionOn: function(params, done) {
function callFunctionWithParams(err, evaluateParams) {
if (err) {
done(err);
return;
}
var callback = this._handleCallFunctionOnObjectResponse
.bind(this, done, params.returnByValue);
this._debuggerClient.request(
'evaluate',
evaluateParams,
callback
);
}
this._createEvaluateParamsForFunctionCall(
params.objectId,
params.functionDeclaration,
params.arguments,
callFunctionWithParams.bind(this)
);
},
_createEvaluateParamsForFunctionCall:
function(selfId, declaration, args, done) {
args = args || [];
try {
var argsData = args.map(this._getFunctionCallArgsData.bind(this));
var params = this._buildEvaluateParamsFromArgsData(
selfId,
declaration,
argsData);
done(null, params);
} catch (err) {
done(err);
}
},
_buildEvaluateParamsFromArgsData: function(selfId, declaration, argsData) {
argsData.unshift(this._getSelfArgData(selfId));
var argNames = argsData.map(function(a) { return a.code; });
var argContexts = argsData
.map(function(a) { return a.context; })
// filter out empty contexts (value types are context-less)
.filter(function(c) { return !!c; });
var expression = util.format(
'(%s).call(%s)',
declaration,
argNames.join(', '));
return {
expression: expression,
global: true,
additional_context: argContexts
};
},
_getSelfArgData: function(selfId) {
var SELF_CONTEXT_NAME = '__node_inspector_self__';
return {
code: SELF_CONTEXT_NAME,
context: {
name: SELF_CONTEXT_NAME,
handle: Number(selfId)
}
};
},
_getFunctionCallArgsData: function(arg, index) {
var uniqueId = '__node_inspector_arg' + index;
switch (arg.type) {
case undefined:
case 'string':
return { code: util.format('"%s"', arg.value) };
case 'number':
return { code: arg.value };
case 'null':
case 'undefined':
return { code: arg.type };
case 'object':
case 'function':
return {
code: uniqueId,
context: {
name: uniqueId,
handle: Number(arg.objectId)
}
};
default:
throw new Error(util.format(
'Function arguments of type "%s" are not supported',
arg.type
));
}
},
_handleCallFunctionOnObjectResponse:
function(done, returnByValue, err, response) {
if (err) {
done(null, {
err: err,
wasThrown: true
});
return;
}
var value = {};
if (returnByValue && response.properties) {
for (var i = 0; i < response.properties.length; i++) {
value[response.properties[i].name] = true;
}
}
done(null, {
result: { value: value },
wasThrown: false
});
},
getProperties: function(params, done) {
// TODO implement the new way of getting object properties
//
// Front-end sends the following two requests for Object properties:
// "params": {"objectId":"78","ownProperties":false,"accessorPropertiesOnly":true}
// "params":{"objectId":"78","ownProperties":true,"accessorPropertiesOnly":false}
//
// Or the following request for Scope properties:
// "params":{"objectId":"scope:0:2","ownProperties":false,"accessorPropertiesOnly":false}
// See getProperties() and getInjectedProperties() in
// http://src.chromium.org/blink/branches/chromium/1625/Source/core/
// inspector/InjectedScriptSource.js
// for more details.
var options = {
ownProperties: params.ownProperties,
accessorPropertiesOnly: params.accessorPropertiesOnly
};
if (this._callFramesProvider.isScopeId(params.objectId)) {
this._getPropertiesOfScopeId(params.objectId, options, done);
} else {
this._getPropertiesOfObjectId(params.objectId, options, done);
}
},
_getPropertiesOfScopeId: function(scopeId, options, done) {
this._callFramesProvider.resolveScopeId(
scopeId,
function(err, result) {
if (err) {
done(err);
} else {
this._getPropertiesOfObjectId(result, options, done);
}
}.bind(this)
);
},
_getPropertiesOfObjectId: function(objectId, options, done) {
var handle = parseInt(objectId, 10);
var request = { handles: [handle], includeSource: false };
this._debuggerClient.request(
'lookup',
request,
function(error, responseBody, responseRefs) {
if (error) {
done(error);
return;
}
var obj = responseBody[handle],
props = convert.v8ObjectToInspectorProperties(obj, responseRefs, options);
done(null, { result: props });
}
);
},
releaseObjectGroup: function(params, done) {
// V8 debugger protocol does not support object groups
done();
},
releaseObject: function(params, done) {
// V8 debugger protocol does not support manual release
done();
}
};
exports.RuntimeAgent = RuntimeAgent;