UNPKG

node-red-contrib-prib-functions

Version:
626 lines (620 loc) 25.2 kB
const logger = new (require("node-red-contrib-logger"))("transform"); logger.sendInfo("Copyright 2020 Jaroslav Peter Prib"); const NumPy = require("./NumPy.js") const typedInput = require("../lib/typedInput.js") const {coalesce,nullif,toDateTypeZulu}=require("../lib/objectExtensions") const regexCSV=/,(?=(?:(?:[^"]*"){2})*[^"]*$)/, Buffer=require('buffer').Buffer, os=require('os'), path=require('path'), process=require('process'); let avsc,snappy,xmlParser,json2xmlParser,XLSX,compressor; const {ISO8583BitMapId,ISO8583BitMapName}=require("./ISO8583BitMap"); let ISO8583,ISO8583message; const XMLoptions = { // attributeNamePrefix : "@_", // attrNodeName: "attr", //default is 'false' // textNodeName : "#text", ignoreAttributes : false, ignoreNameSpace : false, allowBooleanAttributes : true, parseNodeValue : true, parseAttributeValue : false, // cdataTagName: "__cdata", //default is 'false' // cdataPositionChar: "\\c", // parseTrueNumberOnly: false, // arrayMode: false, //"strict" // attrValueProcessor: (val, attrName) => he.decode(val, {isAttributeValue: true}),//default is a=>a // tagValueProcessor : (val, tagName) => he.decode(val), //default is a=>a // stopNodes: ["parse-me-as-string"] trimValues: false }; const makeDateType=data=>(data instanceof Date? data:new Date(data)) const error=(node,ex,shortMessage)=>{ if(logger.active) logger.send({label:"transformNode catch",shortMessage:shortMessage,error:ex.message,stack:ex.stack}); node.error(ex.message); node.status({fill:"red",shape:"ring",text:(shortMessage||ex.message).substr(0,50)}); } const getAvroTransformer=(node,schema)=>{ try{ return avsc.Type.forSchema(node.schemas[schema]); } catch(ex){ if(node.schemas.hasOwnProperty(schema)) throw ex; throw Error("schema not found for "+schema); } } const addWorksheet2JSON=(object,worksheet,workbook,options)=>{ object[worksheet]=XLSX.utils.sheet_to_json(workbook.Sheets[worksheet],options); if(options.header) object[worksheet].shift(); if(logger.active) logger.send({label:"addWorksheet2JSON",object:object,worksheet:worksheet}) return object; } const XLSXObjectToJSON=(RED,node,msg,data)=>data.SheetNames.reduce((a,worksheet)=>addWorksheet2JSON(a,worksheet,data),{}) const XLSXToArray=(RED,node,msg,data)=>XLSXObjectToArray(RED,node,msg,XLSXToXLSXObject(RED,node,msg,data)) const XLSXToJSON=(RED,node,msg,data)=>XLSXObjectToJSON(RED,node,msg,XLSXToXLSXObject(RED,node,msg,data)) const XLSXToXLSXObject=(RED,node,msg,data)=>XLSX.read(data, {raw:true,type: 'buffer' }) const XLSXObjectToArray=(RED,node,msg,data)=>data.SheetNames.reduce((a,worksheet)=>addWorksheet2JSON(a,worksheet,data,{header:1,raw:true}),{}) const JSONToXLSX=(RED,node,msg,data)=>XLSX.write(JSONToXLSXObject(RED,node,msg,data), {bookType:"xlsx", type:'buffer'}) const JSONToXLSXObject=(RED,node,msg,data)=>{ const workbook = XLSX.utils.book_new(); for(const worksheet in data) { const ws=XLSX.utils.json_to_sheet(data[worksheet]); XLSX.utils.book_append_sheet(workbook, ws, worksheet); } return workbook; } const ArrayToXLSX=(RED,node,msg,data)=>XLSX.write(ArrayToXLSXObject(RED,node,msg,data), {bookType:"xlsx", type:'buffer'}) const ArrayToXLSXObject=(RED,node,msg,data)=>{ const workbook = XLSX.utils.book_new(); if(Array.isArray(data)) { const ws=XLSX.utils.aoa_to_sheet(data); XLSX.utils.book_append_sheet(workbook, ws,"worksheet 1"); return workbook; } for(const worksheet in data) { const ws=XLSX.utils.aoa_to_sheet(data[worksheet]); XLSX.utils.book_append_sheet(workbook, ws, worksheet); } return workbook; } const ConfluenceToJSON=(RED,node,msg,data)=>{ if(!Buffer.isBuffer(data)) data=Buffer.from(data); const magicByte=data.readUInt8(); if(magicByte!==0) throw Error("expected magic byte and not found, found "+magicByte); if(data.length<5) throw Error("missing schema, data length "+data.length); const schema=data.readInt32BE(1); const avroTransformer=getAvroTransformer(node,schema); return {schema:schema,data:avroTransformer.fromBuffer(data.subarray(5))}; } const JSONToConfluence=(RED,node,msg,data)=>{ if(!data.schema) throw Error("property schema not defined"); if(!data.data) throw Error("property data not defined"); const header=Buffer.alloc(5); header[0]=0; header.writeInt32BE(data.schema, 1); const transformer=getAvroTransformer(node,data.schema); const avro=transformer.toBuffer(data.data); return Buffer.concat([header,avro]); } function SendArray(RED,node,msg,array){ if(logger.active) logger.send({label:"SendArray",size:array.length}); this.index=0; this.RED=RED; this.node=node; this.msg=msg; this.array=array; this.next(); } SendArray.prototype.next=function() { this.usageCPU=process.cpuUsage(this.usageCPU); this.resourceUsage=process.resourceUsage(); const memoryUsage=process.memoryUsage(), heapUsedRatio=memoryUsage.heapUsed/memoryUsage.heapTotal, memoryUsedRatio=os.freemem()/os.totalmem(); currentTime=Date.now(), cpuUsedRatio=(this.usageCPU.user+this.usageCPU.system)/((currentTime-this.lastTouchTime)*100000); if(logger.active) logger.send({label:"SendArray.next",index:this.index,cpuUsedRatio:cpuUsedRatio,memoryUsedRatio:memoryUsedRatio,heapUsedRatio:heapUsedRatio}); this.lastTouchTime=currentTime; let i=cpuUsedRatio>0.9 || memoryUsedRatio>0.9 || heapUsedRatio>0.99?1:100; const newMsgs=[] while(--i) { if(this.index>=this.array.length) { delete this; return; } const newMsg=this.RED.util.cloneMessage(this.msg),index=this.index; newMsg._msgid=newMsg._msgid+":"+index; this.node.setData(this.RED,this.node,newMsg,this.array[index],index) this.index++; newMsgs.push(newMsg); } this.node.send([newMsgs]); const call=this.next.bind(this); this.timeoutID=setTimeout(call, 100); }; const removeQuotes=(data)=>{ try{ const d=data.trim(); if(d.length>1 && d.startsWith('"') && d.endsWith('"')) return d.slice(1,-1); const r=Number(d); return r?r:d; } catch(ex) { return data; } } const csvLines=(data,skipLeading=0,skipTrailing=0)=>{ if(logger.active) logger.send({label:"csvLines",skipLeading:skipLeading,skipTrailing:skipTrailing}); let lines=data.split(/[\r\n]+/g),skip=skipLeading; while(skip--) lines.shift(); skip=skipTrailing; while(skip--) lines.pop(); return lines; } const array2tag=(a,t,tf)=>{ const ts="<"+t+">",te="</"+t+">" return a.reduce((a,c)=>a+=ts+tf(c)+te,""); } const Array2csv=(node,data)=>{ if(!(data instanceof Array)) return JSON.stringify(data); if(data.length==0) return; if(data[0] instanceof Array) { return data.map(r=> r instanceof Array?r.map(c=>JSON.stringify(c)).join(node.delimiter):JSON.stringify(r) ).join("\n"); } else if(data[0] instanceof Object) { const properties=[]; data.forEach(r=>{ if(typeof r == "object" && ! (r instanceof Array)){ Object.keys(r).forEach(p=>{ if(properties.includes(p)) return properties.push(p) }) } }) properties.sort(); const rows=data.map(r=>{ if(typeof r == "object" && ! (r instanceof Array)) { return properties.map(c=>r[c]||"").join(node.delimiter) } else { return node.delimiter.repeat(properties.length)+JSON.stringify(r) } }) return properties.join(node.delimiter)+"\n"+rows.join("\n"); } return data .map(r=>JSON.stringify(r)).join("/n"); } const functions={ ArrayToCSV: (RED,node,msg,data)=>data.map(c=>JSON.stringify(c)).join("\n"), ArrayToHTML: (RED,node,msg,data)=> "<table>"+ array2tag(data,"tr",(c)=>( Array.isArray(c)? array2tag(c,"td",(cc)=> Array.isArray(cc)? functions.ArrayToHTML(RED,node,msg,cc): "<![CDATA["+cc+"]]>" ): "<![CDATA["+c+"]]>" ) )+"</table>", ArrayToISO8385: (RED,node,msg,data)=>ISO8583message.packSync(data), ArrayToMessages: (RED,node,msg,data)=>{ if(logger.active) logger.send({label:"ArrayToMessages",arraySize:data.length}); if(data.length>node.maxMessages) throw Error("messages to be created "+data.length +"> max: "+node.maxMessages); const newMsgs=[] data.map((row,i)=>{ const newMsg=RED.util.cloneMessage(msg); newMsg._msgid=newMsg._msgid+":"+i; if(logger.active) logger.send({label:"ArrayToMessages",row:row,index:i}); node.setData(RED,node,newMsg,row,i) newMsgs.push(newMsg); }); node.send([newMsgs]) }, ArrayToXLSX:ArrayToXLSX, ArrayToXLSXObject:ArrayToXLSXObject, AVROToJSON: (RED,node,msg,data)=>node.avroTransformer.fromBuffer(data), // = {kind: 'CAT', name: 'Albert'} BigIntToRangeLimit: (RED,node,msg,data)=> data?data.rangeLimit(node.minBigIntTyped,node.maxBigIntTyped):node.minBigInt, BufferToCompressed: (RED,node,msg,data)=>compressor.compress(data, (compressed)=>{ node.setData(RED,node,msg,compressed); node.send(msg); }, (err)=>{ error(node,Error(err)); } ), CompressedToBuffer:(RED,node,msg,data)=>compressor.decompress(data, (uncompressed)=>{ node.setData(RED,node,msg,uncompressed); node.send(msg); }, (err)=>{ error(node,Error(err)); } ), CompressedToJSON:(RED,node,msg,data)=>compressor.decompress(data, (uncompressed)=>{ try{ node.setData(RED,node,msg,JSON.parse(uncompressed)); node.send(msg); } catch(ex){ msg.error=ex.message node.setData(RED,node,msg,uncompressed); } }, (err)=>{ error(node,Error(err)); } ), CompressedToString:(RED,node,msg,data)=>compressor.decompress(data, (uncompressed)=>{ try{ node.setData(RED,node,msg,uncompressed.toString()); node.send(msg); } catch(ex){ msg.error=ex.message; node.setData(RED,node,msg,uncompressed); } }, (err)=>{ error(node,Error(err)); } ), ConfluenceToJSON: ConfluenceToJSON, CSVToArray: (RED,node,msg,data)=>{ let lines=csvLines(data,node.skipLeading,node.skipTrailing); lines.forEach((value, idx) => { lines[idx]=value.split(regexCSV).map((c)=>removeQuotes(c)); }); return lines; }, CSVToHTML: (RED,node,msg,data)=> "<table>"+ array2tag(csvLines(data,node.skipLeading,node.skipTrailing),"tr",(line)=> array2tag(line.split(regexCSV),"td",(c)=>"<![CDATA["+removeQuotes(c)+"]]>") )+"</table>", CSVToMessages: (RED,node,msg,data)=>{ functions.ArrayToMessages(RED,node,msg,csvLines(data,this.skipLeading,this.skipTrailing)); }, CSVWithHeaderToArray: (RED,node,msg,data)=>{ let r=functions.CSVToArray(RED,node,msg,data); r.shift(); return r; }, CSVWithHeaderToHTML: (RED,node,msg,data)=>{ let lines=csvLines(data,node.skipLeading,node.skipTrailing); const header=array2tag(lines.shift().split(regexCSV),"th",(c)=>"<![CDATA["+removeQuotes(c)+"]]>"); return "<table><tr>"+header+"</tr>"+array2tag(lines,"tr",(line)=> array2tag(line.split(regexCSV),'td',(c)=>"<![CDATA["+removeQuotes(c)+"]]>") )+"</table>" }, CSVWithHeaderToJSON: (RED,node,msg,data)=>{ let lines=csvLines(data,node.skipLeading,node.skipTrailing); let header=lines.shift().split(regexCSV); if(logger.active) logger.send({label:"CSVWithHeaderToJSON",header:header}); lines.forEach((value, idx) => { let o={}; value.split(regexCSV).forEach((c,i)=>{ o[header[i]]=removeQuotes(c); }); lines[idx]=o; }); return lines; }, DateToisBetween: (RED,node,msg,data)=> toDateTypeZulu(data).isBetween(node.minDateTyped,node.maxDateTyped), DateToISODate: (RED,node,msg,data)=> toDateTypeZulu(data).toISOString().slice(0,10), DateToLocalDate: (RED,node,msg,data)=> toDateTypeZulu(data).toLocaleDateString().slice(0,10), DateToRangeLimit: (RED,node,msg,data)=> (data? toDateTypeZulu(data).rangeLimit(node.minDateTyped,node.maxDateTyped):node.minDateTyped), ISO8385ToArray: (RED,node,msg,data)=>ISO8583message.unpackSync(data, data.length), ISO8385ToJSON: (RED,node,msg,data)=>{ let j={},d=ISO8583message.unpackSync(data, data.length); d.forEach((r)=>{ j[ISO8583BitMapId(r[0]).name]=r[1]; }); return r; }, JSONToArray: (RED,node,msg,data)=>{ if(data instanceof Object){ let a=[]; properties=Object.keys(data) for(const p of properties) { a.push([p,functions.JSONToArray(RED,node,msg,data[p])]); } return a; } return data; }, JSONToAVRO: (RED,node,msg,data)=>node.avroTransformer.toBuffer(data), // Encoded buffer. JSONToCompressed: (RED,node,msg,data)=>compressor.compress(JSON.stringify(data), (compressed)=>{ node.setData(RED,node,msg,compressed); node.send(msg); }, (err)=>{ error(node,Error(err)); } ), JSONToConfluence:JSONToConfluence, JSONToCSV: (RED,node,msg,data)=>Array2csv(node,data), JSONToHTML: (RED,node,msg,data,level=0)=>{ if(Array.isArray(data)) { return data.length?"<table><tr>"+data.map((r)=>functions.JSONToHTML(RED,node,msg,r,++level)).join("</tr><tr>")+"</tr><table>":""; } if(data instanceof Object){ let a=[]; for(let p in data) { a.push("<td style='vertical-align: top;'>"+escape(p)+":</td><td>"+functions.JSONToHTML(RED,node,msg,data[p],++level)+"</td>"); } return "<table><tr>"+a.join("</tr><tr>")+"</tr><table>"; } return escape(data); }, JSONToISO8385: (RED,node,msg,data)=>{ var d=[]; Object.getOwnPropertyNames(data).forEach((v)=>d.push([ISO8583BitMapName[v].id,data[v]])); d.sort((a, b) => a[0] - b[0]); return ISO8583message.packSync(d); }, JSONToMessages: (RED,node,msg,data)=>{ if(logger.active) logger.send({label:"JSONToMessages",messages:data.length}); if(Array.isArray(data)) { new node.SendArray(RED,node,msg,data); } else { const newMsg=RED.util.cloneMessage(msg); newMsg._msgid=newMsg._msgid+":0"; node.setData(RED,node,newMsg,data,0) node.send(newMsg); } }, JSONTonpy: (RED,node,msg,data)=>new NumPy(data).toNpyBuffer(), JSONToNumPyObject: (RED,node,msg,data)=>new NumPy(data), JSONToString: (RED,node,msg,data)=>JSON.stringify(data), JSONToXLSX:JSONToXLSX, JSONToXLSXObject:JSONToXLSXObject, JSONToXML: (RED,node,msg,data)=>json2xmlParser.parse(data), npyToJSON: (RED,node,msg,data)=>new NumPy(data).toSerializable(), npyToNumPyObject: (RED,node,msg,data)=>new NumPy(data), NumPyObjectToJSON: (RED,node,msg,data)=> data.toSerializable(), NumberToAbbreviated: (RED,node,msg,data)=> data?data.isAbbreviated():data, NumberToisBetween: (RED,node,msg,data)=> data.isBetween(node.minNumber,node.maxNumber), NumberToRangeLimit: (RED,node,msg,data)=> data?data.rangeLimit(node.minNumber,node.maxNumber):node.minNumber, ObjectToCoalesce: (RED,node,msg,data)=>coalesce(data,node.value), ObjectToDeepClone: (RED,node,msg,data)=>daat.deepClone(), ObjectToNullif: (RED,node,msg,data)=>nullif(data,node.value), StringToAppend: (RED,node,msg,data)=>data.concat(node.getString(msg)), StringToArrayByDelimiter: (RED,node,msg,data)=>data .split(node.delimiter??',') .map(entry => entry.trim()) .filter(entry => entry), StringToAt: (RED,node,msg,data)=>data.At(node.index), StringToCapitalize: (RED,node,msg,data)=> data.capitalize(), StringToCamelize: (RED,node,msg,data)=>data.toLowerCase().replace(/[^a-zA-Z0-9]+(.)/g, (m, chr) => chr.toUpperCase()), StringToCharAt: (RED,node,msg,data)=>data.charAt(node.index), StringToCharCodeAt: (RED,node,msg,data)=>data.charCodeAt(node.index), StringToCodePointAt: (RED,node,msg,data)=>data.codePointAt(node.index), StringToCompressed: (RED,node,msg,data)=>compressor.compress(data, (compressed)=>{ node.setData(RED,node,msg,compressed); node.send(msg); }, (err)=>{ error(node,Error(err)); } ), StringToConcat: (RED,node,msg,data)=>data.concat(node.getString(msg)), StringToDate: (RED,node,msg,data)=>toDateTypeZulu(data), StringToDateLocal: (RED,node,msg,data)=>new Date(data), StringToTimestamp: (RED,node,msg,data)=>Date.parse(data), StringToDelimiterOnCase:(RED,node,msg,data)=>data.replace(/[A-Z]/g, (letter, index) => { const lcLet = letter.toLowerCase(); const separator= node.delimiter??"-" return index ? separator + lcLet : lcLet; }) .replace(/([-_ ]){1,}/g,node.delimiter??"-"), StringToDeunderscore: (RED,node,msg,data)=> data.deunderscore(), StringToDeunderscoreCapitilize: (RED,node,msg,data)=> data.deunderscoreCapitilize(), StringToDropSquareBracketPrefix: (RED,node,msg,data)=> data.dropSquareBracketPrefix(), StringToEndsWith: (RED,node,msg,data)=> data.endsWith(node.getString(msg)), StringToFloat: (RED,node,msg,data)=>parseFloat(data), StringToGetWord: (RED,node,msg,data)=> data.getWord(node.index), StringToInteger: (RED,node,msg,data)=>parseInt(data, node.radix??10), StringToisBetween: (RED,node,msg,data)=> data.isBetween(node.minString,node.maxString), StringToJSON: (RED,node,msg,data)=>JSON.parse(data), StringToLowerCase: (RED,node,msg,data)=> data.toLowerCase(), StringToNumber: (RED,node,msg,data)=>Number(data), StringToPrepend: (RED,node,msg,data)=>node.getString(msg).concat(data), StringToRangeLimit: (RED,node,msg,data)=> data?data.rangeLimit(node.minString,node.maxString):node.minString, StringToReal: (RED,node,msg,data)=> data.toReal(), StringToSplit: (RED,node,msg,data)=>data.split(node.getString(msg)), StringToStartsWith: (RED,node,msg,data)=> data.startsWith(node.getString(msg)), StringToTitle: (RED,node,msg,data)=>data.toTitle(), StringTotTitleGrammatical: (RED,node,msg,data)=>data.toTitleGrammatical(), StringToTrim: (RED,node,msg,data)=>data.trim(), StringToTrimEnd: (RED,node,msg,data)=>data.trimEnd(), StringToTrimStart: (RED,node,msg,data)=>data.trimStart(), StringToUpperCase: (RED,node,msg,data)=> data.toUpperCase(), StringToXmlStringEncode: (RED,node,msg,data)=> data.xmlStringEncode(), pathToBasename: (RED,node,msg,data)=>path.basename(data), pathToDirname: (RED,node,msg,data)=>path.dirname(data), pathToExtname: (RED,node,msg,data)=>path.extname(data), pathToFormat: (RED,node,msg,data)=>path.format(data), pathToIsAbsolute: (RED,node,msg,data)=>path.isAbsolute(data), pathToJoin: (RED,node,msg,...data)=>path.join(...data), pathToParse: (RED,node,msg,data)=>path.parse(data), pathToNormalize: (RED,node,msg,data)=>path.normalize(data), pathToResolve: (RED,node,msg,data)=>path.resolve(data), snappyToCompress: (RED,node,msg,data)=>{ if(logger.active) logger.send({label:"snappyToCompress"}); snappy.compress(data, (err, data)=>{ if(logger.active) logger.send({label:"snappy.compress",error:err}) if(err) { error(node,Error(err)); return; } node.setData(RED,node,msg,data) node.send(msg); }) }, snappyToUncompress: (RED,node,msg,data)=>{ if(logger.active) logger.send({label:"snappyToUncompress"}); snappy.uncompress(data, { asBuffer: false }, (err, data)=>{ if(logger.active) logger.send({label:"snappy.uncompress",error:err}); if(err) { error(node,Error(err)); return; } node.setData(RED,node,msg,data) node.send(msg); }) }, XLSXToArray:XLSXToArray, XLSXObjectToArray:XLSXObjectToArray, XLSXToJSON:XLSXToJSON, XLSXObjectToJSON:XLSXObjectToJSON, XLSXToXLSXObject:XLSXToXLSXObject, XMLToJSON: (RED,node,msg,data)=>xmlParser.parse(data,XMLoptions,true), invalidArray:(v=>!Array.isArray(v)) }; function evalFunction(id,mapping){ try{ return eval(mapping); } catch(ex) { throw Error(id+" "+ex.message); } } const is=(node,value)=>{ return node.actionSource==value||node.actionTarget==value; } let jsonata; function JSONataTransform(data,ok,error){ /* (async () => { return result = await expression.evaluate(data); })() */ this.transformFunctionCompiled.evalFunction(data,{},(error, result) => { if(error) { console.error(error); return; } console.log("Finished with", result); }); } module.exports = function (RED) { function transformNode(n) { RED.nodes.createNode(this,n); if(logger.active) logger.send({label:"transformNode",node:n}); let node=Object.assign(this,{maxMessages:1000,SendArray:SendArray},n,{RED:RED}); try{ if(is(node,"XLSX")||is(node,"XLSXObject") ) { if(!XLSX) XLSX=require('xlsx'); } else if(is(node,"AVRO") || is(node,"Confluence")) { if(avsc==null) avsc=require('avsc'); try{ node.schemaValid=eval("("+node.schema+")"); } catch(ex){ throw Error("schema "+ex.message); } if(!node.schemaValid) throw Error("invalid schema") } else if(is(node,"snappy")) { if(snappy==null) snappy=require('snappy'); } else if(is(node,"XML")) { if(xmlParser==null) xmlParser=require('fast-xml-parser'); if(json2xmlParser==null) { const j2xParser=xmlParser.j2xParser; json2xmlParser=new j2xParser(XMLoptions); } if(logger.active) logger.send({label:"load xml",xmlParserKeys:Object.keys(xmlParser),json2xmlParser:Object.keys(json2xmlParser)}); } if(['Append','Concat','EndsWith','Prepend','Split','StartsWith'].includes(node.actionTarget)) { typedInput.setGetFunction(RED,node,"string") } node.sendInFunction=["snappy","Compressed"].includes(node.actionSource)||["Messages","Compressed"].includes(node.actionTarget); node.hasNewTopic=![null,""].includes(node.topicProperty); const source=(node.sourceProperty||"msg.payload") const target=(node.targetProperty||"msg.payload") const sourceMap="(RED,node,msg)=>"+source, deleteSource=typedInput.getValue(RED,node,"deleteSource",true) targetMap="(RED,node,msg,data,index)=>{"+target+"=data;"+ (node.sendInFunction && node.hasNewTopic? "msg.topic=node.topicFunction(RED,node,msg,data,index);":"")+ (deleteSource&&source!==target?"delete "+source+";"+"delete "+source+";":"")+ (node.sendInFunction ? "" : "node.send(msg);" )+ "}", topicMap="(RED,node,msg,data,index)=>"+(node.topicProperty||"msg.topic"); logger.sendInfo({label:"mappings",source:sourceMap,deleteSource:deleteSource,target:targetMap,topicMap:topicMap}); node.getData=evalFunction("source",sourceMap); node.setData=evalFunction("target",targetMap); node.topicFunction=evalFunction("topic",topicMap); if(is(node,"AVRO")) { node.avroTransformer=avsc.Type.forSchema(node.schemaValid); } else if(is(node,"Compressed")) { const CompressionTool = require('compressiontool') compressor=new CompressionTool(); compressor[node.compressionType](); } else if(is(node,"Confluence")) { node.schemas={}; for(const schema in node.schemaValid ) node.schemas[schema]=avsc.Type.forSchema(node.schemaValid[schema]); logger.info({label:"confluence",schemas:Object.keys(node.schemas)}); } else if(node.actionSource=="Date") { if(node.maxDate) node.maxDateTyped=toDateTypeZulu(node.maxDate) if(node.minDate) node.minDateTyped=toDateTypeZulu(node.minDate) } if(node.actionTarget=="Compressed"){ const CompressionTool = require('compressiontool') compressor=new CompressionTool(); compressor[node.compressionType](); } } catch(ex) { logger.error(n); error(node,ex,"Invalid setup "+ex.message); return; } if(is(node,"ISO8583")) { if(!ISO8583) { try{ ISO8583=require('iso-8583'); ISO8583message=ISO8583.Message(); node.log("loaded iso-8583"); } catch (ex) { error(node,Error("need to run 'npm install iso-8583'"),"iso-8583 not installed"); return; } } } if(node.transformFunction && is(node,"JSON")) { try{ if(!jsonata) jsonata=require('jsonata') node.transformFunctionCompiled = jsonata(node.transformFunction); } catch (ex) { error(node,ex,"Transform function error"); return; } } const typeValidate="invalid"+node.actionSource; node.invalidSourceType=typeValidate in functions &! ["XLSX","XLSXObject"].includes(node.actionTarget)?functions[typeValidate]:(()=>false); try { node.transform=functions[node.actionSource+"To"+node.actionTarget]; if(!node.transform) throw Error("transform routine not found for "+node.actionSource+" to "+node.actionTarget); } catch (ex) { error(node,ex,node.actionSource+"\nto "+node.actionTarget + " not implemented") return; } node.processMsg=node.sendInFunction?this.transform :(RED,node,msg,data)=>node.setData(RED,node,msg,node.transform(RED,node,msg,data)); this.status({fill:"green",shape:"ring",text:"Ready"}); node.on("input", function(msg) { if(logger.active) logger.send({label:"input",msgid:msg._msgid,topic:msg.topic}); try{ const data=node.getData(RED,node,msg); if(node.invalidSourceType(data)) throw Error("expected source data type "+node.actionSource); node.processMsg(RED,node,msg,data); } catch (ex) { if(logger.active) logger.sendErrorAndDump("on input error",ex) msg.error=node.actionSource+" to "+node.actionTarget + " " +ex.message; error(node,Error(msg.error),"Error(s)"); node.send([null,msg]); } }); } RED.nodes.registerType(logger.label,transformNode); };