UNPKG

noflo

Version:

Flow-Based Programming environment for JavaScript

1,162 lines (1,095 loc) 36.9 kB
(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);