123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586 |
- // Load modules
- var Fs = require('fs');
- var Escape = require('./escape');
- // Declare internals
- var internals = {};
- // Clone object or array
- exports.clone = function (obj, seen) {
- if (typeof obj !== 'object' ||
- obj === null) {
- return obj;
- }
- seen = seen || { orig: [], copy: [] };
- var lookup = seen.orig.indexOf(obj);
- if (lookup !== -1) {
- return seen.copy[lookup];
- }
- var newObj = (obj instanceof Array) ? [] : {};
- seen.orig.push(obj);
- seen.copy.push(newObj);
- for (var i in obj) {
- if (obj.hasOwnProperty(i)) {
- if (obj[i] instanceof Buffer) {
- newObj[i] = new Buffer(obj[i]);
- }
- else if (obj[i] instanceof Date) {
- newObj[i] = new Date(obj[i].getTime());
- }
- else if (obj[i] instanceof RegExp) {
- var flags = '' + (obj[i].global ? 'g' : '') + (obj[i].ignoreCase ? 'i' : '') + (obj[i].multiline ? 'm' : '');
- newObj[i] = new RegExp(obj[i].source, flags);
- }
- else {
- newObj[i] = exports.clone(obj[i], seen);
- }
- }
- }
- return newObj;
- };
- // Merge all the properties of source into target, source wins in conflic, and by default null and undefined from source are applied
- exports.merge = function (target, source, isNullOverride /* = true */, isMergeArrays /* = true */) {
- exports.assert(target && typeof target == 'object', 'Invalid target value: must be an object');
- exports.assert(source === null || source === undefined || typeof source === 'object', 'Invalid source value: must be null, undefined, or an object');
- if (!source) {
- return target;
- }
- if (source instanceof Array) {
- exports.assert(target instanceof Array, 'Cannot merge array onto an object');
- if (isMergeArrays === false) { // isMergeArrays defaults to true
- target.length = 0; // Must not change target assignment
- }
- for (var i = 0, il = source.length; i < il; ++i) {
- target.push(source[i]);
- }
- return target;
- }
- var keys = Object.keys(source);
- for (var k = 0, kl = keys.length; k < kl; ++k) {
- var key = keys[k];
- var value = source[key];
- if (value &&
- typeof value === 'object') {
- if (!target[key] ||
- typeof target[key] !== 'object') {
- target[key] = exports.clone(value);
- }
- else {
- exports.merge(target[key], source[key], isNullOverride, isMergeArrays);
- }
- }
- else {
- if (value !== null && value !== undefined) { // Explicit to preserve empty strings
- target[key] = value;
- }
- else if (isNullOverride !== false) { // Defaults to true
- target[key] = value;
- }
- }
- }
- return target;
- };
- // Apply options to a copy of the defaults
- exports.applyToDefaults = function (defaults, options) {
- exports.assert(defaults && typeof defaults == 'object', 'Invalid defaults value: must be an object');
- exports.assert(!options || options === true || typeof options === 'object', 'Invalid options value: must be true, falsy or an object');
- if (!options) { // If no options, return null
- return null;
- }
- var copy = exports.clone(defaults);
- if (options === true) { // If options is set to true, use defaults
- return copy;
- }
- return exports.merge(copy, options, false, false);
- };
- // Remove duplicate items from array
- exports.unique = function (array, key) {
- var index = {};
- var result = [];
- for (var i = 0, il = array.length; i < il; ++i) {
- var id = (key ? array[i][key] : array[i]);
- if (index[id] !== true) {
- result.push(array[i]);
- index[id] = true;
- }
- }
- return result;
- };
- // Convert array into object
- exports.mapToObject = function (array, key) {
- if (!array) {
- return null;
- }
- var obj = {};
- for (var i = 0, il = array.length; i < il; ++i) {
- if (key) {
- if (array[i][key]) {
- obj[array[i][key]] = true;
- }
- }
- else {
- obj[array[i]] = true;
- }
- }
- return obj;
- };
- // Find the common unique items in two arrays
- exports.intersect = function (array1, array2, justFirst) {
- if (!array1 || !array2) {
- return [];
- }
- var common = [];
- var hash = (array1 instanceof Array ? exports.mapToObject(array1) : array1);
- var found = {};
- for (var i = 0, il = array2.length; i < il; ++i) {
- if (hash[array2[i]] && !found[array2[i]]) {
- if (justFirst) {
- return array2[i];
- }
- common.push(array2[i]);
- found[array2[i]] = true;
- }
- }
- return (justFirst ? null : common);
- };
- // Find which keys are present
- exports.matchKeys = function (obj, keys) {
- var matched = [];
- for (var i = 0, il = keys.length; i < il; ++i) {
- if (obj.hasOwnProperty(keys[i])) {
- matched.push(keys[i]);
- }
- }
- return matched;
- };
- // Flatten array
- exports.flatten = function (array, target) {
- var result = target || [];
- for (var i = 0, il = array.length; i < il; ++i) {
- if (Array.isArray(array[i])) {
- exports.flatten(array[i], result);
- }
- else {
- result.push(array[i]);
- }
- }
- return result;
- };
- // Remove keys
- exports.removeKeys = function (object, keys) {
- for (var i = 0, il = keys.length; i < il; i++) {
- delete object[keys[i]];
- }
- };
- // Convert an object key chain string ('a.b.c') to reference (object[a][b][c])
- exports.reach = function (obj, chain) {
- var path = chain.split('.');
- var ref = obj;
- for (var i = 0, il = path.length; i < il; ++i) {
- if (ref) {
- ref = ref[path[i]];
- }
- }
- return ref;
- };
- // Inherits a selected set of methods from an object, wrapping functions in asynchronous syntax and catching errors
- exports.inheritAsync = function (self, obj, keys) {
- keys = keys || null;
- for (var i in obj) {
- if (obj.hasOwnProperty(i)) {
- if (keys instanceof Array &&
- keys.indexOf(i) < 0) {
- continue;
- }
- self.prototype[i] = (function (fn) {
- return function (next) {
- var result = null;
- try {
- result = fn();
- }
- catch (err) {
- return next(err);
- }
- return next(null, result);
- };
- })(obj[i]);
- }
- }
- };
- exports.formatStack = function (stack) {
- var trace = [];
- for (var i = 0, il = stack.length; i < il; ++i) {
- var item = stack[i];
- trace.push([item.getFileName(), item.getLineNumber(), item.getColumnNumber(), item.getFunctionName(), item.isConstructor()]);
- }
- return trace;
- };
- exports.formatTrace = function (trace) {
- var display = [];
- for (var i = 0, il = trace.length; i < il; ++i) {
- var row = trace[i];
- display.push((row[4] ? 'new ' : '') + row[3] + ' (' + row[0] + ':' + row[1] + ':' + row[2] + ')');
- }
- return display;
- };
- exports.callStack = function (slice) {
- // http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
- var v8 = Error.prepareStackTrace;
- Error.prepareStackTrace = function (err, stack) {
- return stack;
- };
- var capture = {};
- Error.captureStackTrace(capture, arguments.callee);
- var stack = capture.stack;
- Error.prepareStackTrace = v8;
- var trace = exports.formatStack(stack);
- if (slice) {
- return trace.slice(slice);
- }
- return trace;
- };
- exports.displayStack = function (slice) {
- var trace = exports.callStack(slice === undefined ? 1 : slice + 1);
- return exports.formatTrace(trace);
- };
- exports.abortThrow = false;
- exports.abort = function (message, hideStack) {
- if (process.env.NODE_ENV === 'test' || exports.abortThrow === true) {
- throw new Error(message || 'Unknown error');
- }
- var stack = '';
- if (!hideStack) {
- stack = exports.displayStack(1).join('\n\t');
- }
- console.log('ABORT: ' + message + '\n\t' + stack);
- process.exit(1);
- };
- exports.assert = function (condition /*, msg1, msg2, msg3 */) {
- if (condition) {
- return;
- }
- var msgs = Array.prototype.slice.call(arguments, 1);
- msgs = msgs.map(function (msg) {
- return typeof msg === 'string' ? msg : msg instanceof Error ? msg.message : JSON.stringify(msg);
- });
- throw new Error(msgs.join(' ') || 'Unknown error');
- };
- exports.loadDirModules = function (path, excludeFiles, target) { // target(filename, name, capName)
- var exclude = {};
- for (var i = 0, il = excludeFiles.length; i < il; ++i) {
- exclude[excludeFiles[i] + '.js'] = true;
- }
- var files = Fs.readdirSync(path);
- for (i = 0, il = files.length; i < il; ++i) {
- var filename = files[i];
- if (/\.js$/.test(filename) &&
- !exclude[filename]) {
- var name = filename.substr(0, filename.lastIndexOf('.'));
- var capName = name.charAt(0).toUpperCase() + name.substr(1).toLowerCase();
- if (typeof target !== 'function') {
- target[capName] = require(path + '/' + name);
- }
- else {
- target(path + '/' + name, name, capName);
- }
- }
- }
- };
- exports.rename = function (obj, from, to) {
- obj[to] = obj[from];
- delete obj[from];
- };
- exports.Timer = function () {
- this.reset();
- };
- exports.Timer.prototype.reset = function () {
- this.ts = Date.now();
- };
- exports.Timer.prototype.elapsed = function () {
- return Date.now() - this.ts;
- };
- // Load and parse package.json process root or given directory
- exports.loadPackage = function (dir) {
- var result = {};
- var filepath = (dir || process.env.PWD) + '/package.json';
- if (Fs.existsSync(filepath)) {
- try {
- result = JSON.parse(Fs.readFileSync(filepath));
- }
- catch (e) { }
- }
- return result;
- };
- // Escape string for Regex construction
- exports.escapeRegex = function (string) {
- // Escape ^$.*+-?=!:|\/()[]{},
- return string.replace(/[\^\$\.\*\+\-\?\=\!\:\|\\\/\(\)\[\]\{\}\,]/g, '\\$&');
- };
- // Return an error as first argument of a callback
- exports.toss = function (condition /*, [message], next */) {
- var message = (arguments.length === 3 ? arguments[1] : '');
- var next = (arguments.length === 3 ? arguments[2] : arguments[1]);
- var err = (message instanceof Error ? message : (message ? new Error(message) : (condition instanceof Error ? condition : new Error())));
- if (condition instanceof Error ||
- !condition) {
- return next(err);
- }
- };
- // Base64url (RFC 4648) encode
- exports.base64urlEncode = function (value) {
- return (new Buffer(value, 'binary')).toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/\=/g, '');
- };
- // Base64url (RFC 4648) decode
- exports.base64urlDecode = function (encoded) {
- if (encoded &&
- !encoded.match(/^[\w\-]*$/)) {
- return new Error('Invalid character');
- }
- try {
- return (new Buffer(encoded.replace(/-/g, '+').replace(/:/g, '/'), 'base64')).toString('binary');
- }
- catch (err) {
- return err;
- }
- };
- // Escape attribute value for use in HTTP header
- exports.escapeHeaderAttribute = function (attribute) {
- // Allowed value characters: !#$%&'()*+,-./:;<=>?@[]^_`{|}~ and space, a-z, A-Z, 0-9, \, "
- exports.assert(attribute.match(/^[ \w\!#\$%&'\(\)\*\+,\-\.\/\:;<\=>\?@\[\]\^`\{\|\}~\"\\]*$/), 'Bad attribute value (' + attribute + ')');
- return attribute.replace(/\\/g, '\\\\').replace(/\"/g, '\\"'); // Escape quotes and slash
- };
- exports.escapeHtml = function (string) {
- return Escape.escapeHtml(string);
- };
- exports.escapeJavaScript = function (string) {
- return Escape.escapeJavaScript(string);
- };
- /*
- var event = {
- timestamp: now.getTime(),
- tags: ['tag'],
- data: { some: 'data' }
- };
- */
- exports.consoleFunc = console.log;
- exports.printEvent = function (event) {
- var pad = function (value) {
- return (value < 10 ? '0' : '') + value;
- };
- var now = new Date(event.timestamp);
- var timestring = (now.getYear() - 100).toString() +
- pad(now.getMonth() + 1) +
- pad(now.getDate()) +
- '/' +
- pad(now.getHours()) +
- pad(now.getMinutes()) +
- pad(now.getSeconds()) +
- '.' +
- now.getMilliseconds();
- var data = event.data;
- if (typeof event.data !== 'string') {
- try {
- data = JSON.stringify(event.data);
- }
- catch (e) {
- data = 'JSON Error: ' + e.message;
- }
- }
- var output = timestring + ', ' + event.tags[0] + ', ' + data;
- exports.consoleFunc(output);
- };
- exports.nextTick = function (callback) {
- return function () {
- var args = arguments;
- process.nextTick(function () {
- callback.apply(null, args);
- });
- };
- };
|