diff options
Diffstat (limited to 'node_modules/time-require/src')
| -rw-r--r-- | node_modules/time-require/src/requireHook.js | 93 | ||||
| -rw-r--r-- | node_modules/time-require/src/timeRequire.js | 140 | 
2 files changed, 233 insertions, 0 deletions
diff --git a/node_modules/time-require/src/requireHook.js b/node_modules/time-require/src/requireHook.js new file mode 100644 index 000000000..ebafbb603 --- /dev/null +++ b/node_modules/time-require/src/requireHook.js @@ -0,0 +1,93 @@ +/** + * requireHook - module wrapping a function that register require() listener and returns hook/unhook control + * + * @author Ciprian Popa (cyparu) + * @since 0.0.1 + * @version 0.0.1 + */ + +"use strict"; + +var Module = require("module").Module, +		_load = Module._load, +		_hookedAt, _listener; + +/** + * Module hooker function that will replace Module._load and invoke the _listener with module and timing information + * + * @function _hooker + */ +function _hooker(name, parent) { +	var timeIn = Date.now(), +			exports = _load.apply(Module, arguments), +			timeOut = Date.now(), +			mod = parent.children[parent.children.length - 1]; // should be the last loaded children +	// call the listener +	_listener({ +		name: name, +		parent: parent, +		module: mod, +		filename: mod ? mod.filename : name, +		exports: exports, +		requiredOn: timeIn, +		startedIn: timeOut - timeIn +	}); +	return exports; +} + +/** + * Hook Node's require() so the configured callback will be invocked with additional module and time loading information information + * + * @param {Function} [listener] - optional listener if + * @method hook + */ +function _hook(listener) { +	if (typeof listener !== "undefined") { +		if (typeof listener !== "function") { +			throw new Error("The optional parameter for hook() should be a function but was " + (typeof listener)); +		} +		// set the listener +		_listener = listener; +	} +	// set the hoocker loader +	Module._load = _hooker; +	// mark hooked time +	_hookedAt = new Date(); +} + +/** + * Unhook Node's require() to the original function + * + * @method unhook + */ +function _unhook() { +	// set the original loader +	Module._load = _load; +	// reset hooking time +	_hookedAt = undefined; +} + +/** + * Export a function that set the callback and return hook/unhook control functionality + * + * @function + * @param {Function} listener - require() listener + * @param {Boolean} [autohook=true] - optional flag telling if the hooking will be started automatically + * @return hook/unhook control function + */ +module.exports = function(listener, autohook) { +	if (typeof listener !== "function") { +		throw new Error("The hooking function should be set"); +	} +	// set the listener +	_listener = listener; +	// if autohook (by default), +	if (autohook !== false) { +		_hook(); +	} +	return { +		hookedAt: _hookedAt, +		hook: _hook, +		unhook: _unhook +	}; +}; diff --git a/node_modules/time-require/src/timeRequire.js b/node_modules/time-require/src/timeRequire.js new file mode 100644 index 000000000..0ba556fab --- /dev/null +++ b/node_modules/time-require/src/timeRequire.js @@ -0,0 +1,140 @@ +/** + * timeRequire - measure the time to load all the subsequnt modules by hoocking require() calls + * + * @author Ciprian Popa (cyparu) + * @since 0.0.1 + * @version 0.0.1 + */ + +"use strict"; + +var // setup vars +		requireData = [], +		write = process.stdout.write.bind(process.stdout), +		relative = require("path").relative, +		cwd = process.cwd(), +		// require hooker should be first module loaded so all the other requires should count as well +		/* jshint -W003 */ +		hook = require("./requireHook")(_hooker), +		table = require("text-table"), +		dateTime = require("date-time"), +		prettyMs = require("pretty-ms"), +		chalk = require("chalk"), +		// extra locals +		DEFAULT_COLUMNS = 80, +		BAR_CHAR = process.platform === "win32" ? "■" : "▇", +		sorted = hasArg("--sorted") || hasArg("--s"), +		treshold = (hasArg("--verbose") || hasArg("--V")) ? 0.0: 0.01, // TODO - configure treshold using CLI ? +		EXTRA_COLUMNS = sorted ? 24 : 20; + +function hasArg(arg) { +	return process.argv.indexOf(arg) !== -1; +} + +function pad(count, seq) { +	return (count > 1) ? new Array(count).join(seq) : ""; +} + +function log(str) { +	write(str + "\n", "utf8"); +} + +/** + * Callback/listener used by requireHook hook to collect all the modules in their loading order + */ +function _hooker(data) { +	var filename = relative(cwd, data.filename); +	// use the shortest name +	if (filename.length > data.filename) { +		filename = data.filename; +	} +	requireData.push({ +		order: requireData.length, // loading order +		time: data.startedIn, // time +		label: data.name + " (" + filename + ")" +//		name: data.name, +//		filename: filename +	}); +} + +function formatTable(tableData, totalTime) { +	var NAME_FILE_REX = /(.+)( \(.+\))/, +			maxColumns = process.stdout.columns || DEFAULT_COLUMNS, +			validCount = 0, +			longestRequire = tableData.reduce(function(acc, data) { +				var avg = data.time / totalTime; +				if (avg < treshold) { +					return acc; +				} +				validCount++; +				return Math.max(acc, data.label.length); +			}, 0), +			maxBarWidth = (longestRequire > maxColumns / 2) ? ((maxColumns - EXTRA_COLUMNS) / 2) : (maxColumns - (longestRequire + EXTRA_COLUMNS)), +			processedTableData = [], +			counter, maxOrderChars; + +	function shorten(name) { +		var nameLength = name.length, +				partLength, start, end; +		if (name.length < maxBarWidth) { +			return name; +		} +		partLength = Math.floor((maxBarWidth - 3) / 2); +		start = name.substr(0, partLength + 1); +		end = name.substr(nameLength - partLength); +		return start.trim() + "..." + end.trim(); +	} + +	function createBar(percentage) { +		var rounded = Math.round(percentage * 100); +		return ((rounded === 0) ? "0" : (pad(Math.ceil(maxBarWidth * percentage) + 1, BAR_CHAR) + " " + rounded)) + "%"; +	} + +	// sort the data if needed +	if (sorted) { +		tableData.sort(function(e1, e2) { +			return e2.time - e1.time; +		}); +	} +	// initialize the counter +	counter = 1; +	// get num ber of chars for padding +	maxOrderChars = tableData.length.toString().length; +	// push the header +	processedTableData.push(["#" + (sorted ? " [order]" : ""), "module", "time", "%"]); +	tableData.forEach(function(data) { +		var avg = data.time / totalTime, +				counterLabel, label, match; +		// slect just data over the threshold +		if (avg >= treshold) { +			counterLabel = counter++; +			// for sorted collumns show the order loading with padding +			if (sorted) { +				counterLabel += pad(maxOrderChars - data.order.toString().length + 1, " ") + " [" + data.order + "]"; +			} +			label = shorten(data.label); +			match = label.match(NAME_FILE_REX); +			if (match) { +				label = chalk.green(match[1]) + match[2]; +			} +			processedTableData.push([counterLabel, label, chalk.yellow(prettyMs(data.time)), chalk.blue(createBar(avg))]); +		} +	}); + +	return table(processedTableData, { +		align: ["r", "l", "r", "l"], +		stringLength: function(str) { +			return chalk.stripColor(str).length; +		} +	}); +} + +// hook process exit to display the report at the end +process.once("exit", function() { +	var startTime = hook.hookedAt, +			totalTime = Date.now() - startTime.getTime(); +	log("\n\n" + chalk.underline("Start time: " + chalk.yellow("(" + dateTime(startTime) + ")") + " [treshold=" + (treshold * 100) + "%" + (sorted ? ",sorted" : "") + "]")); +	log(formatTable(requireData, totalTime)); +	log(chalk.bold.blue("Total require(): ") + chalk.yellow(requireData.length)); +	log(chalk.bold.blue("Total time: ") + chalk.yellow(prettyMs(totalTime))); +});  | 
