UNPKG

noflo

Version:

Flow-Based Programming environment for JavaScript

509 lines (466 loc) 15.4 kB
(function() { var Component, EventEmitter, IP, ProcessInput, ProcessOutput, ports, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __hasProp = {}.hasOwnProperty, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; EventEmitter = require('events').EventEmitter; ports = require('./Ports'); IP = require('./IP'); Component = (function(_super) { __extends(Component, _super); Component.prototype.description = ''; Component.prototype.icon = null; function Component(options) { this.error = __bind(this.error, this); if (!options) { options = {}; } if (!options.inPorts) { options.inPorts = {}; } if (options.inPorts instanceof ports.InPorts) { this.inPorts = options.inPorts; } else { this.inPorts = new ports.InPorts(options.inPorts); } if (!options.outPorts) { options.outPorts = {}; } if (options.outPorts instanceof ports.OutPorts) { this.outPorts = options.outPorts; } else { this.outPorts = new ports.OutPorts(options.outPorts); } if (options.icon) { this.icon = options.icon; } if (options.description) { this.description = options.description; } this.started = false; this.load = 0; this.ordered = false; this.autoOrdering = false; this.outputQ = []; this.activateOnInput = true; this.forwardBrackets = { "in": ['out', 'error'] }; this.bracketCounter = {}; this.dropEmptyBrackets = ['error']; if ('ordered' in options) { this.ordered = options.ordered; } if ('activateOnInput' in options) { this.activateOnInput = options.activateOnInput; } if ('forwardBrackets' in options) { this.forwardBrackets = options.forwardBrackets; } if ('dropEmptyBrackets' in options) { this.dropEmptyBrackets = options.dropEmptyBrackets; } if (typeof options.process === 'function') { this.process(options.process); } } Component.prototype.getDescription = function() { return this.description; }; Component.prototype.isReady = function() { return true; }; Component.prototype.isSubgraph = function() { return false; }; Component.prototype.setIcon = function(icon) { this.icon = icon; return this.emit('icon', this.icon); }; Component.prototype.getIcon = function() { return this.icon; }; Component.prototype.error = function(e, groups, errorPort) { var group, _i, _j, _len, _len1; if (groups == null) { groups = []; } if (errorPort == null) { errorPort = 'error'; } if (this.outPorts[errorPort] && (this.outPorts[errorPort].isAttached() || !this.outPorts[errorPort].isRequired())) { for (_i = 0, _len = groups.length; _i < _len; _i++) { group = groups[_i]; this.outPorts[errorPort].beginGroup(group); } this.outPorts[errorPort].send(e); for (_j = 0, _len1 = groups.length; _j < _len1; _j++) { group = groups[_j]; this.outPorts[errorPort].endGroup(); } this.outPorts[errorPort].disconnect(); return; } throw e; }; Component.prototype.shutdown = function() { return this.started = false; }; Component.prototype.start = function() { this.started = true; return this.started; }; Component.prototype.isStarted = function() { return this.started; }; Component.prototype.prepareForwarding = function() { var inPort, outPort, outPorts, tmp, _i, _j, _len, _len1, _ref, _ref1; _ref = this.forwardBrackets; for (inPort in _ref) { outPorts = _ref[inPort]; if (!(inPort in this.inPorts.ports)) { delete this.forwardBrackets[inPort]; continue; } tmp = []; for (_i = 0, _len = outPorts.length; _i < _len; _i++) { outPort = outPorts[_i]; if (outPort in this.outPorts.ports) { tmp.push(outPort); } } if (tmp.length === 0) { delete this.forwardBrackets[inPort]; } else { this.forwardBrackets[inPort] = tmp; this.bracketCounter[inPort] = 0; } } tmp = []; _ref1 = this.dropEmptyBrackets; for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { outPort = _ref1[_j]; if (outPort in this.outPorts.ports) { tmp.push(outPort); } } return this.dropEmptyBrackets = tmp; }; Component.prototype.process = function(handle) { var name, port, _fn, _ref; if (typeof handle !== 'function') { throw new Error("Process handler must be a function"); } if (!this.inPorts) { throw new Error("Component ports must be defined before process function"); } this.prepareForwarding(); this.handle = handle; _ref = this.inPorts.ports; _fn = (function(_this) { return function(name, port) { if (!port.name) { port.name = name; } return port.on('ip', function(ip) { return _this.handleIP(ip, port); }); }; })(this); for (name in _ref) { port = _ref[name]; _fn(name, port); } return this; }; Component.prototype.handleIP = function(ip, port) { var entry, haveData, i, input, ips, outPort, output, outputEntry, result, _i, _ip, _j, _k, _len, _len1, _ref, _ref1; if (ip.type === 'openBracket') { if (!this.autoOrdering) { this.autoOrdering = true; } this.bracketCounter[port.name]++; } if (port.name in this.forwardBrackets && (ip.type === 'openBracket' || ip.type === 'closeBracket')) { outputEntry = { __resolved: ip.type === 'closeBracket' || !this.dropEmptyBrackets.length, __forwarded: true, __type: ip.type, __scope: ip.scope }; _ref = this.forwardBrackets[port.name]; for (_i = 0, _len = _ref.length; _i < _len; _i++) { outPort = _ref[_i]; if (!(outPort in outputEntry)) { outputEntry[outPort] = []; } outputEntry[outPort].push(ip); } port.buffer.pop(); if (ip.type === 'closeBracket' && this.dropEmptyBrackets.length) { haveData = []; for (i = _j = _ref1 = this.outputQ.length - 1; _ref1 <= 0 ? _j <= 0 : _j >= 0; i = _ref1 <= 0 ? ++_j : --_j) { entry = this.outputQ[i]; if ('__forwarded' in entry) { if (entry.__type === 'openBracket' && !entry.__resolved && entry.__scope === ip.scope) { for (port in entry) { ips = entry[port]; if (haveData.indexOf(port) === -1 && this.dropEmptyBrackets.indexOf(port) !== -1) { delete entry[port]; delete outputEntry[port]; } } entry.__resolved = true; break; } } else { for (port in entry) { ips = entry[port]; if (port.indexOf('__') === 0 || haveData.indexOf(port) >= 0) { continue; } for (_k = 0, _len1 = ips.length; _k < _len1; _k++) { _ip = ips[_k]; if (_ip.scope === ip.scope) { haveData.push(port); break; } } } } } } this.outputQ.push(outputEntry); this.processOutputQueue(); return; } if (!port.options.triggering) { return; } result = {}; input = new ProcessInput(this.inPorts, ip, this, port, result); output = new ProcessOutput(this.outPorts, ip, this, result); this.load++; return this.handle(input, output, function() { return output.done(); }); }; Component.prototype.processOutputQueue = function() { var bracketsClosed, ip, ips, name, port, result, _i, _len, _ref; while (this.outputQ.length > 0) { result = this.outputQ[0]; if (!result.__resolved) { break; } for (port in result) { ips = result[port]; if (port.indexOf('__') === 0) { continue; } for (_i = 0, _len = ips.length; _i < _len; _i++) { ip = ips[_i]; if (ip.type === 'closeBracket') { this.bracketCounter[port]--; } this.outPorts[port].sendIP(ip); } } this.outputQ.shift(); } bracketsClosed = true; _ref = this.outPorts.ports; for (name in _ref) { port = _ref[name]; if (this.bracketCounter[port] !== 0) { bracketsClosed = false; break; } } if (bracketsClosed) { return this.autoOrdering = false; } }; return Component; })(EventEmitter); exports.Component = Component; ProcessInput = (function() { function ProcessInput(ports, ip, nodeInstance, port, result) { this.ports = ports; this.ip = ip; this.nodeInstance = nodeInstance; this.port = port; this.result = result; this.scope = this.ip.scope; } ProcessInput.prototype.activate = function() { this.result.__resolved = false; if (this.nodeInstance.ordered || this.nodeInstance.autoOrdering) { return this.nodeInstance.outputQ.push(this.result); } }; ProcessInput.prototype.has = function(port) { var args, res, _i, _len; if (port == null) { port = 'in'; } args = arguments.length === 0 ? [port] : arguments; res = true; for (_i = 0, _len = args.length; _i < _len; _i++) { port = args[_i]; res && (res = this.ports[port].ready(this.scope)); } return res; }; ProcessInput.prototype.get = function(port) { var args, res; if (port == null) { port = 'in'; } args = arguments.length === 0 ? [port] : arguments; if ((this.nodeInstance.ordered || this.nodeInstance.autoOrdering) && this.nodeInstance.activateOnInput && !('__resolved' in this.result)) { this.activate(); } res = (function() { var _i, _len, _results; _results = []; for (_i = 0, _len = args.length; _i < _len; _i++) { port = args[_i]; _results.push(this.ports[port].get(this.scope)); } return _results; }).call(this); if (args.length === 1) { return res[0]; } else { return res; } }; ProcessInput.prototype.getData = function(port) { var args, ip, ips, _i, _len, _ref, _ref1, _results; if (port == null) { port = 'in'; } args = arguments.length === 0 ? [port] : arguments; ips = this.get.apply(this, args); if (args.length === 1) { return (_ref = ips != null ? ips.data : void 0) != null ? _ref : void 0; } _results = []; for (_i = 0, _len = ips.length; _i < _len; _i++) { ip = ips[_i]; _results.push((_ref1 = ip != null ? ip.data : void 0) != null ? _ref1 : void 0); } return _results; }; return ProcessInput; })(); ProcessOutput = (function() { function ProcessOutput(ports, ip, nodeInstance, result) { this.ports = ports; this.ip = ip; this.nodeInstance = nodeInstance; this.result = result; this.scope = this.ip.scope; } ProcessOutput.prototype.activate = function() { this.result.__resolved = false; if (this.nodeInstance.ordered || this.nodeInstance.autoOrdering) { return this.nodeInstance.outputQ.push(this.result); } }; ProcessOutput.prototype.isError = function(err) { return err instanceof Error || Array.isArray(err) && err.length > 0 && err[0] instanceof Error; }; ProcessOutput.prototype.error = function(err) { var e, multiple, _i, _j, _len, _len1, _results; multiple = Array.isArray(err); if (!multiple) { err = [err]; } if ('error' in this.ports && (this.ports.error.isAttached() || !this.ports.error.isRequired())) { if (multiple) { this.sendIP('error', new IP('openBracket')); } for (_i = 0, _len = err.length; _i < _len; _i++) { e = err[_i]; this.sendIP('error', e); } if (multiple) { return this.sendIP('error', new IP('closeBracket')); } } else { _results = []; for (_j = 0, _len1 = err.length; _j < _len1; _j++) { e = err[_j]; throw e; } return _results; } }; ProcessOutput.prototype.sendIP = function(port, packet) { var ip; if (typeof packet !== 'object' || IP.types.indexOf(packet.type) === -1) { ip = new IP('data', packet); } else { ip = packet; } if (this.scope !== null && ip.scope === null) { ip.scope = this.scope; } if (this.nodeInstance.ordered || this.nodeInstance.autoOrdering) { if (!(port in this.result)) { this.result[port] = []; } return this.result[port].push(ip); } else { return this.nodeInstance.outPorts[port].sendIP(ip); } }; ProcessOutput.prototype.send = function(outputMap) { var packet, port, _results; if ((this.nodeInstance.ordered || this.nodeInstance.autoOrdering) && !('__resolved' in this.result)) { this.activate(); } if (this.isError(outputMap)) { return this.error(outputMap); } _results = []; for (port in outputMap) { packet = outputMap[port]; _results.push(this.sendIP(port, packet)); } return _results; }; ProcessOutput.prototype.sendDone = function(outputMap) { this.send(outputMap); return this.done(); }; ProcessOutput.prototype.pass = function(data, options) { var key, val; if (options == null) { options = {}; } if (!('out' in this.ports)) { throw new Error('output.pass() requires port "out" to be present'); } for (key in options) { val = options[key]; this.ip[key] = val; } this.ip.data = data; this.sendIP('out', this.ip); return this.done(); }; ProcessOutput.prototype.done = function(error) { if (error) { this.error(error); } if (this.nodeInstance.ordered || this.nodeInstance.autoOrdering) { this.result.__resolved = true; this.nodeInstance.processOutputQueue(); } return this.nodeInstance.load--; }; return ProcessOutput; })(); }).call(this);