node-inspector/lib/PageAgent.js

179 строки
5.2 KiB
JavaScript

// node-inspector version of on webkit-inspector/InspectorPageAgent.cpp
var fs = require('fs'),
path = require('path'),
inherits = require('util').inherits,
extend = require('util')._extend,
EventEmitter = require('events').EventEmitter,
async = require('async'),
convert = require('./convert.js'),
ScriptFileStorage = require('./ScriptFileStorage.js').ScriptFileStorage;
/**
* @param {{isScriptHidden}} config
* @param {DebuggerClient} debuggerClient
* @param {ScriptManager} scriptManager
* @constructor
*/
function PageAgent(config, debuggerClient, scriptManager) {
this._debuggerClient = debuggerClient;
this._scriptManager = scriptManager;
this._scriptStorage = new ScriptFileStorage(config);
}
inherits(PageAgent, EventEmitter);
extend(PageAgent.prototype, {
enable: function(params, done) {
done();
},
canShowFPSCounter: function(params, done) {
done(null, { show: false });
},
canContinuouslyPaint: function(params, done) {
done(null, { value: false });
},
setTouchEmulationEnabled: function(params, done) {
done();
},
getResourceTree: function(params, done) {
var cb = function() {
done.apply(null, arguments);
this.emit('resource-tree');
}.bind(this);
if (this._debuggerClient.isConnected) {
this._doGetResourceTree(params, cb);
} else {
this._debuggerClient.once(
'connect',
this._doGetResourceTree.bind(this, params, cb)
);
}
},
_doGetResourceTree: function(params, done) {
var describeProgram = '[process.cwd(), ' +
'process.mainModule ? process.mainModule.filename : process.argv[1]]';
async.waterfall(
[
this._debuggerClient.evaluateGlobal
.bind(this._debuggerClient, describeProgram),
function(evaluateResult, cb) {
cb(null, evaluateResult[0], evaluateResult[1]);
},
this._resolveMainAppScript.bind(this),
this._getResourceTreeForAppScript.bind(this)
],
done
);
},
_resolveMainAppScript: function(startDirectory, mainAppScript, done) {
this._scriptManager.mainAppScript = mainAppScript;
if (mainAppScript == null) {
// mainScriptFile is null when running in the REPL mode
return done(null, startDirectory, mainAppScript);
}
fs.stat(mainAppScript, function(err, stat) {
if (err && !/\.js$/.test(mainAppScript)) {
mainAppScript += '.js';
}
return done(null, startDirectory, mainAppScript);
});
},
_getResourceTreeForAppScript: function(startDirectory, mainAppScript, done) {
async.waterfall(
[
this._scriptStorage.findAllApplicationScripts
.bind(this._scriptStorage, startDirectory, mainAppScript),
this._createResourceTreeResponse.bind(this, mainAppScript)
],
done
);
},
_createResourceTreeResponse: function(mainAppScript, scriptFiles, done) {
var resources = scriptFiles.map(function(filePath) {
return {
url: convert.v8NameToInspectorUrl(filePath),
type: 'Script',
mimeType: 'text/javascript'
};
});
done(null, {
frameTree: {
frame: {
id: 'nodeinspector-toplevel-frame',
url: convert.v8NameToInspectorUrl(mainAppScript),
// Front-end keeps a history of local modifications based
// on loaderId. Ideally we should return such id that it remains
// same as long as the the debugger process has the same content
// of scripts and that changes when a new content is loaded.
//
// To keep things easy, we are returning an unique value for now.
// This means that every reload of node-inspector page discards
// the history of live-edit changes.
//
// Perhaps we can use PID as loaderId instead?
loaderId: createUniqueLoaderId(),
_isNodeInspectorScript: true
},
resources: resources
}
});
},
getResourceContent: function(params, done) {
var scriptName = convert.inspectorUrlToV8Name(params.url);
if (scriptName === '') {
// When running REPL, main application file is null
// and node inspector returns an empty string to the front-end.
// However, front-end still asks for resource content.
// Let's return a descriptive comment then.
var content = '// There is no main module loaded in node.\n' +
'// This is expected when you are debugging node\'s interactive REPL console.';
return process.nextTick(
this._convertScriptSourceToGetResourceResponse.bind(this, content, done));
}
async.waterfall(
[
this._scriptStorage.load.bind(this._scriptStorage, scriptName),
this._convertScriptSourceToGetResourceResponse.bind(this)
],
done
);
},
_convertScriptSourceToGetResourceResponse: function(source, done) {
return done(null, {
content: source
});
},
reload: function(params, done) {
// This is called when user press Cmd+R (F5?), do we want to perform an action on this?
done();
}
});
exports.PageAgent = PageAgent;
function createUniqueLoaderId() {
var randomPart = String(Math.random()).slice(2);
return Date.now() + '-' + randomPart;
}