noflo
Version:
Flow-Based Programming environment for JavaScript
1,162 lines (1,095 loc) • 36.9 kB
JavaScript
(function() {
var Component, EventEmitter, IP, ProcessContext, ProcessInput, ProcessOutput, debug, debugBrackets, debugSend, ports,
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
extend = 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; },
hasProp = {}.hasOwnProperty,
slice = [].slice;
EventEmitter = require('events').EventEmitter;
ports = require('./Ports');
IP = require('./IP');
debug = require('debug')('noflo:component');
debugBrackets = require('debug')('noflo:component:brackets');
debugSend = require('debug')('noflo:component:send');
Component = (function(superClass) {
extend(Component, superClass);
Component.prototype.description = '';
Component.prototype.icon = null;
function Component(options) {
this.error = bind(this.error, this);
var ref, ref1, ref2;
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 = (ref = options.ordered) != null ? ref : false;
this.autoOrdering = (ref1 = options.autoOrdering) != null ? ref1 : null;
this.outputQ = [];
this.bracketContext = {
"in": {},
out: {}
};
this.activateOnInput = (ref2 = options.activateOnInput) != null ? ref2 : true;
this.forwardBrackets = {
"in": ['out', 'error']
};
if ('forwardBrackets' in options) {
this.forwardBrackets = options.forwardBrackets;
}
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, scope) {
var group, i, j, len1, len2;
if (groups == null) {
groups = [];
}
if (errorPort == null) {
errorPort = 'error';
}
if (scope == null) {
scope = null;
}
if (this.outPorts[errorPort] && (this.outPorts[errorPort].isAttached() || !this.outPorts[errorPort].isRequired())) {
for (i = 0, len1 = groups.length; i < len1; i++) {
group = groups[i];
this.outPorts[errorPort].openBracket(group, {
scope: scope
});
}
this.outPorts[errorPort].data(e, {
scope: scope
});
for (j = 0, len2 = groups.length; j < len2; j++) {
group = groups[j];
this.outPorts[errorPort].closeBracket(group, {
scope: scope
});
}
return;
}
throw e;
};
Component.prototype.setUp = function(callback) {
return callback();
};
Component.prototype.tearDown = function(callback) {
return callback();
};
Component.prototype.start = function(callback) {
if (this.isStarted()) {
return callback();
}
return this.setUp((function(_this) {
return function(err) {
if (err) {
return callback(err);
}
_this.started = true;
_this.emit('start');
return callback(null);
};
})(this));
};
Component.prototype.shutdown = function(callback) {
var finalize;
finalize = (function(_this) {
return function() {
var inPort, inPorts, portName;
inPorts = _this.inPorts.ports || _this.inPorts;
for (portName in inPorts) {
inPort = inPorts[portName];
if (typeof inPort.clear !== 'function') {
continue;
}
inPort.clear();
}
_this.bracketContext = {
"in": {},
out: {}
};
if (!_this.isStarted()) {
return callback();
}
_this.started = false;
_this.emit('end');
return callback();
};
})(this);
return this.tearDown((function(_this) {
return function(err) {
var checkLoad;
if (err) {
return callback(err);
}
if (_this.load > 0) {
checkLoad = function(load) {
if (load > 0) {
return;
}
this.removeListener('deactivate', checkLoad);
return finalize();
};
_this.on('deactivate', checkLoad);
return;
}
return finalize();
};
})(this));
};
Component.prototype.isStarted = function() {
return this.started;
};
Component.prototype.prepareForwarding = function() {
var i, inPort, len1, outPort, outPorts, ref, results, tmp;
ref = this.forwardBrackets;
results = [];
for (inPort in ref) {
outPorts = ref[inPort];
if (!(inPort in this.inPorts.ports)) {
delete this.forwardBrackets[inPort];
continue;
}
tmp = [];
for (i = 0, len1 = outPorts.length; i < len1; i++) {
outPort = outPorts[i];
if (outPort in this.outPorts.ports) {
tmp.push(outPort);
}
}
if (tmp.length === 0) {
results.push(delete this.forwardBrackets[inPort]);
} else {
results.push(this.forwardBrackets[inPort] = tmp);
}
}
return results;
};
Component.prototype.isLegacy = function() {
if (this.handle) {
return false;
}
if (this._wpData) {
return false;
}
return true;
};
Component.prototype.process = function(handle) {
var fn, name, port, 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.isForwardingInport = function(port) {
var portName;
if (typeof port === 'string') {
portName = port;
} else {
portName = port.name;
}
if (portName in this.forwardBrackets) {
return true;
}
return false;
};
Component.prototype.isForwardingOutport = function(inport, outport) {
var inportName, outportName;
if (typeof inport === 'string') {
inportName = inport;
} else {
inportName = inport.name;
}
if (typeof outport === 'string') {
outportName = outport;
} else {
outportName = outport.name;
}
if (!this.forwardBrackets[inportName]) {
return false;
}
if (this.forwardBrackets[inportName].indexOf(outportName) !== -1) {
return true;
}
return false;
};
Component.prototype.isOrdered = function() {
if (this.ordered) {
return true;
}
if (this.autoOrdering) {
return true;
}
return false;
};
Component.prototype.handleIP = function(ip, port) {
var buf, context, dataPackets, e, error1, input, output, result;
if (!port.options.triggering) {
return;
}
if (ip.type === 'openBracket' && this.autoOrdering === null && !this.ordered) {
debug(this.nodeId + " port '" + port.name + "' entered auto-ordering mode");
this.autoOrdering = true;
}
result = {};
if (this.isForwardingInport(port)) {
if (ip.type === 'openBracket') {
return;
}
if (ip.type === 'closeBracket') {
buf = port.getBuffer(ip.scope, ip.index);
dataPackets = buf.filter(function(ip) {
return ip.type === 'data';
});
if (this.outputQ.length >= this.load && dataPackets.length === 0) {
if (buf[0] !== ip) {
return;
}
port.get(ip.scope, ip.index);
context = this.getBracketContext('in', port.name, ip.scope, ip.index).pop();
context.closeIp = ip;
debugBrackets(this.nodeId + " closeBracket-C from '" + context.source + "' to " + context.ports + ": '" + ip.data + "'");
result = {
__resolved: true,
__bracketClosingAfter: [context]
};
this.outputQ.push(result);
this.processOutputQueue();
}
if (!dataPackets.length) {
return;
}
}
}
context = new ProcessContext(ip, this, port, result);
input = new ProcessInput(this.inPorts, context);
output = new ProcessOutput(this.outPorts, context);
try {
this.handle(input, output, context);
} catch (error1) {
e = error1;
this.deactivate(context);
output.sendDone(e);
}
if (context.activated) {
return;
}
if (port.isAddressable()) {
debug(this.nodeId + " packet on '" + port.name + "[" + ip.index + "]' didn't match preconditions: " + ip.type);
return;
}
debug(this.nodeId + " packet on '" + port.name + "' didn't match preconditions: " + ip.type);
};
Component.prototype.getBracketContext = function(type, port, scope, idx) {
var index, name, portsList, ref;
ref = ports.normalizePortName(port), name = ref.name, index = ref.index;
if (idx != null) {
index = idx;
}
portsList = type === 'in' ? this.inPorts : this.outPorts;
if (portsList[name].isAddressable()) {
port = name + "[" + index + "]";
}
if (!this.bracketContext[type][port]) {
this.bracketContext[type][port] = {};
}
if (!this.bracketContext[type][port][scope]) {
this.bracketContext[type][port][scope] = [];
}
return this.bracketContext[type][port][scope];
};
Component.prototype.addToResult = function(result, port, ip, before) {
var idx, index, method, name, ref;
if (before == null) {
before = false;
}
ref = ports.normalizePortName(port), name = ref.name, index = ref.index;
method = before ? 'unshift' : 'push';
if (this.outPorts[name].isAddressable()) {
idx = index ? parseInt(index) : ip.index;
if (!result[name]) {
result[name] = {};
}
if (!result[name][idx]) {
result[name][idx] = [];
}
ip.index = idx;
result[name][idx][method](ip);
return;
}
if (!result[name]) {
result[name] = [];
}
return result[name][method](ip);
};
Component.prototype.getForwardableContexts = function(inport, outport, contexts) {
var forwardable, index, name, ref;
ref = ports.normalizePortName(outport), name = ref.name, index = ref.index;
forwardable = [];
contexts.forEach((function(_this) {
return function(ctx, idx) {
var outContext;
if (!_this.isForwardingOutport(inport, name)) {
return;
}
if (ctx.ports.indexOf(outport) !== -1) {
return;
}
outContext = _this.getBracketContext('out', name, ctx.ip.scope, index)[idx];
if (outContext) {
if (outContext.ip.data === ctx.ip.data && outContext.ports.indexOf(outport) !== -1) {
return;
}
}
return forwardable.push(ctx);
};
})(this));
return forwardable;
};
Component.prototype.addBracketForwards = function(result) {
var context, i, ipClone, j, k, l, len1, len2, len3, len4, port, ref, ref1, ref2, ref3, ref4, ref5;
if ((ref = result.__bracketClosingBefore) != null ? ref.length : void 0) {
ref1 = result.__bracketClosingBefore;
for (i = 0, len1 = ref1.length; i < len1; i++) {
context = ref1[i];
debugBrackets(this.nodeId + " closeBracket-A from '" + context.source + "' to " + context.ports + ": '" + context.closeIp.data + "'");
if (!context.ports.length) {
continue;
}
ref2 = context.ports;
for (j = 0, len2 = ref2.length; j < len2; j++) {
port = ref2[j];
ipClone = context.closeIp.clone();
this.addToResult(result, port, ipClone, true);
this.getBracketContext('out', port, ipClone.scope).pop();
}
}
}
if (result.__bracketContext) {
Object.keys(result.__bracketContext).reverse().forEach((function(_this) {
return function(inport) {
var ctx, datas, forwardedOpens, idx, idxIps, ip, ips, k, l, len3, len4, len5, m, outport, portIdentifier, results, unforwarded;
context = result.__bracketContext[inport];
if (!context.length) {
return;
}
results = [];
for (outport in result) {
ips = result[outport];
if (outport.indexOf('__') === 0) {
continue;
}
if (_this.outPorts[outport].isAddressable()) {
for (idx in ips) {
idxIps = ips[idx];
datas = idxIps.filter(function(ip) {
return ip.type === 'data';
});
if (!datas.length) {
continue;
}
portIdentifier = outport + "[" + idx + "]";
unforwarded = _this.getForwardableContexts(inport, portIdentifier, context);
if (!unforwarded.length) {
continue;
}
forwardedOpens = [];
for (k = 0, len3 = unforwarded.length; k < len3; k++) {
ctx = unforwarded[k];
debugBrackets(_this.nodeId + " openBracket from '" + inport + "' to '" + portIdentifier + "': '" + ctx.ip.data + "'");
ipClone = ctx.ip.clone();
ipClone.index = parseInt(idx);
forwardedOpens.push(ipClone);
ctx.ports.push(portIdentifier);
_this.getBracketContext('out', outport, ctx.ip.scope, idx).push(ctx);
}
forwardedOpens.reverse();
for (l = 0, len4 = forwardedOpens.length; l < len4; l++) {
ip = forwardedOpens[l];
_this.addToResult(result, outport, ip, true);
}
}
continue;
}
datas = ips.filter(function(ip) {
return ip.type === 'data';
});
if (!datas.length) {
continue;
}
unforwarded = _this.getForwardableContexts(inport, outport, context);
if (!unforwarded.length) {
continue;
}
forwardedOpens = [];
for (m = 0, len5 = unforwarded.length; m < len5; m++) {
ctx = unforwarded[m];
debugBrackets(_this.nodeId + " openBracket from '" + inport + "' to '" + outport + "': '" + ctx.ip.data + "'");
forwardedOpens.push(ctx.ip.clone());
ctx.ports.push(outport);
_this.getBracketContext('out', outport, ctx.ip.scope).push(ctx);
}
forwardedOpens.reverse();
results.push((function() {
var len6, n, results1;
results1 = [];
for (n = 0, len6 = forwardedOpens.length; n < len6; n++) {
ip = forwardedOpens[n];
results1.push(this.addToResult(result, outport, ip, true));
}
return results1;
}).call(_this));
}
return results;
};
})(this));
}
if ((ref3 = result.__bracketClosingAfter) != null ? ref3.length : void 0) {
ref4 = result.__bracketClosingAfter;
for (k = 0, len3 = ref4.length; k < len3; k++) {
context = ref4[k];
debugBrackets(this.nodeId + " closeBracket-B from '" + context.source + "' to " + context.ports + ": '" + context.closeIp.data + "'");
if (!context.ports.length) {
continue;
}
ref5 = context.ports;
for (l = 0, len4 = ref5.length; l < len4; l++) {
port = ref5[l];
ipClone = context.closeIp.clone();
this.addToResult(result, port, ipClone, false);
this.getBracketContext('out', port, ipClone.scope).pop();
}
}
}
delete result.__bracketClosingBefore;
delete result.__bracketContext;
return delete result.__bracketClosingAfter;
};
Component.prototype.processOutputQueue = function() {
var i, idx, idxIps, ip, ips, j, len1, len2, port, portIdentifier, result, results;
results = [];
while (this.outputQ.length > 0) {
result = this.outputQ[0];
if (!result.__resolved) {
break;
}
this.addBracketForwards(result);
for (port in result) {
ips = result[port];
if (port.indexOf('__') === 0) {
continue;
}
if (this.outPorts.ports[port].isAddressable()) {
for (idx in ips) {
idxIps = ips[idx];
idx = parseInt(idx);
if (!this.outPorts.ports[port].isAttached(idx)) {
continue;
}
for (i = 0, len1 = idxIps.length; i < len1; i++) {
ip = idxIps[i];
portIdentifier = port + "[" + ip.index + "]";
if (ip.type === 'openBracket') {
debugSend(this.nodeId + " sending " + portIdentifier + " < '" + ip.data + "'");
} else if (ip.type === 'closeBracket') {
debugSend(this.nodeId + " sending " + portIdentifier + " > '" + ip.data + "'");
} else {
debugSend(this.nodeId + " sending " + portIdentifier + " DATA");
}
this.outPorts[port].sendIP(ip);
}
}
continue;
}
if (!this.outPorts.ports[port].isAttached()) {
continue;
}
for (j = 0, len2 = ips.length; j < len2; j++) {
ip = ips[j];
portIdentifier = port;
if (ip.type === 'openBracket') {
debugSend(this.nodeId + " sending " + portIdentifier + " < '" + ip.data + "'");
} else if (ip.type === 'closeBracket') {
debugSend(this.nodeId + " sending " + portIdentifier + " > '" + ip.data + "'");
} else {
debugSend(this.nodeId + " sending " + portIdentifier + " DATA");
}
this.outPorts[port].sendIP(ip);
}
}
results.push(this.outputQ.shift());
}
return results;
};
Component.prototype.activate = function(context) {
if (context.activated) {
return;
}
context.activated = true;
context.deactivated = false;
this.load++;
this.emit('activate', this.load);
if (this.ordered || this.autoOrdering) {
return this.outputQ.push(context.result);
}
};
Component.prototype.deactivate = function(context) {
if (context.deactivated) {
return;
}
context.deactivated = true;
context.activated = false;
if (this.isOrdered()) {
this.processOutputQueue();
}
this.load--;
return this.emit('deactivate', this.load);
};
return Component;
})(EventEmitter);
exports.Component = Component;
ProcessContext = (function() {
function ProcessContext(ip1, nodeInstance, port1, result1) {
this.ip = ip1;
this.nodeInstance = nodeInstance;
this.port = port1;
this.result = result1;
this.scope = this.ip.scope;
this.activated = false;
this.deactivated = false;
}
ProcessContext.prototype.activate = function() {
if (this.result.__resolved || this.nodeInstance.outputQ.indexOf(this.result) === -1) {
this.result = {};
}
return this.nodeInstance.activate(this);
};
ProcessContext.prototype.deactivate = function() {
if (!this.result.__resolved) {
this.result.__resolved = true;
}
return this.nodeInstance.deactivate(this);
};
return ProcessContext;
})();
ProcessInput = (function() {
function ProcessInput(ports1, context1) {
this.ports = ports1;
this.context = context1;
this.nodeInstance = this.context.nodeInstance;
this.ip = this.context.ip;
this.port = this.context.port;
this.result = this.context.result;
this.scope = this.context.scope;
}
ProcessInput.prototype.activate = function() {
if (this.context.activated) {
return;
}
if (this.nodeInstance.isOrdered()) {
this.result.__resolved = false;
}
this.nodeInstance.activate(this.context);
if (this.port.isAddressable()) {
return debug(this.nodeInstance.nodeId + " packet on '" + this.port.name + "[" + this.ip.index + "]' caused activation " + this.nodeInstance.load + ": " + this.ip.type);
} else {
return debug(this.nodeInstance.nodeId + " packet on '" + this.port.name + "' caused activation " + this.nodeInstance.load + ": " + this.ip.type);
}
};
ProcessInput.prototype.attached = function() {
var args, i, len1, port, res;
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
if (!args.length) {
args = ['in'];
}
res = [];
for (i = 0, len1 = args.length; i < len1; i++) {
port = args[i];
res.push(this.ports[port].listAttached());
}
if (args.length === 1) {
return res.pop();
}
return res;
};
ProcessInput.prototype.has = function() {
var args, i, len1, port, validate;
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
if (!args.length) {
args = ['in'];
}
if (typeof args[args.length - 1] === 'function') {
validate = args.pop();
} else {
validate = function() {
return true;
};
}
for (i = 0, len1 = args.length; i < len1; i++) {
port = args[i];
if (Array.isArray(port)) {
if (!this.ports[port[0]].isAddressable()) {
throw new Error("Non-addressable ports, access must be with string " + port[0]);
}
if (!this.ports[port[0]].has(this.scope, port[1], validate)) {
return false;
}
continue;
}
if (this.ports[port].isAddressable()) {
throw new Error("For addressable ports, access must be with array [" + port + ", idx]");
}
if (!this.ports[port].has(this.scope, validate)) {
return false;
}
}
return true;
};
ProcessInput.prototype.hasData = function() {
var args;
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
if (!args.length) {
args = ['in'];
}
args.push(function(ip) {
return ip.type === 'data';
});
return this.has.apply(this, args);
};
ProcessInput.prototype.hasStream = function() {
var args, dataBrackets, hasData, i, len1, port, portBrackets, validate, validateStream;
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
if (!args.length) {
args = ['in'];
}
if (typeof args[args.length - 1] === 'function') {
validateStream = args.pop();
} else {
validateStream = function() {
return true;
};
}
for (i = 0, len1 = args.length; i < len1; i++) {
port = args[i];
portBrackets = [];
dataBrackets = [];
hasData = false;
validate = function(ip) {
if (ip.type === 'openBracket') {
portBrackets.push(ip.data);
return false;
}
if (ip.type === 'data') {
hasData = validateStream(ip, portBrackets);
if (!portBrackets.length) {
return hasData;
}
return false;
}
if (ip.type === 'closeBracket') {
portBrackets.pop();
if (portBrackets.length) {
return false;
}
if (!hasData) {
return false;
}
return true;
}
};
if (!this.has(port, validate)) {
return false;
}
}
return true;
};
ProcessInput.prototype.get = function() {
var args, i, idx, ip, len1, port, portname, res;
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
this.activate();
if (!args.length) {
args = ['in'];
}
res = [];
for (i = 0, len1 = args.length; i < len1; i++) {
port = args[i];
if (Array.isArray(port)) {
portname = port[0], idx = port[1];
if (!this.ports[portname].isAddressable()) {
throw new Error('Non-addressable ports, access must be with string portname');
}
} else {
portname = port;
if (this.ports[portname].isAddressable()) {
throw new Error('For addressable ports, access must be with array [portname, idx]');
}
}
if (this.nodeInstance.isForwardingInport(portname)) {
ip = this.__getForForwarding(portname, idx);
res.push(ip);
continue;
}
ip = this.ports[portname].get(this.scope, idx);
res.push(ip);
}
if (args.length === 1) {
return res[0];
} else {
return res;
}
};
ProcessInput.prototype.__getForForwarding = function(port, idx) {
var context, dataIp, i, ip, len1, prefix;
prefix = [];
dataIp = null;
while (true) {
ip = this.ports[port].get(this.scope, idx);
if (!ip) {
break;
}
if (ip.type === 'data') {
dataIp = ip;
break;
}
prefix.push(ip);
}
for (i = 0, len1 = prefix.length; i < len1; i++) {
ip = prefix[i];
if (ip.type === 'closeBracket') {
if (!this.result.__bracketClosingBefore) {
this.result.__bracketClosingBefore = [];
}
context = this.nodeInstance.getBracketContext('in', port, this.scope, idx).pop();
context.closeIp = ip;
this.result.__bracketClosingBefore.push(context);
continue;
}
if (ip.type === 'openBracket') {
this.nodeInstance.getBracketContext('in', port, this.scope, idx).push({
ip: ip,
ports: [],
source: port
});
continue;
}
}
if (!this.result.__bracketContext) {
this.result.__bracketContext = {};
}
this.result.__bracketContext[port] = this.nodeInstance.getBracketContext('in', port, this.scope, idx).slice(0);
return dataIp;
};
ProcessInput.prototype.getData = function() {
var args, datas, i, len1, packet, port;
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
if (!args.length) {
args = ['in'];
}
datas = [];
for (i = 0, len1 = args.length; i < len1; i++) {
port = args[i];
packet = this.get(port);
if (packet == null) {
datas.push(packet);
continue;
}
while (packet.type !== 'data') {
packet = this.get(port);
if (!packet) {
break;
}
}
datas.push(packet.data);
}
if (args.length === 1) {
return datas.pop();
}
return datas;
};
ProcessInput.prototype.getStream = function() {
var args, datas, hasData, i, ip, len1, port, portBrackets, portPackets;
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
if (!args.length) {
args = ['in'];
}
datas = [];
for (i = 0, len1 = args.length; i < len1; i++) {
port = args[i];
portBrackets = [];
portPackets = [];
hasData = false;
ip = this.get(port);
if (!ip) {
datas.push(void 0);
}
while (ip) {
if (ip.type === 'openBracket') {
if (!portBrackets.length) {
portPackets = [];
hasData = false;
}
portBrackets.push(ip.data);
portPackets.push(ip);
}
if (ip.type === 'data') {
portPackets.push(ip);
hasData = true;
if (!portBrackets.length) {
break;
}
}
if (ip.type === 'closeBracket') {
portPackets.push(ip);
portBrackets.pop();
if (hasData && !portBrackets.length) {
break;
}
}
ip = this.get(port);
}
datas.push(portPackets);
}
if (args.length === 1) {
return datas.pop();
}
return datas;
};
return ProcessInput;
})();
ProcessOutput = (function() {
function ProcessOutput(ports1, context1) {
this.ports = ports1;
this.context = context1;
this.nodeInstance = this.context.nodeInstance;
this.ip = this.context.ip;
this.result = this.context.result;
this.scope = this.context.scope;
}
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, i, j, len1, len2, multiple, 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, len1 = err.length; i < len1; i++) {
e = err[i];
this.sendIP('error', e);
}
if (multiple) {
return this.sendIP('error', new IP('closeBracket'));
}
} else {
results = [];
for (j = 0, len2 = err.length; j < len2; j++) {
e = err[j];
throw e;
}
return results;
}
};
ProcessOutput.prototype.sendIP = function(port, packet) {
var ip;
if (!IP.isIP(packet)) {
ip = new IP('data', packet);
} else {
ip = packet;
}
if (this.scope !== null && ip.scope === null) {
ip.scope = this.scope;
}
if (this.nodeInstance.outPorts[port].isAddressable() && ip.index === null) {
throw new Error('Sending packets to addressable ports requires specifying index');
}
if (this.nodeInstance.isOrdered()) {
this.nodeInstance.addToResult(this.result, port, ip);
return;
}
return this.nodeInstance.outPorts[port].sendIP(ip);
};
ProcessOutput.prototype.send = function(outputMap) {
var componentPorts, i, len1, mapIsInPorts, packet, port, ref, results;
if (this.isError(outputMap)) {
return this.error(outputMap);
}
componentPorts = [];
mapIsInPorts = false;
ref = Object.keys(this.ports.ports);
for (i = 0, len1 = ref.length; i < len1; i++) {
port = ref[i];
if (port !== 'error' && port !== 'ports' && port !== '_callbacks') {
componentPorts.push(port);
}
if (!mapIsInPorts && (outputMap != null) && typeof outputMap === 'object' && Object.keys(outputMap).indexOf(port) !== -1) {
mapIsInPorts = true;
}
}
if (componentPorts.length === 1 && !mapIsInPorts) {
this.sendIP(componentPorts[0], outputMap);
return;
}
if (componentPorts.length > 1 && !mapIsInPorts) {
throw new Error('Port must be specified for sending output');
}
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) {
var buf, context, contexts, ctx, ip, isLast, nodeContext, port, ref;
this.result.__resolved = true;
this.nodeInstance.activate(this.context);
if (error) {
this.error(error);
}
isLast = (function(_this) {
return function() {
var len, load, pos, resultsOnly;
resultsOnly = _this.nodeInstance.outputQ.filter(function(q) {
if (!q.__resolved) {
return true;
}
if (Object.keys(q).length === 2 && q.__bracketClosingAfter) {
return false;
}
return true;
});
pos = resultsOnly.indexOf(_this.result);
len = resultsOnly.length;
load = _this.nodeInstance.load;
if (pos === len - 1) {
return true;
}
if (pos === -1 && load === len + 1) {
return true;
}
if (len <= 1 && load === 1) {
return true;
}
return false;
};
})(this);
if (this.nodeInstance.isOrdered() && isLast()) {
ref = this.nodeInstance.bracketContext["in"];
for (port in ref) {
contexts = ref[port];
if (!contexts[this.scope]) {
continue;
}
nodeContext = contexts[this.scope];
if (!nodeContext.length) {
continue;
}
context = nodeContext[nodeContext.length - 1];
buf = this.nodeInstance.inPorts[context.source].getBuffer(context.ip.scope, context.ip.index);
while (true) {
if (!buf.length) {
break;
}
if (buf[0].type !== 'closeBracket') {
break;
}
ip = this.nodeInstance.inPorts[context.source].get(context.ip.scope, context.ip.index);
ctx = nodeContext.pop();
ctx.closeIp = ip;
if (!this.result.__bracketClosingAfter) {
this.result.__bracketClosingAfter = [];
}
this.result.__bracketClosingAfter.push(ctx);
}
}
}
debug(this.nodeInstance.nodeId + " finished processing " + this.nodeInstance.load);
return this.nodeInstance.deactivate(this.context);
};
return ProcessOutput;
})();
}).call(this);