UNPKG

devil-windows

Version:

Debugger, profiler and runtime with embedded WebKit DevTools client (for Windows).

261 lines (217 loc) 8.31 kB
var fs = require('fs'), path = require('path'), async = require('async'), glob = require('glob'); function escapeRegex(str) { return str.replace(/([/\\.?*()^${}|[\]])/g, '\\$1'); } var MODULE_HEADER = '(function (exports, require, module, __filename, __dirname) { '; var MODULE_TRAILER = '\n});'; var MODULE_WRAP_REGEX = new RegExp( '^' + escapeRegex(MODULE_HEADER) + '([\\s\\S]*)' + escapeRegex(MODULE_TRAILER) + '$' ); var CONVENTIONAL_DIRS_PATTERN = '{*.js,lib/**/*.js,node_modules/**/*.js,test/**/*.js}'; var ALL_JS_PATTERN = '**/*.js'; /** * ScriptStorage class. Controls all scripts and live edit. * Refactored from node-inspector * https://github.com/node-inspector/node-inspector * * @param {boolean} preload * @param {v8.DebuggerClient} debuggerClient * @constructor */ var ScriptStorage = function (debuggerClient, preload) { var $this = this; // // Public stuff /** * @type {object} * @private */ var _lastList = null; /** * @type {boolean} * @private */ var _noPreload = (preload === false); /** * @type {ScriptManager} * @private */ var _scriptManager = debuggerClient.scriptManager; /** * For a given script file, find the root directory containing all application source files. * * Example: * file = ~/work/app/bin/cli.js * root = ~/work/app * * The algorithm: * * By default, we assume that the source file is in the root directory * (~/work/app/bin in the example above). * * If this directory does not contain 'package.json' and the parent directory * contains 'package.json', then we assume the parent directory is * the application root (~/work/app in the example above). * * @param {string} file * @param {Function} callback */ var _findApplicationRootForRealFile = function (file, callback) { var mainDir = path.dirname(file); var parentDir = path.dirname(mainDir); console.log("_findApplicationRootForRealFile", mainDir, parentDir, file); async.detect([mainDir, parentDir], _isApplicationRoot, function (result) { callback(null, result || mainDir, !!result); }); }; var _isApplicationRoot = function (folder, callback) { fs.exists(path.join(folder, 'package.json'), callback); }; var _findScriptsOfRunningApp = function (mainScriptFile, callback) { if (!mainScriptFile) { // mainScriptFile is null when running in the REPL mode return process.nextTick(callback.bind(null, null, [])); } $this.findApplicationRoot(mainScriptFile, function (err, dir, isRoot) { if (err) return callback(err); $this.rootDir = dir; var pattern = isRoot ? ALL_JS_PATTERN : CONVENTIONAL_DIRS_PATTERN; $this.listScripts(dir, pattern, callback); }); }; var _findScriptsOfStartDirectoryApp = function (startDirectory, callback) { // TODO: check this out some day. return callback(null, []); _isApplicationRoot(startDirectory, function handleIsStartDirectoryApplicationRoot(result) { if (!result) callback(null, []); else $this.listScripts(startDirectory, ALL_JS_PATTERN, callback); }); }; // // Public stuff this.rootDir = null; /** * @param {string} path * @param {function(Object, string)} callback */ this.load = function (path, callback) { fs.readFile(path, 'utf-8', function (err, content) { if (err) return callback(err); // remove shebang content = content.replace(/^\#\!.*/, ''); var source = content; _scriptManager.setContent(path, source); return callback(null, source); }); }; /** * @param {string} path * @param {string} content * @param {Function} callback */ this.save = function (path, content, callback) { /*var match = MODULE_WRAP_REGEX.exec(content); if (!match) { callback(new Error('The new content is not a valid node.js script.')); return; } var newSource = match[1];*/ var newSource = content; fs.readFile(path, 'utf-8', function (err, oldContent) { if (err) return callback(err); var match = /^(\#\!.*)/.exec(oldContent); if (match) newSource = match[1] + newSource; console.log("-- GOD DAMN IT", err); fs.writeFile(path, newSource, callback); }); }; /** * @param {string} mainScriptFile * @param {function(Object, string)} callback */ this.findApplicationRoot = function (mainScriptFile, callback) { fs.realpath(mainScriptFile, function (err, realPath) { if (err) { console.demonicLog('[WARNING] Cannot resolve real path of %s: %s', mainScriptFile, err); realPath = mainScriptFile; } _findApplicationRootForRealFile(realPath, callback); }); }; /** * @param {string} rootFolder * @param {string} pattern * @param {function(Object, Array.<string>?)} callback */ this.listScripts = function (rootFolder, pattern, callback) { var last = _lastList; if (last && last.rootFolder == rootFolder && last.pattern == pattern) { process.nextTick(function () { callback(last.error, last.result); }); return; } // This simpler solution unfortunately does not work on windows // see https://github.com/isaacs/node-glob/pull/68 // glob( // '**/*.js', // { root: rootFolder }, // callback // ); glob(pattern, {cwd: rootFolder, strict: false}, function (err, result) { if (result) { result = result.map(function (relativeUnixPath) { var relativePath = relativeUnixPath.split('/').join(path.sep); return path.join(rootFolder, relativePath); }); } _lastList = { rootFolder: rootFolder, pattern: pattern, error: err, result: result }; callback(err, result); }); }; /** * @param {string} startDirectory * @param {string} mainScriptFile * @param {function(Object, Array.<string>)} callback */ this.findAllApplicationScripts = function (startDirectory, mainScriptFile, callback) { if (_noPreload) return process.nextTick(function () { callback(null, []); }); console.log("\n\n\n\n\n\n\n\n\n\n====\n\n\n\n\n\n\n\n\n", startDirectory, mainScriptFile, "\n\n\n\n\n\n\n\n\n\n====\n\n\n\n\n\n\n\n\n"); async.series([ _findScriptsOfRunningApp.bind(this, mainScriptFile), _findScriptsOfStartDirectoryApp.bind(this, startDirectory)//, //_scriptManager.getAllScripts.bind(_scriptManager) ], function (err, results) { if (err) return callback(err); var files = results[0].concat(results[1]); //, results[2] files = files.filter(function onlyUnique(value, index, self) { return self.indexOf(value) === index && value.length > 0; }); console.log("\n\n\n\n\n\n\n\n\n\n====\n\n\n\n\n\n\n\n\n", files, "\n\n\n\n\n\n\n\n\n\n====\n\n\n\n\n\n\n\n\n"); // Filter out duplicates and files to hide files = files.filter(function (elem, ix, arr) { return arr.indexOf(elem) >= ix && !_scriptManager.isScriptHidden(elem); }); return callback(null, files); }); }; /** * Destructor */ this.destroy = function () { _scriptManager = null; }; }; module.exports = ScriptStorage;