dataflo.ws
Version:
Zero-code JSON config-based dataflow engine for Node, PhoneGap and browser.
344 lines (305 loc) • 9.47 kB
JavaScript
var util = require ('util');
Object.PLATFORM_NATIVE_TYPES = {
// Buffer seems to be the only custom type in the Node core
'Buffer': true
};
Object.lookUpCustomType = function (obj) {
var name = obj && obj.constructor && obj.constructor.name;
if (name && name in Object.PLATFORM_NATIVE_TYPES) {
return name;
}
};
/**
* Get the type of any object.
* Usage:
* Object.typeOf([ 1, 2, 3 ]); // 'Array'
* Object.typeOf(null); // 'Null'
* Object.typeOf(new Buffer('')); // 'Buffer'
*/
Object.typeOf = function (obj) {
return Object.lookUpCustomType(obj) ||
Object.prototype.toString.call(obj).slice(8, -1);
};
/**
* Safe and universal type check.
* Usage:
* Object.is('Number', 4); // true
* Object.is('Undefined', undefined); // true
*/
Object.is = function (type, obj) {
return type == Object.typeOf(obj);
};
function isEmpty(obj) {
var type = Object.typeOf(obj);
return (
('Undefined' == type) ||
('Null' == type) ||
('Boolean' == type && false === obj) ||
('Number' == type && (0 === obj || isNaN(obj))) ||
('String' == type && 0 == obj.length) ||
('Array' == type && 0 == obj.length) ||
('Object' == type && 0 == Object.keys(obj).length)
);
}
var Project;
var projectRoot;
var projectInstance;
if (!util.inherits) {
util.inherits = function (ctor, superCtor) {
ctor.super_ = superCtor;
ctor.prototype = Object.create (superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}});
};
// http://stackoverflow.com/questions/13201775/looking-for-a-javascript-implementation-of-nodes-util-inherits
// B.prototype = Object.create(A.prototype); B.prototype.constructor = B;
}
if (!util.extend) {
util.extend = function extend () {
var hasOwnProperty = Object.prototype.hasOwnProperty;
// copy reference to target object
var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options, name, src, copy;
// Handle a deep copy situation
if (typeof target === "boolean") {
deep = target;
target = arguments[1] || {};
// skip the boolean and the target
i = 2;
}
// Handle case when target is a string or something (possible in deep copy)
if (typeof target !== "object" && !typeof target === 'function')
target = {};
var isPlainObject = function(obj) {
// Must be an Object.
// Because of IE, we also have to check the presence of the constructor property.
// Make sure that DOM nodes and window objects don't pass through, as well
if (!obj || !Object.is('Object', obj) || obj.nodeType || obj.setInterval)
return false;
var has_own_constructor = hasOwnProperty.call(obj, "constructor");
var has_is_property_of_method = hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf");
// Not own constructor property must be Object
if (obj.constructor && !has_own_constructor && !has_is_property_of_method)
return false;
// Own properties are enumerated firstly, so to speed up,
// if last one is own, then all properties are own.
var last_key;
for (var key in obj)
last_key = key;
return typeof last_key === "undefined" || hasOwnProperty.call(obj, last_key);
};
for (; i < length; i++) {
// Only deal with non-null/undefined values
if ((options = arguments[i]) !== null) {
// Extend the base object
for (name in options) {
src = target[name];
copy = options[name];
// Prevent never-ending loop
if (target === copy)
continue;
// Recurse if we're merging object literal values or arrays
if (deep && copy && (isPlainObject(copy) || Array.isArray(copy))) {
var clone = src && (isPlainObject(src) || Array.isArray(src)) ? src : Array.isArray(copy) ? [] : {};
// Never move original objects, clone them
target[name] = extend(deep, clone, copy);
// Don't bring in undefined values
} else if (typeof copy !== "undefined")
target[name] = copy;
}
}
}
// Return the modified object
return target;
}
}
if (!util.shallowMerge) {
util.shallowMerge = function (dest, src, filter) {
Object.keys(src).forEach(function (key) {
if ((!filter || -1 != filter.indexOf(key)) && null == dest[key]) {
dest[key] = src[key];
}
});
return dest;
};
}
if (!util.clone) {
util.clone = function(object) {
var result;
if (object.constructor === Array) {
result = object.map(function(item) {
return util.clone(item);
});
} else if (object.constructor === Object) {
result = {};
util.extend(result, object);
} else {
result = object;
}
return result;
}
}
try {
if (process.pid) {
global.$isClientSide = false;
global.$isServerSide = true;
global.$mainModule = process.mainModule;
global.$scope = 'process.mainModule';
global.$stash = {};
global.$isPhoneGap = false;
global.$global = global;
} else {
throw 'WTF?';
}
} catch (e) {
window.$isClientSide = true;
window.$isServerSide = false;
window.$mainModule = window;
window.$scope = 'window';
window.$stash = {};
window.$global = window;
try {
if (window.PhoneGap || window.Cordova || window.cordova) window.$isPhoneGap = true;
} catch (e) {
console.log (e);
window.$isPhoneGap = false;
}
}
Number.prototype.hours = Number.prototype.hour
= function () {return this * 60 * 60 * 1e3}
Number.prototype.minutes = Number.prototype.minute
= function () {return this * 60 * 1e3}
Number.prototype.seconds = Number.prototype.second
= function () {return this * 1e3}
Number.prototype.times = function (cb) {
var a = [];
for (var i = 0; i < this; i++)
a[i] = cb (i);
return a;
}
// especially for stupid loaders
if (0)
module.exports = {};
module.exports.$global = $global;
// overwrite subject with values from object (merge object with subject)
var mergeObjects = module.exports.mergeObjects = function (object, subjectParent, subjectKey) {
// subject parent here for js's lack of pass by reference
if (subjectParent[subjectKey] === void 0)
subjectParent[subjectKey] = {};
var subject = subjectParent[subjectKey];
for (var objectField in object) {
subject[objectField] = object[objectField];
}
};
var getByPath = module.exports.getByPath = function (path, origin) {
var value = origin || $global;
var scope, key;
var validPath = path.split('.').every(function (prop) {
scope = value;
key = prop;
if (null == scope) {
// break
return false;
} else {
value = scope[key];
return true;
}
});
return validPath && { value: value, scope: scope, key: key };
};
var pathToVal = module.exports.pathToVal = function (dict, path, value, method) {
var chunks = 'string' == typeof path ? path.split('.') : path;
var chunk = chunks[0];
var rest = chunks.slice(1);
if (chunks.length == 1) {
var oldValue = dict[chunk];
if (value !== undefined) {
if (method !== undefined) {
method(value, dict, chunk);
} else {
dict[chunk] = value;
}
}
return oldValue;
}
return pathToVal(dict[chunk], rest, value, method);
};
String.prototype.interpolate = function (dict, marks) {
if (!marks)
marks = {};
marks.start = marks.start || '{';
marks.end = marks.end || '}';
marks.path = marks.path || '.';
marks.typeSafe = marks.typeSafe || '$';
marks.typeRaw = marks.typeRaw || '*';
// TODO: escape character range delims
var re = new RegExp([
'[', marks.start, ']',
'([', marks.typeSafe, marks.typeRaw, '])',
'([^', marks.end, ']+)',
'[', marks.end, ']'
].join(''), 'g');
var startRe = new RegExp([
'[', marks.start, ']',
'([', marks.typeSafe, marks.typeRaw, '])'
].join(''), 'g');
var values = [];
var replacedStr = this.replace(re, function (_, varType, varPath) {
if (varPath.indexOf(marks.path) > -1) {
var value = pathToVal(dict, varPath);
} else {
value = dict[varPath];
}
if (isEmpty(value) && varType == marks.typeSafe) {
value = undefined;
}
values.push(value);
return value;
});
if (values.some(function (v) { return (typeof v === "undefined"); })) {
return undefined;
}
if (values.length === 1 && (values[0] + '') === replacedStr) {
return values[0];
}
return replacedStr;
};
/**
* [waitAll wait all events to complete]
* @param {[type]} events array of event arrays: [[subject, eventName, description]]
* @param {Function} callback called after all events handled
* @return {[type]} [description]
*/
module.exports.waitAll = function waitAll (events, callback) {
var remaining = [];
function _listener (eventName) {
remaining.some (function (remainingName, idx) {
if (remainingName == eventName) {
remaining.splice (idx, 1);
return true;
}
})
// console.log ("wait for " + remaining.length + " more: " + remaining.join (', '));
if (!remaining.length)
callback();
}
events.forEach (function (event) {
var subject = event[0];
var eventName = event[1];
var eventLogName = eventName + ' ' + event[2];
remaining.push (eventLogName);
if (typeof subject === "function") {
subject (_listener.bind ($global, eventLogName));
} else {
if (subject.addEventListener) {
subject.addEventListener (eventName, _listener.bind (subject, eventLogName), false);
} else {
subject.on (eventName, _listener.bind (subject, eventLogName), false);
}
}
});
}
module.exports.isEmpty = isEmpty;