node-red-contrib-prib-functions 0.21.0 → 0.23.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,8 @@
1
1
  const logger = new (require("node-red-contrib-logger"))("transform");
2
2
  logger.sendInfo("Copyright 2020 Jaroslav Peter Prib");
3
- const CompressionTool = require('compressiontool');
4
3
  const NumPy = require("./NumPy.js")
4
+ const typedInput = require("../lib/typedInput.js")
5
+ const {coalesce,nullif,toDateTypeZulu}=require("../lib/objectExtensions")
5
6
  const regexCSV=/,(?=(?:(?:[^"]*"){2})*[^"]*$)/,
6
7
  Buffer=require('buffer').Buffer,
7
8
  os=require('os'),
@@ -28,12 +29,13 @@ const XMLoptions = {
28
29
  // stopNodes: ["parse-me-as-string"]
29
30
  trimValues: false
30
31
  };
31
- function error(node,ex,shortMessage){
32
+ const makeDateType=data=>(data instanceof Date? data:new Date(data))
33
+ const error=(node,ex,shortMessage)=>{
32
34
  if(logger.active) logger.send({label:"transformNode catch",shortMessage:shortMessage,error:ex.message,stack:ex.stack});
33
35
  node.error(ex.message);
34
36
  node.status({fill:"red",shape:"ring",text:(shortMessage||ex.message).substr(0,50)});
35
37
  }
36
- function getAvroTransformer(node,schema) {
38
+ const getAvroTransformer=(node,schema)=>{
37
39
  try{
38
40
  return avsc.Type.forSchema(node.schemas[schema]);
39
41
  } catch(ex){
@@ -42,32 +44,19 @@ function getAvroTransformer(node,schema) {
42
44
  }
43
45
  }
44
46
 
45
- function addWorksheet2JSON(object,worksheet,workbook,options){
47
+ const addWorksheet2JSON=(object,worksheet,workbook,options)=>{
46
48
  object[worksheet]=XLSX.utils.sheet_to_json(workbook.Sheets[worksheet],options);
47
49
  if(options.header) object[worksheet].shift();
48
50
  if(logger.active) logger.send({label:"addWorksheet2JSON",object:object,worksheet:worksheet})
49
51
  return object;
50
52
  }
51
- function XLSXObjectToJSON(RED,node,msg,data){
52
- return data.SheetNames.reduce((a,worksheet)=>addWorksheet2JSON(a,worksheet,data),{})
53
- }
54
- function XLSXToArray(RED,node,msg,data){
55
- return XLSXObjectToArray(RED,node,msg,XLSXToXLSXObject(RED,node,msg,data));
56
- }
57
- function XLSXToJSON(RED,node,msg,data){
58
- return XLSXObjectToJSON(RED,node,msg,XLSXToXLSXObject(RED,node,msg,data));
59
- }
60
- function XLSXToXLSXObject(RED,node,msg,data){
61
- return XLSX.read(data, {raw:true,type: 'buffer' });
62
- }
63
- function XLSXObjectToArray(RED,node,msg,data){
64
- return data.SheetNames.reduce((a,worksheet)=>addWorksheet2JSON(a,worksheet,data,{header:1,raw:true}),{})
65
- }
66
- function JSONToXLSX(RED,node,msg,data){
67
- const workbook=JSONToXLSXObject(RED,node,msg,data);
68
- return XLSX.write(workbook, {bookType:"xlsx", type:'buffer'});
69
- }
70
- function JSONToXLSXObject(RED,node,msg,data){
53
+ const XLSXObjectToJSON=(RED,node,msg,data)=>data.SheetNames.reduce((a,worksheet)=>addWorksheet2JSON(a,worksheet,data),{})
54
+ const XLSXToArray=(RED,node,msg,data)=>XLSXObjectToArray(RED,node,msg,XLSXToXLSXObject(RED,node,msg,data))
55
+ const XLSXToJSON=(RED,node,msg,data)=>XLSXObjectToJSON(RED,node,msg,XLSXToXLSXObject(RED,node,msg,data))
56
+ const XLSXToXLSXObject=(RED,node,msg,data)=>XLSX.read(data, {raw:true,type: 'buffer' })
57
+ const XLSXObjectToArray=(RED,node,msg,data)=>data.SheetNames.reduce((a,worksheet)=>addWorksheet2JSON(a,worksheet,data,{header:1,raw:true}),{})
58
+ const JSONToXLSX=(RED,node,msg,data)=>XLSX.write(JSONToXLSXObject(RED,node,msg,data), {bookType:"xlsx", type:'buffer'})
59
+ const JSONToXLSXObject=(RED,node,msg,data)=>{
71
60
  const workbook = XLSX.utils.book_new();
72
61
  for(const worksheet in data) {
73
62
  const ws=XLSX.utils.json_to_sheet(data[worksheet]);
@@ -75,11 +64,8 @@ function JSONToXLSXObject(RED,node,msg,data){
75
64
  }
76
65
  return workbook;
77
66
  }
78
- function ArrayToXLSX(RED,node,msg,data){
79
- const workbook=ArrayToXLSXObject(RED,node,msg,data);
80
- return XLSX.write(workbook, {bookType:"xlsx", type:'buffer'});
81
- }
82
- function ArrayToXLSXObject(RED,node,msg,data){
67
+ const ArrayToXLSX=(RED,node,msg,data)=>XLSX.write(ArrayToXLSXObject(RED,node,msg,data), {bookType:"xlsx", type:'buffer'})
68
+ const ArrayToXLSXObject=(RED,node,msg,data)=>{
83
69
  const workbook = XLSX.utils.book_new();
84
70
  if(Array.isArray(data)) {
85
71
  const ws=XLSX.utils.aoa_to_sheet(data);
@@ -92,7 +78,7 @@ function ArrayToXLSXObject(RED,node,msg,data){
92
78
  }
93
79
  return workbook;
94
80
  }
95
- function ConfluenceToJSON(RED,node,msg,data){
81
+ const ConfluenceToJSON=(RED,node,msg,data)=>{
96
82
  if(!Buffer.isBuffer(data)) data=Buffer.from(data);
97
83
  const magicByte=data.readUInt8();
98
84
  if(magicByte!==0) throw Error("expected magic byte and not found, found "+magicByte);
@@ -101,8 +87,7 @@ function ConfluenceToJSON(RED,node,msg,data){
101
87
  const avroTransformer=getAvroTransformer(node,schema);
102
88
  return {schema:schema,data:avroTransformer.fromBuffer(data.subarray(5))};
103
89
  }
104
-
105
- function JSONToConfluence(RED,node,msg,data){
90
+ const JSONToConfluence=(RED,node,msg,data)=>{
106
91
  if(!data.schema) throw Error("property schema not defined");
107
92
  if(!data.data) throw Error("property data not defined");
108
93
  const header=Buffer.alloc(5);
@@ -112,7 +97,6 @@ function JSONToConfluence(RED,node,msg,data){
112
97
  const avro=transformer.toBuffer(data.data);
113
98
  return Buffer.concat([header,avro]);
114
99
  }
115
-
116
100
  function SendArray(RED,node,msg,array){
117
101
  if(logger.active) logger.send({label:"SendArray",size:array.length});
118
102
  this.index=0;
@@ -120,7 +104,6 @@ function SendArray(RED,node,msg,array){
120
104
  this.node=node;
121
105
  this.msg=msg;
122
106
  this.array=array;
123
- node.deleteSourceProperty(RED,node,msg);
124
107
  this.next();
125
108
  }
126
109
  SendArray.prototype.next=function() {
@@ -135,6 +118,7 @@ SendArray.prototype.next=function() {
135
118
  this.lastTouchTime=currentTime;
136
119
 
137
120
  let i=cpuUsedRatio>0.9 || memoryUsedRatio>0.9 || heapUsedRatio>0.99?1:100;
121
+ const newMsgs=[]
138
122
  while(--i) {
139
123
  if(this.index>=this.array.length) {
140
124
  delete this;
@@ -144,12 +128,13 @@ SendArray.prototype.next=function() {
144
128
  newMsg._msgid=newMsg._msgid+":"+index;
145
129
  this.node.setData(this.RED,this.node,newMsg,this.array[index],index)
146
130
  this.index++;
147
- this.node.send(newMsg);
131
+ newMsgs.push(newMsg);
148
132
  }
133
+ this.node.send([newMsgs]);
149
134
  const call=this.next.bind(this);
150
135
  this.timeoutID=setTimeout(call, 100);
151
136
  };
152
- function removeQuotes(data){
137
+ const removeQuotes=(data)=>{
153
138
  try{
154
139
  const d=data.trim();
155
140
  if(d.length>1 && d.startsWith('"') && d.endsWith('"')) return d.slice(1,-1);
@@ -159,7 +144,7 @@ function removeQuotes(data){
159
144
  return data;
160
145
  }
161
146
  }
162
- function csvLines(data,skipLeading=0,skipTrailing=0) {
147
+ const csvLines=(data,skipLeading=0,skipTrailing=0)=>{
163
148
  if(logger.active) logger.send({label:"csvLines",skipLeading:skipLeading,skipTrailing:skipTrailing});
164
149
  let lines=data.split(/[\r\n]+/g),skip=skipLeading;
165
150
  while(skip--) lines.shift();
@@ -167,11 +152,11 @@ function csvLines(data,skipLeading=0,skipTrailing=0) {
167
152
  while(skip--) lines.pop();
168
153
  return lines;
169
154
  }
170
- function array2tag(a,t,tf){
155
+ const array2tag=(a,t,tf)=>{
171
156
  const ts="<"+t+">",te="</"+t+">"
172
157
  return a.reduce((a,c)=>a+=ts+tf(c)+te,"");
173
158
  }
174
- function Array2csv(node,data){
159
+ const Array2csv=(node,data)=>{
175
160
  if(!(data instanceof Array)) return JSON.stringify(data);
176
161
  if(data.length==0) return;
177
162
  if(data[0] instanceof Array) {
@@ -217,17 +202,20 @@ const functions={
217
202
  ArrayToMessages: (RED,node,msg,data)=>{
218
203
  if(logger.active) logger.send({label:"ArrayToMessages",arraySize:data.length});
219
204
  if(data.length>node.maxMessages) throw Error("messages to be created "+data.length +"> max: "+node.maxMessages);
205
+ const newMsgs=[]
220
206
  data.map((row,i)=>{
221
207
  const newMsg=RED.util.cloneMessage(msg);
222
208
  newMsg._msgid=newMsg._msgid+":"+i;
223
209
  if(logger.active) logger.send({label:"ArrayToMessages",row:row,index:i});
224
210
  node.setData(RED,node,newMsg,row,i)
225
- node.send(newMsg);
211
+ newMsgs.push(newMsg);
226
212
  });
213
+ node.send([newMsgs])
227
214
  },
228
215
  ArrayToXLSX:ArrayToXLSX,
229
216
  ArrayToXLSXObject:ArrayToXLSXObject,
230
217
  AVROToJSON: (RED,node,msg,data)=>node.avroTransformer.fromBuffer(data), // = {kind: 'CAT', name: 'Albert'}
218
+ BigIntToRangeLimit: (RED,node,msg,data)=> data?data.rangeLimit(node.minBigIntTyped,node.maxBigIntTyped):node.minBigInt,
231
219
  BufferToCompressed: (RED,node,msg,data)=>compressor.compress(data,
232
220
  (compressed)=>{
233
221
  node.setData(RED,node,msg,compressed);
@@ -314,6 +302,10 @@ const functions={
314
302
  });
315
303
  return lines;
316
304
  },
305
+ DateToisBetween: (RED,node,msg,data)=> toDateTypeZulu(data).isBetween(node.minDateTyped,node.maxDateTyped),
306
+ DateToISODate: (RED,node,msg,data)=> toDateTypeZulu(data).toISOString().slice(0,10),
307
+ DateToLocalDate: (RED,node,msg,data)=> toDateTypeZulu(data).toLocaleDateString().slice(0,10),
308
+ DateToRangeLimit: (RED,node,msg,data)=> (data? toDateTypeZulu(data).rangeLimit(node.minDateTyped,node.maxDateTyped):node.minDateTyped),
317
309
  ISO8385ToArray: (RED,node,msg,data)=>ISO8583message.unpackSync(data, data.length),
318
310
  ISO8385ToJSON: (RED,node,msg,data)=>{
319
311
  let j={},d=ISO8583message.unpackSync(data, data.length);
@@ -325,7 +317,8 @@ const functions={
325
317
  JSONToArray: (RED,node,msg,data)=>{
326
318
  if(data instanceof Object){
327
319
  let a=[];
328
- for(let p in data) {
320
+ properties=Object.keys(data)
321
+ for(const p of properties) {
329
322
  a.push([p,functions.JSONToArray(RED,node,msg,data[p])]);
330
323
  }
331
324
  return a;
@@ -367,7 +360,6 @@ const functions={
367
360
  if(logger.active) logger.send({label:"JSONToMessages",messages:data.length});
368
361
  if(Array.isArray(data)) {
369
362
  new node.SendArray(RED,node,msg,data);
370
- // functions.ArrayToMessages(RED,node,msg,data);
371
363
  } else {
372
364
  const newMsg=RED.util.cloneMessage(msg);
373
365
  newMsg._msgid=newMsg._msgid+":0";
@@ -384,6 +376,23 @@ const functions={
384
376
  npyToJSON: (RED,node,msg,data)=>new NumPy(data).toSerializable(),
385
377
  npyToNumPyObject: (RED,node,msg,data)=>new NumPy(data),
386
378
  NumPyObjectToJSON: (RED,node,msg,data)=> data.toSerializable(),
379
+ NumberToAbbreviated: (RED,node,msg,data)=> data?data.isAbbreviated():data,
380
+ NumberToisBetween: (RED,node,msg,data)=> data.isBetween(node.minNumber,node.maxNumber),
381
+ NumberToRangeLimit: (RED,node,msg,data)=> data?data.rangeLimit(node.minNumber,node.maxNumber):node.minNumber,
382
+ ObjectToCoalesce: (RED,node,msg,data)=>coalesce(data,node.value),
383
+ ObjectToDeepClone: (RED,node,msg,data)=>daat.deepClone(),
384
+ ObjectToNullif: (RED,node,msg,data)=>nullif(data,node.value),
385
+ StringToAppend: (RED,node,msg,data)=>data.concat(node.getString(msg)),
386
+ StringToArrayByDelimiter: (RED,node,msg,data)=>data
387
+ .split(node.delimiter??',')
388
+ .map(entry => entry.trim())
389
+ .filter(entry => entry),
390
+ StringToAt: (RED,node,msg,data)=>data.At(node.index),
391
+ StringToCapitalize: (RED,node,msg,data)=> data.capitalize(),
392
+ StringToCamelize: (RED,node,msg,data)=>data.toLowerCase().replace(/[^a-zA-Z0-9]+(.)/g, (m, chr) => chr.toUpperCase()),
393
+ StringToCharAt: (RED,node,msg,data)=>data.charAt(node.index),
394
+ StringToCharCodeAt: (RED,node,msg,data)=>data.charCodeAt(node.index),
395
+ StringToCodePointAt: (RED,node,msg,data)=>data.codePointAt(node.index),
387
396
  StringToCompressed: (RED,node,msg,data)=>compressor.compress(data,
388
397
  (compressed)=>{
389
398
  node.setData(RED,node,msg,compressed);
@@ -393,7 +402,39 @@ const functions={
393
402
  error(node,Error(err));
394
403
  }
395
404
  ),
396
- StringToJSON: (RED,node,msg,data)=>JSON.parse(data),
405
+ StringToConcat: (RED,node,msg,data)=>data.concat(node.getString(msg)),
406
+ StringToDate: (RED,node,msg,data)=>toDateTypeZulu(data),
407
+ StringToDateLocal: (RED,node,msg,data)=>new Date(data),
408
+ StringToTimestamp: (RED,node,msg,data)=>Date.parse(data),
409
+ StringToDelimiterOnCase:(RED,node,msg,data)=>data.replace(/[A-Z]/g, (letter, index) => {
410
+ const lcLet = letter.toLowerCase();
411
+ const separator= node.delimiter??"-"
412
+ return index ? separator + lcLet : lcLet;
413
+ })
414
+ .replace(/([-_ ]){1,}/g,node.delimiter??"-"),
415
+ StringToDeunderscore: (RED,node,msg,data)=> data.deunderscore(),
416
+ StringToDeunderscoreCapitilize: (RED,node,msg,data)=> data.deunderscoreCapitilize(),
417
+ StringToDropSquareBracketPrefix: (RED,node,msg,data)=> data.dropSquareBracketPrefix(),
418
+ StringToEndsWith: (RED,node,msg,data)=> data.endsWith(node.getString(msg)),
419
+ StringToFloat: (RED,node,msg,data)=>parseFloat(data),
420
+ StringToGetWord: (RED,node,msg,data)=> data.getWord(node.index),
421
+ StringToInteger: (RED,node,msg,data)=>parseInt(data, node.radix??10),
422
+ StringToisBetween: (RED,node,msg,data)=> data.isBetween(node.minString,node.maxString),
423
+ StringToJSON: (RED,node,msg,data)=>JSON.parse(data),
424
+ StringToLowerCase: (RED,node,msg,data)=> data.toLowerCase(),
425
+ StringToNumber: (RED,node,msg,data)=>Number(data),
426
+ StringToPrepend: (RED,node,msg,data)=>node.getString(msg).concat(data),
427
+ StringToRangeLimit: (RED,node,msg,data)=> data?data.rangeLimit(node.minString,node.maxString):node.minString,
428
+ StringToReal: (RED,node,msg,data)=> data.toReal(),
429
+ StringToSplit: (RED,node,msg,data)=>data.split(node.getString(msg)),
430
+ StringToStartsWith: (RED,node,msg,data)=> data.startsWith(node.getString(msg)),
431
+ StringToTitle: (RED,node,msg,data)=>data.toTitle(),
432
+ StringTotTitleGrammatical: (RED,node,msg,data)=>data.toTitleGrammatical(),
433
+ StringToTrim: (RED,node,msg,data)=>data.trim(),
434
+ StringToTrimEnd: (RED,node,msg,data)=>data.trimEnd(),
435
+ StringToTrimStart: (RED,node,msg,data)=>data.trimStart(),
436
+ StringToUpperCase: (RED,node,msg,data)=> data.toUpperCase(),
437
+ StringToXmlStringEncode: (RED,node,msg,data)=> data.xmlStringEncode(),
397
438
  pathToBasename: (RED,node,msg,data)=>path.basename(data),
398
439
  pathToDirname: (RED,node,msg,data)=>path.dirname(data),
399
440
  pathToExtname: (RED,node,msg,data)=>path.extname(data),
@@ -443,7 +484,7 @@ function evalFunction(id,mapping){
443
484
  throw Error(id+" "+ex.message);
444
485
  }
445
486
  }
446
- function is(node,value){
487
+ const is=(node,value)=>{
447
488
  return node.actionSource==value||node.actionTarget==value;
448
489
  }
449
490
  let jsonata;
@@ -454,7 +495,7 @@ function JSONataTransform(data,ok,error){
454
495
  })()
455
496
  */
456
497
 
457
- this.transformFuncionCompiled.evalFunction(data,{},(error, result) => {
498
+ this.transformFunctionCompiled.evalFunction(data,{},(error, result) => {
458
499
  if(error) {
459
500
  console.error(error);
460
501
  return;
@@ -489,32 +530,42 @@ module.exports = function (RED) {
489
530
  }
490
531
  if(logger.active) logger.send({label:"load xml",xmlParserKeys:Object.keys(xmlParser),json2xmlParser:Object.keys(json2xmlParser)});
491
532
  }
533
+ if(['Append','Concat','EndsWith','Prepend','Split','StartsWith'].includes(node.actionTarget)) {
534
+ typedInput.setGetFunction(RED,node,"string")
535
+ }
492
536
  node.sendInFunction=["snappy","Compressed"].includes(node.actionSource)||["Messages","Compressed"].includes(node.actionTarget);
493
537
  node.hasNewTopic=![null,""].includes(node.topicProperty);
494
- const sourceMap="(RED,node,msg)=>"+(node.sourceProperty||"msg.payload"),
495
- sourceDelete="(RED,node,msg)=>{delete "+(node.sourceProperty||"msg.payload")+";}",
496
- targetMap="(RED,node,msg,data,index)=>{"+(node.targetProperty||"msg.payload")+"=data;"+
538
+ const source=(node.sourceProperty||"msg.payload")
539
+ const target=(node.targetProperty||"msg.payload")
540
+ const sourceMap="(RED,node,msg)=>"+source,
541
+ deleteSource=typedInput.getValue(RED,node,"deleteSource",true)
542
+ targetMap="(RED,node,msg,data,index)=>{"+target+"=data;"+
497
543
  (node.sendInFunction && node.hasNewTopic? "msg.topic=node.topicFunction(RED,node,msg,data,index);":"")+
544
+ (deleteSource&&source!==target?"delete "+source+";"+"delete "+source+";":"")+
498
545
  (node.sendInFunction ? "" : "node.send(msg);" )+
499
546
  "}",
500
547
  topicMap="(RED,node,msg,data,index)=>"+(node.topicProperty||"msg.topic");
501
- logger.sendInfo({label:"mappings",source:sourceMap,target:targetMap,topicMap:topicMap});
548
+ logger.sendInfo({label:"mappings",source:sourceMap,deleteSource:deleteSource,target:targetMap,topicMap:topicMap});
502
549
  node.getData=evalFunction("source",sourceMap);
503
- node.deleteSourceProperty=evalFunction("source delete",sourceDelete);
504
550
  node.setData=evalFunction("target",targetMap);
505
551
  node.topicFunction=evalFunction("topic",topicMap);
506
552
  if(is(node,"AVRO")) {
507
553
  node.avroTransformer=avsc.Type.forSchema(node.schemaValid);
508
- } else if(is(node,"Compressed")) {
554
+ } else if(is(node,"Compressed")) {
555
+ const CompressionTool = require('compressiontool')
509
556
  compressor=new CompressionTool();
510
557
  compressor[node.compressionType]();
511
- } else if(is(node,"Confluence")) {
558
+ } else if(is(node,"Confluence")) {
512
559
  node.schemas={};
513
560
  for(const schema in node.schemaValid )
514
561
  node.schemas[schema]=avsc.Type.forSchema(node.schemaValid[schema]);
515
562
  logger.info({label:"confluence",schemas:Object.keys(node.schemas)});
563
+ } else if(node.actionSource=="Date") {
564
+ if(node.maxDate) node.maxDateTyped=toDateTypeZulu(node.maxDate)
565
+ if(node.minDate) node.minDateTyped=toDateTypeZulu(node.minDate)
516
566
  }
517
567
  if(node.actionTarget=="Compressed"){
568
+ const CompressionTool = require('compressiontool')
518
569
  compressor=new CompressionTool();
519
570
  compressor[node.compressionType]();
520
571
  }
@@ -523,7 +574,7 @@ module.exports = function (RED) {
523
574
  error(node,ex,"Invalid setup "+ex.message);
524
575
  return;
525
576
  }
526
- if(node.actionSource=="ISO8583" || node.actionTarget=="ISO8583") {
577
+ if(is(node,"ISO8583")) {
527
578
  if(!ISO8583) {
528
579
  try{
529
580
  ISO8583=require('iso-8583');
@@ -535,10 +586,10 @@ module.exports = function (RED) {
535
586
  }
536
587
  }
537
588
  }
538
- if(node.transformFuncion && ( node.actionSource=="JSON" || node.actionTarget=="JSON" )) {
589
+ if(node.transformFunction && is(node,"JSON")) {
539
590
  try{
540
591
  if(!jsonata) jsonata=require('jsonata')
541
- node.transformFuncionCompiled = jsonata(node.transformFuncion);
592
+ node.transformFunctionCompiled = jsonata(node.transformFunction);
542
593
  } catch (ex) {
543
594
  error(node,ex,"Transform function error");
544
595
  return;
@@ -0,0 +1 @@
1
+ const square=[[0,0],[1,0],[1,1],[0,1]]
File without changes
@@ -0,0 +1,45 @@
1
+ const logger = new (require("node-red-contrib-logger"))("visual");
2
+ logger.sendInfo("Copyright 2025 Jaroslav Peter Prib");
3
+ const levenshteinDistance = require("./levenshteinDistance");
4
+ function error(node,message,shortMessage){
5
+ if(logger.active) logger.send({label:"error",node:node.id,error:error,shortMessage});
6
+ node.error(message);
7
+ node.status({fill:"red",shape:"ring",text:shortMessage});
8
+ }
9
+ function evalFunction(id,mapping){
10
+ try{
11
+ return eval(mapping);
12
+ } catch(ex) {
13
+ throw Error(id+" "+ex.message);
14
+ }
15
+ }
16
+ module.exports = function (RED) {
17
+ function loggerNode (n) {
18
+ RED.nodes.createNode(this, n);
19
+ const node = Object.assign(this, n);
20
+
21
+ const source1Map="(RED,node,msg)=>"+(node.source1Property||"msg.payload"),
22
+ source2Map="(RED,node,msg)=>"+(node.source2Property||"msg.payload"),
23
+ targetMap="(RED,node,msg,data)=>{"+(node.targetProperty||"msg.payload")+"=data;}";
24
+ logger.sendInfo({label:"mappings",source1:source1Map,source2:source2Map,target:targetMap});
25
+ try{
26
+ node.getData1=evalFunction("source1",source1Map);
27
+ node.getData2=evalFunction("source2",source2Map);
28
+ node.setData=evalFunction("target",targetMap);
29
+ } catch(ex) {
30
+ error(node,ex,"Invalid setup "+ex.message);
31
+ return;
32
+ }
33
+ node.on('input', function (msg) {
34
+ try{
35
+ node.setData(RED,node,msg,levenshteinDistance(node.getData1(RED,node,msg),node.getData2(RED,node,msg)));
36
+ node.send(msg);
37
+ } catch(ex) {
38
+ msg.error=ex.message;
39
+ error(node,ex,"Error(s), check log");
40
+ node.send([null,msg]);
41
+ }
42
+ });
43
+ }
44
+ RED.nodes.registerType(logger.label, loggerNode);
45
+ };