UNPKG

do-red

Version:

A do-node and corresponding return-node for creating loops and task-lists.

105 lines (97 loc) 4.01 kB
const initNextValue = (msg, config, tasks, RED) => { const _do = msg._do _do.index = _do.index + 1 delete _do.valueDeleted // first time the task stack has values from general _do initaliziation if (!_do.stack.length) _do.isFirstMsg = false _do.stack = [...tasks].reverse() if (_do.collectionType === 'Array') { if (config.yield === 'value') { msg.payload = _do.collection[_do.index] } else { msg.payload = { [_do.index]: _do.collection[_do.index] } } } else if (_do.collectionType === 'Set') { msg.payload = _do.setIterator.next().value _do.currentSetValue = RED.util.cloneMessage(msg.payload) } else if (_do.collectionType === 'Object' || _do.collectionType === 'Map') { const currentKey = _do.keys[_do.index] let currentValue if (_do.collectionType === 'Object') currentValue = _do.collection[currentKey] else if (_do.collectionType === 'Map') currentValue = _do.collection.get(currentKey) if (config.yield === 'keyValue') { msg.payload = { [currentKey]: currentValue } } else if (config.yield === 'key') { msg.payload = currentKey } else if (config.yield === 'value') { msg.payload = currentValue } else { throw new Error("Can't put value into payload (" + config.yield + ' is not valid for Yield).') } } else { throw new Error('No valid collection set!') } return msg } const initEachDo = (RED, msg, node, config, _do) => { _do.index = -1 _do.isFirstMsg = true _do.isLastMsg = false _do.eachType = config.eachType _do.eachPath = config.each _do.yieldType = config.yield // clone the collection and payload. The collection will always be written when done is reached. // if the collection is not (within) msg.payload, msg.payload will be replaced with it's original value after all tasks are done. if (config.eachType === 'msg') { _do.collection = RED.util.cloneMessage(RED.util.getObjectProperty(msg, _do.eachPath)) } else { _do.collection = RED.util.evaluateNodeProperty(config.each, config.eachType, node, msg) } _do.payload = RED.util.cloneMessage(msg.payload) return _do } const handleDone = (RED, msg, config, send, done) => { // return original payload after each is done // if (msg?._do?.payload) { // use optional chaining when latest supported version from node-red is allowing if (msg._do && msg._do.payload) { msg.payload = msg._do.payload } // get parent do or delete if done // if (msg?._do?._do) { if (msg._do && msg._do._do) { msg._do = msg._do._do } else { delete msg._do } // send to output or event to other do-node if (config.doneOutput) { const out = new Array(config.outputs - 1) out.push(msg) // must be last output send(out) // } else if (msg?._do?.returnTo) { } else if (msg._do && msg._do.returnTo) { // if we return to a previous do-node then a task was completed if (Array.isArray(msg._do.stack)) msg._do.stack.pop() const event = 'do:' + msg._do.returnTo msg._event = event RED.events.emit(event, msg) } if (done) return done() } const checkCollectionType = (config, collection) => { if (typeof collection === 'undefined') throw new Error(`Collection ${config.eachType}.${config.each} is undefined!`) else if (Array.isArray(collection)) return 'Array' // instanceof Set/Map seems not to work. Maybe proxy variable through Node-Red? // else if (collection?.constructor?.name === 'Map') return 'Map' // else if (collection?.constructor?.name === 'Set') return 'Set' else if (collection.constructor && collection.constructor.name === 'Map') return 'Map' else if (collection.constructor && collection.constructor.name === 'Set') return 'Set' else if (!!collection && typeof collection === 'object' && Array.isArray(collection) === false) return 'Object' throw new Error(`Collection ${config.eachType}.${config.each} could not identified!`) } module.exports = { initNextValue, initEachDo, handleDone, checkCollectionType }