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

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.
@@ -10,6 +10,7 @@ const regexCSV=/,(?=(?:(?:[^"]*"){2})*[^"]*$)/,
10
10
  process=require('process');
11
11
  let avsc,snappy,xmlParser,json2xmlParser,XLSX,compressor;
12
12
  const {ISO8583BitMapId,ISO8583BitMapName}=require("./ISO8583BitMap");
13
+ const { callbackify } = require("util");
13
14
  let ISO8583,ISO8583message;
14
15
  const XMLoptions = {
15
16
  // attributeNamePrefix : "@_",
@@ -31,63 +32,31 @@ const XMLoptions = {
31
32
  };
32
33
  const makeDateType=data=>(data instanceof Date? data:new Date(data))
33
34
  const error=(node,ex,shortMessage)=>{
35
+ if(!ex) ex =Error("no exception/error")
34
36
  if(logger.active) logger.send({label:"transformNode catch",shortMessage:shortMessage,error:ex.message,stack:ex.stack});
35
37
  node.error(ex.message);
36
- node.status({fill:"red",shape:"ring",text:(shortMessage||ex.message).substr(0,50)});
38
+ node.status({fill:"red",shape:"ring",text:(shortMessage??ex.message??"unknown error").substr(0,50)});
37
39
  }
38
40
  const getAvroTransformer=(node,schema)=>{
39
41
  try{
40
- return avsc.Type.forSchema(node.schemas[schema]);
42
+ return avsc.Type.forSchema(node.schemas[schema])
41
43
  } catch(ex){
42
- if(node.schemas.hasOwnProperty(schema)) throw ex;
43
- throw Error("schema not found for "+schema);
44
+ if(node.schemas.hasOwnProperty(schema)) throw ex
45
+ throw Error("schema not found for "+schema)
44
46
  }
45
47
  }
48
+ const xlsx2=require("./xlsx2")
46
49
 
47
- const addWorksheet2JSON=(object,worksheet,workbook,options)=>{
48
- object[worksheet]=XLSX.utils.sheet_to_json(workbook.Sheets[worksheet],options);
49
- if(options.header) object[worksheet].shift();
50
- if(logger.active) logger.send({label:"addWorksheet2JSON",object:object,worksheet:worksheet})
51
- return object;
50
+ const ConfluenceToJSON=(RED,node,msg,data,callback)=>{
51
+ if(!Buffer.isBuffer(data)) data=Buffer.from(data)
52
+ const magicByte=data.readUInt8()
53
+ if(magicByte!==0) throw Error("expected magic byte and not found, found "+magicByte)
54
+ if(data.length<5) throw Error("missing schema, data length "+data.length)
55
+ const schema=data.readInt32BE(1)
56
+ const avroTransformer=getAvroTransformer(node,schema)
57
+ callback(RED,node,msg,data,{schema:schema,data:avroTransformer.fromBuffer(data.subarray(5))})
52
58
  }
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)=>{
60
- const workbook = XLSX.utils.book_new();
61
- for(const worksheet in data) {
62
- const ws=XLSX.utils.json_to_sheet(data[worksheet]);
63
- XLSX.utils.book_append_sheet(workbook, ws, worksheet);
64
- }
65
- return workbook;
66
- }
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)=>{
69
- const workbook = XLSX.utils.book_new();
70
- if(Array.isArray(data)) {
71
- const ws=XLSX.utils.aoa_to_sheet(data);
72
- XLSX.utils.book_append_sheet(workbook, ws,"worksheet 1");
73
- return workbook;
74
- }
75
- for(const worksheet in data) {
76
- const ws=XLSX.utils.aoa_to_sheet(data[worksheet]);
77
- XLSX.utils.book_append_sheet(workbook, ws, worksheet);
78
- }
79
- return workbook;
80
- }
81
- const ConfluenceToJSON=(RED,node,msg,data)=>{
82
- if(!Buffer.isBuffer(data)) data=Buffer.from(data);
83
- const magicByte=data.readUInt8();
84
- if(magicByte!==0) throw Error("expected magic byte and not found, found "+magicByte);
85
- if(data.length<5) throw Error("missing schema, data length "+data.length);
86
- const schema=data.readInt32BE(1);
87
- const avroTransformer=getAvroTransformer(node,schema);
88
- return {schema:schema,data:avroTransformer.fromBuffer(data.subarray(5))};
89
- }
90
- const JSONToConfluence=(RED,node,msg,data)=>{
59
+ const JSONToConfluence=(RED,node,msg,data,callback)=>{
91
60
  if(!data.schema) throw Error("property schema not defined");
92
61
  if(!data.data) throw Error("property data not defined");
93
62
  const header=Buffer.alloc(5);
@@ -95,7 +64,7 @@ const JSONToConfluence=(RED,node,msg,data)=>{
95
64
  header.writeInt32BE(data.schema, 1);
96
65
  const transformer=getAvroTransformer(node,data.schema);
97
66
  const avro=transformer.toBuffer(data.data);
98
- return Buffer.concat([header,avro]);
67
+ callback(RED,node,msg,data,Buffer.concat([header,avro]))
99
68
  }
100
69
  function SendArray(RED,node,msg,array){
101
70
  if(logger.active) logger.send({label:"SendArray",size:array.length});
@@ -183,11 +152,36 @@ const Array2csv=(node,data)=>{
183
152
  })
184
153
  return properties.join(node.delimiter)+"\n"+rows.join("\n");
185
154
  }
186
- return data .map(r=>JSON.stringify(r)).join("/n");
155
+ return data.map(r=>JSON.stringify(r)).join("/n");
156
+ }
157
+ const JSON2Array=data=>{
158
+ if(data instanceof Object){
159
+ let a=[];
160
+ properties=Object.keys(data)
161
+ for(const p of properties) {
162
+ a.push([p,JSON2Array(data[p])]);
163
+ }
164
+ return a;
165
+ }
166
+ return [data]
167
+ }
168
+ const JSON2HTML=(data,level=0)=>{
169
+ if(Array.isArray(data)) {
170
+ return data.length?"<table><tr>"+data.map((r)=>JSON2HTML(r,++level)).join("</tr><tr>")+"</tr><table>":"";
171
+ }
172
+ if(data instanceof Object){
173
+ let a=[];
174
+ for(let p in data) {
175
+ a.push("<td style='vertical-align: top;'>"+escape(p)+":</td><td>"+functions.JSONToHTML(data[p],++level)+"</td>");
176
+ }
177
+ return "<table><tr>"+a.join("</tr><tr>")+"</tr><table>";
178
+ }
179
+ return escape(data);
187
180
  }
181
+
188
182
  const functions={
189
- ArrayToCSV: (RED,node,msg,data)=>data.map(c=>JSON.stringify(c)).join("\n"),
190
- ArrayToHTML: (RED,node,msg,data)=>
183
+ ArrayToCSV: (RED,node,msg,data,callback)=>callback(RED,node,msg,data.map(c=>JSON.stringify(c)).join("\n")),
184
+ ArrayToHTML: (RED,node,msg,data,callback)=>callback(RED,node,msg,
191
185
  "<table>"+ array2tag(data,"tr",(c)=>(
192
186
  Array.isArray(c)?
193
187
  array2tag(c,"td",(cc)=>
@@ -197,9 +191,9 @@ const functions={
197
191
  ):
198
192
  "<![CDATA["+c+"]]>"
199
193
  )
200
- )+"</table>",
201
- ArrayToISO8385: (RED,node,msg,data)=>ISO8583message.packSync(data),
202
- ArrayToMessages: (RED,node,msg,data)=>{
194
+ )+"</table>"),
195
+ ArrayToISO8385: (RED,node,msg,data,callback)=>callback(RED,node,msg,ISO8583message.packSync(data)),
196
+ ArrayToMessages: (RED,node,msg,data,callback)=>{
203
197
  if(logger.active) logger.send({label:"ArrayToMessages",arraySize:data.length});
204
198
  if(data.length>node.maxMessages) throw Error("messages to be created "+data.length +"> max: "+node.maxMessages);
205
199
  const newMsgs=[]
@@ -212,84 +206,67 @@ const functions={
212
206
  });
213
207
  node.send([newMsgs])
214
208
  },
215
- ArrayToXLSX:ArrayToXLSX,
216
- ArrayToXLSXObject:ArrayToXLSXObject,
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,
219
- BufferToCompressed: (RED,node,msg,data)=>compressor.compress(data,
220
- (compressed)=>{
221
- node.setData(RED,node,msg,compressed);
222
- node.send(msg);
223
- },
224
- (err)=>{
225
- error(node,Error(err));
226
- }
209
+ ArrayToXLSX:(RED,node,msg,data,callback)=>callback(RED,node,msg,xlsx2.Array2XLSX(data)),
210
+ ArrayToXLSXObject:(RED,node,msg,data,callback)=>callback(RED,node,msg,xlsx2.Array2XLSXObject(data)),
211
+ AVROToJSON: (RED,node,msg,data,callback)=>callback(RED,node,msg,node.avroTransformer.fromBuffer(data)), // = {kind: 'CAT', name: 'Albert'}
212
+ BigIntToRangeLimit: (RED,node,msg,data,callback)=> callback(RED,node,msg,data?data.rangeLimit(node.minBigIntTyped,node.maxBigIntTyped):node.minBigInt),
213
+ BufferToCompressed: (RED,node,msg,data,callback)=>compressor.compress(data,
214
+ compressed=>node.setData(RED,node,msg,compressed,callback),
215
+ err=>error(node,Error(err))
227
216
  ),
228
- CompressedToBuffer:(RED,node,msg,data)=>compressor.decompress(data,
229
- (uncompressed)=>{
230
- node.setData(RED,node,msg,uncompressed);
231
- node.send(msg);
232
- },
233
- (err)=>{
234
- error(node,Error(err));
235
- }
217
+ CompressedToBuffer:(RED,node,msg,data,callback)=>compressor.decompress(data,
218
+ uncompressed=>node.setData(RED,node,msg,uncompressed,callback),
219
+ err=>error(node,Error(err))
236
220
  ),
237
- CompressedToJSON:(RED,node,msg,data)=>compressor.decompress(data,
238
- (uncompressed)=>{
221
+ CompressedToJSON:(RED,node,msg,data,callback)=>compressor.decompress(data,
222
+ uncompressed=>{
239
223
  try{
240
- node.setData(RED,node,msg,JSON.parse(uncompressed));
241
- node.send(msg);
224
+ node.setData(RED,node,msg,JSON.parse(uncompresse,callback));
242
225
  } catch(ex){
243
226
  msg.error=ex.message
244
- node.setData(RED,node,msg,uncompressed);
227
+ node.setData(RED,node,msg,uncompressed,callback);
245
228
  }
246
229
  },
247
- (err)=>{
248
- error(node,Error(err));
249
- }
230
+ err=>error(node,Error(err))
250
231
  ),
251
- CompressedToString:(RED,node,msg,data)=>compressor.decompress(data,
252
- (uncompressed)=>{
232
+ CompressedToString:(RED,node,msg,data,callback)=>compressor.decompress(data,
233
+ uncompressed=>{
253
234
  try{
254
- node.setData(RED,node,msg,uncompressed.toString());
255
- node.send(msg);
235
+ node.setData(RED,node,msg,uncompressed.toString(),callback)
256
236
  } catch(ex){
257
237
  msg.error=ex.message;
258
- node.setData(RED,node,msg,uncompressed);
238
+ node.setData(RED,node,msg,uncompressed,callback)
259
239
  }
260
240
  },
261
- (err)=>{
262
- error(node,Error(err));
263
- }
241
+ err=>error(node,Error(err))
264
242
  ),
265
243
  ConfluenceToJSON: ConfluenceToJSON,
266
- CSVToArray: (RED,node,msg,data)=>{
244
+ CSVToArray: (RED,node,msg,data,callback)=>{
267
245
  let lines=csvLines(data,node.skipLeading,node.skipTrailing);
268
246
  lines.forEach((value, idx) => {
269
247
  lines[idx]=value.split(regexCSV).map((c)=>removeQuotes(c));
270
248
  });
271
- return lines;
249
+ callback(RED,node,msg,lines)
272
250
  },
273
- CSVToHTML: (RED,node,msg,data)=>
251
+ CSVToHTML: (RED,node,msg,data,callback)=>callback(RED,node,msg,
274
252
  "<table>"+ array2tag(csvLines(data,node.skipLeading,node.skipTrailing),"tr",(line)=>
275
253
  array2tag(line.split(regexCSV),"td",(c)=>"<![CDATA["+removeQuotes(c)+"]]>")
276
- )+"</table>",
277
- CSVToMessages: (RED,node,msg,data)=>{
278
- functions.ArrayToMessages(RED,node,msg,csvLines(data,this.skipLeading,this.skipTrailing));
279
- },
280
- CSVWithHeaderToArray: (RED,node,msg,data)=>{
254
+ )+"</table>"),
255
+ CSVToMessages: (RED,node,msg,data,callback)=>functions.ArrayToMessages(RED,node,msg,csvLines(data,this.skipLeading,this.skipTrailing),callback),
256
+ CSVWithHeaderToArray: (RED,node,msg,data,callback)=>{
281
257
  let r=functions.CSVToArray(RED,node,msg,data);
282
258
  r.shift();
283
- return r;
259
+ rcallback(RED,node,msg,r)
284
260
  },
285
- CSVWithHeaderToHTML: (RED,node,msg,data)=>{
261
+ CSVWithHeaderToHTML: (RED,node,msg,data,callback)=>{
286
262
  let lines=csvLines(data,node.skipLeading,node.skipTrailing);
287
263
  const header=array2tag(lines.shift().split(regexCSV),"th",(c)=>"<![CDATA["+removeQuotes(c)+"]]>");
288
- return "<table><tr>"+header+"</tr>"+array2tag(lines,"tr",(line)=>
289
- array2tag(line.split(regexCSV),'td',(c)=>"<![CDATA["+removeQuotes(c)+"]]>")
290
- )+"</table>"
264
+ const result= "<table><tr>"+header+"</tr>"+array2tag(lines,"tr",(line)=>
265
+ array2tag(line.split(regexCSV),'td',(c)=>"<![CDATA["+removeQuotes(c)+"]]>")
266
+ )+"</table>"
267
+ callback(RED,node,msg,result)
291
268
  },
292
- CSVWithHeaderToJSON: (RED,node,msg,data)=>{
269
+ CSVWithHeaderToJSON: (RED,node,msg,data,callback)=>{
293
270
  let lines=csvLines(data,node.skipLeading,node.skipTrailing);
294
271
  let header=lines.shift().split(regexCSV);
295
272
  if(logger.active) logger.send({label:"CSVWithHeaderToJSON",header:header});
@@ -300,163 +277,129 @@ const functions={
300
277
  });
301
278
  lines[idx]=o;
302
279
  });
303
- return lines;
280
+ callback(RED,node,msg,lines)
304
281
  },
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),
309
- ISO8385ToArray: (RED,node,msg,data)=>ISO8583message.unpackSync(data, data.length),
310
- ISO8385ToJSON: (RED,node,msg,data)=>{
282
+ DateToisBetween: (RED,node,msg,data,callback)=> callback(RED,node,msg,toDateTypeZulu(data).isBetween(node.minDateTyped,node.maxDateTyped)),
283
+ DateToISODate: (RED,node,msg,data,callback)=> callback(RED,node,msg,toDateTypeZulu(data).toISOString().slice(0,10)),
284
+ DateToLocalDate: (RED,node,msg,data,callback)=> callback(RED,node,msg,toDateTypeZulu(data).toLocaleDateString().slice(0,10)),
285
+ DateToRangeLimit: (RED,node,msg,data,callback)=> callback(RED,node,msg,(data? toDateTypeZulu(data).rangeLimit(node.minDateTyped,node.maxDateTyped):node.minDateTyped)),
286
+ ISO8385ToArray: (RED,node,msg,data,callback)=>callback(RED,node,msg,ISO8583message.unpackSync(data, data.length)),
287
+ ISO8385ToJSON: (RED,node,msg,data,callback)=>{
311
288
  let j={},d=ISO8583message.unpackSync(data, data.length);
312
289
  d.forEach((r)=>{
313
290
  j[ISO8583BitMapId(r[0]).name]=r[1];
314
291
  });
315
- return r;
292
+ callback(RED,node,msg,r)
316
293
  },
317
- JSONToArray: (RED,node,msg,data)=>{
318
- if(data instanceof Object){
319
- let a=[];
320
- properties=Object.keys(data)
321
- for(const p of properties) {
322
- a.push([p,functions.JSONToArray(RED,node,msg,data[p])]);
323
- }
324
- return a;
325
- }
326
- return data;
327
- },
328
- JSONToAVRO: (RED,node,msg,data)=>node.avroTransformer.toBuffer(data), // Encoded buffer.
329
- JSONToCompressed: (RED,node,msg,data)=>compressor.compress(JSON.stringify(data),
330
- (compressed)=>{
331
- node.setData(RED,node,msg,compressed);
332
- node.send(msg);
333
- },
334
- (err)=>{
335
- error(node,Error(err));
336
- }
294
+ JSONToArray: (RED,node,msg,data,callback)=>callback(RED,node,msg,JSON2Array(data)),
295
+ JSONToAVRO: (RED,node,msg,data,callback)=>callback(RED,node,msg,node.avroTransformer.toBuffer(data)), // Encoded buffer.
296
+ JSONToCompressed: (RED,node,msg,data,callback)=>compressor.compress(JSON.stringify(data),
297
+ compressed=>node.setData(RED,node,msg,compressed.callback),
298
+ err=>error(node,Error(err))
337
299
  ),
338
300
  JSONToConfluence:JSONToConfluence,
339
- JSONToCSV: (RED,node,msg,data)=>Array2csv(node,data),
340
- JSONToHTML: (RED,node,msg,data,level=0)=>{
341
- if(Array.isArray(data)) {
342
- return data.length?"<table><tr>"+data.map((r)=>functions.JSONToHTML(RED,node,msg,r,++level)).join("</tr><tr>")+"</tr><table>":"";
343
- }
344
- if(data instanceof Object){
345
- let a=[];
346
- for(let p in data) {
347
- a.push("<td style='vertical-align: top;'>"+escape(p)+":</td><td>"+functions.JSONToHTML(RED,node,msg,data[p],++level)+"</td>");
348
- }
349
- return "<table><tr>"+a.join("</tr><tr>")+"</tr><table>";
350
- }
351
- return escape(data);
352
- },
353
- JSONToISO8385: (RED,node,msg,data)=>{
301
+ JSONToCSV: (RED,node,msg,data,callback)=>callback(RED,node,msg,Array2csv(node,data)),
302
+ JSONToHTML: (RED,node,msg,data,callback)=>callback(RED,node,msg,JSON2HTML(data)),
303
+ JSONToISO8385: (RED,node,msg,data,callback)=>{
354
304
  var d=[];
355
305
  Object.getOwnPropertyNames(data).forEach((v)=>d.push([ISO8583BitMapName[v].id,data[v]]));
356
306
  d.sort((a, b) => a[0] - b[0]);
357
- return ISO8583message.packSync(d);
307
+ callback(RED,node,msg, ISO8583message.packSync(d))
358
308
  },
359
- JSONToMessages: (RED,node,msg,data)=>{
309
+ JSONToJSON: (RED,node,msg,data,callback)=>callback(RED,node,msg,data),
310
+ JSONToMessages: (RED,node,msg,data,callback)=>{
360
311
  if(logger.active) logger.send({label:"JSONToMessages",messages:data.length});
361
312
  if(Array.isArray(data)) {
362
313
  new node.SendArray(RED,node,msg,data);
363
314
  } else {
364
315
  const newMsg=RED.util.cloneMessage(msg);
365
316
  newMsg._msgid=newMsg._msgid+":0";
366
- node.setData(RED,node,newMsg,data,0)
367
- node.send(newMsg);
317
+ node.setData(RED,node,newMsg,data,callback)
368
318
  }
369
319
  },
370
- JSONTonpy: (RED,node,msg,data)=>new NumPy(data).toNpyBuffer(),
371
- JSONToNumPyObject: (RED,node,msg,data)=>new NumPy(data),
372
- JSONToString: (RED,node,msg,data)=>JSON.stringify(data),
373
- JSONToXLSX:JSONToXLSX,
374
- JSONToXLSXObject:JSONToXLSXObject,
375
- JSONToXML: (RED,node,msg,data)=>json2xmlParser.parse(data),
376
- npyToJSON: (RED,node,msg,data)=>new NumPy(data).toSerializable(),
377
- npyToNumPyObject: (RED,node,msg,data)=>new NumPy(data),
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
320
+ JSONTonpy: (RED,node,msg,data,callback)=>callback(RED,node,msg,new NumPy(data).toNpyBuffer()),
321
+ JSONToNumPyObject: (RED,node,msg,data,callback)=>callback(RED,node,msg,new NumPy(data)),
322
+ JSONToString: (RED,node,msg,data,callback)=>callback(RED,node,msg,JSON.stringify(data)),
323
+ JSONToXLSX:(RED,node,msg,data,callback)=>callback(RED,node,msg,xlsx2.JSON2XLSX(data)),
324
+ JSONToXLSXObject:(RED,node,msg,data,callback)=>callback(RED,node,msg,xlsx2.JSON2XLSXObject(data)),
325
+ JSONToXML: (RED,node,msg,data,callback)=>callback(RED,node,msg,json2xmlParser.parse(data)),
326
+ npyToJSON: (RED,node,msg,data,callback)=>callback(RED,node,msg,new NumPy(data).toSerializable()),
327
+ npyToNumPyObject: (RED,node,msg,data,callback)=>callback(RED,node,msg,new NumPy(data)),
328
+ NumPyObjectToJSON: (RED,node,msg,data,callback)=> callback(RED,node,msg,data.toSerializable()),
329
+ NumberToAbbreviated: (RED,node,msg,data,callback)=> callback(RED,node,msg,data?data.isAbbreviated():data),
330
+ NumberToisBetween: (RED,node,msg,data,callback)=> callback(RED,node,msg,data.isBetween(node.minNumber,node.maxNumber)),
331
+ NumberToRangeLimit: (RED,node,msg,data)=> callback(RED,node,msg,data?data.rangeLimit(node.minNumber,node.maxNumber):node.minNumber),
332
+ ObjectToCoalesce: (RED,node,msg,data,callback)=>callback(RED,node,msg,coalesce(data,node.value)),
333
+ ObjectToDeepClone: (RED,node,msg,data,callback)=>callback(RED,node,msg,data.deepClone()),
334
+ ObjectToNullif: (RED,node,msg,data,callback)=>callback(RED,node,msg,nullif(data,node.value)),
335
+ StringToAppend: (RED,node,msg,data,callback)=>callback(RED,node,msg,data.concat(node.getString(msg))),
336
+ StringToArrayByDelimiter: (RED,node,msg,data,callback)=>callback(RED,node,msg,data
387
337
  .split(node.delimiter??',')
388
338
  .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),
396
- StringToCompressed: (RED,node,msg,data)=>compressor.compress(data,
397
- (compressed)=>{
398
- node.setData(RED,node,msg,compressed);
399
- node.send(msg);
400
- },
401
- (err)=>{
402
- error(node,Error(err));
403
- }
339
+ .filter(entry => entry)),
340
+ StringToAt: (RED,node,msg,data,callback)=>callback(RED,node,msg,data.At(node.index)),
341
+ StringToCapitalize: (RED,node,msg,data,callback)=> callback(RED,node,msg,data.capitalize()),
342
+ StringToCamelize: (RED,node,msg,data,callback)=>callback(RED,node,msg,data.toLowerCase().replace(/[^a-zA-Z0-9]+(.)/g, (m, chr) => chr.toUpperCase())),
343
+ StringToCharAt: (RED,node,msg,data,callback)=>callback(RED,node,msg,data.charAt(node.index)),
344
+ StringToCharCodeAt: (RED,node,msg,data,callback)=>callback(RED,node,msg,data.charCodeAt(node.index)),
345
+ StringToCodePointAt: (RED,node,msg,data,callback)=>callback(RED,node,msg,data.codePointAt(node.index)),
346
+ StringToCompressed: (RED,node,msg,data,callback)=>compressor.compress(data,
347
+ compressed=>node.setData(RED,node,msg,compressed,callback),
348
+ err=>error(node,Error(err))
404
349
  ),
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(),
438
- pathToBasename: (RED,node,msg,data)=>path.basename(data),
439
- pathToDirname: (RED,node,msg,data)=>path.dirname(data),
440
- pathToExtname: (RED,node,msg,data)=>path.extname(data),
441
- pathToFormat: (RED,node,msg,data)=>path.format(data),
442
- pathToIsAbsolute: (RED,node,msg,data)=>path.isAbsolute(data),
443
- pathToJoin: (RED,node,msg,...data)=>path.join(...data),
444
- pathToParse: (RED,node,msg,data)=>path.parse(data),
445
- pathToNormalize: (RED,node,msg,data)=>path.normalize(data),
446
- pathToResolve: (RED,node,msg,data)=>path.resolve(data),
447
- snappyToCompress: (RED,node,msg,data)=>{
350
+ StringToConcat: (RED,node,msg,data,callback)=>callback(RED,node,msg,data.concat(node.getString(msg))),
351
+ StringToDate: (RED,node,msg,data,callback)=>callback(RED,node,msg,toDateTypeZulu(data)),
352
+ StringToDateLocal: (RED,node,msg,data,callback)=>callback(RED,node,msg,new Date(data)),
353
+ StringToTimestamp: (RED,node,msg,data,callback)=>callback(RED,node,msg,Date.parse(data)),
354
+ StringToDelimiterOnCase:(RED,node,msg,data,callback)=>callback(RED,node,msg,
355
+ data.replace(/[A-Z]/g, (letter, index) => {
356
+ const lcLet = letter.toLowerCase();
357
+ const separator= node.delimiter??"-"
358
+ return index ? separator + lcLet : lcLet;
359
+ })
360
+ .replace(/([-_ ]){1,}/g,node.delimiter??"-")
361
+ ),
362
+ StringToDeunderscore: (RED,node,msg,data,callback)=> callback(RED,node,msg,data.deunderscore()),
363
+ StringToDeunderscoreCapitilize: (RED,node,msg,data,callback)=> callback(RED,node,msg,data.deunderscoreCapitilize()),
364
+ StringToDropSquareBracketPrefix: (RED,node,msg,data,callback)=> callback(RED,node,msg,data.dropSquareBracketPrefix()),
365
+ StringToEndsWith: (RED,node,msg,data,callback)=> callback(RED,node,msg,data.endsWith(node.getString(msg))),
366
+ StringToFloat: (RED,node,msg,data,callback)=>callback(RED,node,msg,parseFloat(data)),
367
+ StringToGetWord: (RED,node,msg,data,callback)=> callback(RED,node,msg,data.getWord(node.index)),
368
+ StringToInteger: (RED,node,msg,data,callback)=>callback(RED,node,msg,parseInt(data, node.radix??10)),
369
+ StringToisBetween: (RED,node,msg,data,callback)=> callback(RED,node,msg,data.isBetween(node.minString,node.maxString)),
370
+ StringToJSON: (RED,node,msg,data,callback)=>callback(RED,node,msg,JSON.parse(data)),
371
+ StringToLowerCase: (RED,node,msg,data,callback)=> callback(RED,node,msg,data.toLowerCase()),
372
+ StringToNumber: (RED,node,msg,data,callback)=>callback(RED,node,msg,Number(data)),
373
+ StringToPrepend: (RED,node,msg,data,callback)=>callback(RED,node,msg,node.getString(msg).concat(data)),
374
+ StringToRangeLimit: (RED,node,msg,data,callback)=> callback(RED,node,msg,data?data.rangeLimit(node.minString,node.maxString):node.minString),
375
+ StringToReal: (RED,node,msg,data,callback)=> callback(RED,node,msg,data.toReal()),
376
+ StringToSplit: (RED,node,msg,data,callback)=>callback(RED,node,msg,data.split(node.getString(msg))),
377
+ StringToStartsWith: (RED,node,msg,data,callback)=> callback(RED,node,msg,data.startsWith(node.getString(msg))),
378
+ StringToTitle: (RED,node,msg,data,callback)=>callback(RED,node,msg,data.toTitle()),
379
+ StringTotTitleGrammatical: (RED,node,msg,data,callback)=>callback(RED,node,msg,data.toTitleGrammatical()),
380
+ StringToTrim: (RED,node,msg,data,callback)=>callback(RED,node,msg,data.trim()),
381
+ StringToTrimEnd: (RED,node,msg,data,callback)=>callback(RED,node,msg,data.trimEnd()),
382
+ StringToTrimStart: (RED,node,msg,data,callback)=>callback(RED,node,msg,data.trimStart()),
383
+ StringToUpperCase: (RED,node,msg,data,callback)=> callback(RED,node,msg,data.toUpperCase()),
384
+ StringToXmlStringEncode: (RED,node,msg,data,callback)=> callback(RED,node,msg,data.xmlStringEncode()),
385
+ pathToBasename: (RED,node,msg,data,callback)=>callback(RED,node,msg,path.basename(data)),
386
+ pathToDirname: (RED,node,msg,data,callback)=>callback(RED,node,msg,path.dirname(data)),
387
+ pathToExtname: (RED,node,msg,data,callback)=>callback(RED,node,msg,path.extname(data)),
388
+ pathToFormat: (RED,node,msg,data,callback)=>callback(RED,node,msg,path.format(data)),
389
+ pathToIsAbsolute: (RED,node,msg,data,callback)=>callback(RED,node,msg,path.isAbsolute(data)),
390
+ pathToJoin: (RED,node,msg,data)=>callback(RED,node,msg,path.join(data)),
391
+ pathToParse: (RED,node,msg,data,callback)=>callback(RED,node,msg,path.parse(data)),
392
+ pathToNormalize: (RED,node,msg,data,callback)=>callback(RED,node,msg,path.normalize(data)),
393
+ pathToResolve: (RED,node,msg,data,callback)=>callback(RED,node,msg,path.resolve(data)),
394
+ snappyToCompress: (RED,node,msg,data,callback)=>{
448
395
  if(logger.active) logger.send({label:"snappyToCompress"});
449
396
  snappy.compress(data, (err, data)=>{
450
397
  if(logger.active) logger.send({label:"snappy.compress",error:err})
451
- if(err) {
452
- error(node,Error(err));
453
- return;
454
- }
455
- node.setData(RED,node,msg,data)
456
- node.send(msg);
398
+ if(err) return error(node,Error(err))
399
+ node.setData(RED,node,msg,data,callback)
457
400
  })
458
401
  },
459
- snappyToUncompress: (RED,node,msg,data)=>{
402
+ snappyToUncompress: (RED,node,msg,data,callback)=>{
460
403
  if(logger.active) logger.send({label:"snappyToUncompress"});
461
404
  snappy.uncompress(data, { asBuffer: false }, (err, data)=>{
462
405
  if(logger.active) logger.send({label:"snappy.uncompress",error:err});
@@ -464,16 +407,15 @@ const functions={
464
407
  error(node,Error(err));
465
408
  return;
466
409
  }
467
- node.setData(RED,node,msg,data)
468
- node.send(msg);
410
+ node.setData(RED,node,msg,data,callback)
469
411
  })
470
412
  },
471
- XLSXToArray:XLSXToArray,
472
- XLSXObjectToArray:XLSXObjectToArray,
473
- XLSXToJSON:XLSXToJSON,
474
- XLSXObjectToJSON:XLSXObjectToJSON,
475
- XLSXToXLSXObject:XLSXToXLSXObject,
476
- XMLToJSON: (RED,node,msg,data)=>xmlParser.parse(data,XMLoptions,true),
413
+ XLSXToArray:(RED,node,msg,data,callback)=>callback(RED,node,msg,xlsx2.XLSX2Array(data)),
414
+ XLSXObjectToArray:(RED,node,msg,data,callback)=>callback(RED,node,msg,xlsx2.XLSXObject2Array(data)),
415
+ XLSXToJSON:(RED,node,msg,data,callback)=>callback(RED,node,msg,xlsx2.XLSX2JSON(data)),
416
+ XLSXObjectToJSON:(RED,node,msg,data,callback)=>callback(RED,node,msg,xlsx2.XLSXObject2JSON(data)),
417
+ XLSXToXLSXObject:(RED,node,msg,data,callback)=>callback(RED,node,msg,xlsx2.XLSX2XLSXObject(data)),
418
+ XMLToJSON: (RED,node,msg,data,callback)=>callback(RED,node,msg,xmlParser.parse(data,XMLoptions,true)),
477
419
  invalidArray:(v=>!Array.isArray(v))
478
420
  };
479
421
 
@@ -488,22 +430,6 @@ const is=(node,value)=>{
488
430
  return node.actionSource==value||node.actionTarget==value;
489
431
  }
490
432
  let jsonata;
491
- function JSONataTransform(data,ok,error){
492
- /*
493
- (async () => {
494
- return result = await expression.evaluate(data);
495
- })()
496
- */
497
-
498
- this.transformFunctionCompiled.evalFunction(data,{},(error, result) => {
499
- if(error) {
500
- console.error(error);
501
- return;
502
- }
503
- console.log("Finished with", result);
504
- });
505
- }
506
-
507
433
  module.exports = function (RED) {
508
434
  function transformNode(n) {
509
435
  RED.nodes.createNode(this,n);
@@ -533,28 +459,32 @@ module.exports = function (RED) {
533
459
  if(['Append','Concat','EndsWith','Prepend','Split','StartsWith'].includes(node.actionTarget)) {
534
460
  typedInput.setGetFunction(RED,node,"string")
535
461
  }
536
- node.sendInFunction=["snappy","Compressed"].includes(node.actionSource)||["Messages","Compressed"].includes(node.actionTarget);
537
- node.hasNewTopic=![null,""].includes(node.topicProperty);
538
462
  const source=(node.sourceProperty||"msg.payload")
539
463
  const target=(node.targetProperty||"msg.payload")
540
464
  const sourceMap="(RED,node,msg)=>"+source,
541
465
  deleteSource=typedInput.getValue(RED,node,"deleteSource",true)
542
- targetMap="(RED,node,msg,data,index)=>{"+target+"=data;"+
543
- (node.sendInFunction && node.hasNewTopic? "msg.topic=node.topicFunction(RED,node,msg,data,index);":"")+
466
+ targetMap="(RED,node,msg,data,callback)=>{"+target+"=data;"+
467
+ (node.topicProperty? "msg.topic=node.topicFunction(RED,node,msg,data);":"")+
544
468
  (deleteSource&&source!==target?"delete "+source+";"+"delete "+source+";":"")+
545
- (node.sendInFunction ? "" : "node.send(msg);" )+
546
469
  "}",
547
470
  topicMap="(RED,node,msg,data,index)=>"+(node.topicProperty||"msg.topic");
548
471
  logger.sendInfo({label:"mappings",source:sourceMap,deleteSource:deleteSource,target:targetMap,topicMap:topicMap});
549
- node.getData=evalFunction("source",sourceMap);
550
- node.setData=evalFunction("target",targetMap);
472
+ const getData=evalFunction("source",sourceMap);
473
+ node.getData=(RED,node,msg,callback)=>callback(RED,node,msg,getData(RED,node,msg))
474
+ const setData1=evalFunction("target",targetMap);
475
+ node.setData=(RED,node,msg,data,callback)=>{
476
+ setData1(RED,node,msg,data)
477
+ callback(RED,node,msg,data)
478
+ }
551
479
  node.topicFunction=evalFunction("topic",topicMap);
552
480
  if(is(node,"AVRO")) {
553
481
  node.avroTransformer=avsc.Type.forSchema(node.schemaValid);
554
482
  } else if(is(node,"Compressed")) {
555
- const CompressionTool = require('compressiontool')
556
- compressor=new CompressionTool();
557
- compressor[node.compressionType]();
483
+ if(compressor==null) {
484
+ const CompressionTool = require('compressiontool')
485
+ compressor=new CompressionTool();
486
+ compressor[node.compressionType]();
487
+ }
558
488
  } else if(is(node,"Confluence")) {
559
489
  node.schemas={};
560
490
  for(const schema in node.schemaValid )
@@ -564,11 +494,6 @@ module.exports = function (RED) {
564
494
  if(node.maxDate) node.maxDateTyped=toDateTypeZulu(node.maxDate)
565
495
  if(node.minDate) node.minDateTyped=toDateTypeZulu(node.minDate)
566
496
  }
567
- if(node.actionTarget=="Compressed"){
568
- const CompressionTool = require('compressiontool')
569
- compressor=new CompressionTool();
570
- compressor[node.compressionType]();
571
- }
572
497
  } catch(ex) {
573
498
  logger.error(n);
574
499
  error(node,ex,"Invalid setup "+ex.message);
@@ -586,16 +511,42 @@ module.exports = function (RED) {
586
511
  }
587
512
  }
588
513
  }
589
- if(node.transformFunction && is(node,"JSON")) {
514
+ if(node.actionSource=="JSON" && node.JSONataSource){
590
515
  try{
591
516
  if(!jsonata) jsonata=require('jsonata')
592
- node.transformFunctionCompiled = jsonata(node.transformFunction);
517
+ node.JSONataSourceExpression = jsonata(node.JSONataSource)
518
+ node.getData1=node.getData
519
+ node.getData=(RED,node,msg,callback)=>
520
+ node.getData1(RED,node,msg,(RED,node,msg,data)=>
521
+ node.JSONataSourceExpression.evaluate(data,
522
+ {msg:msg,RED:RED,node:node},
523
+ (err,response)=>err?error(node,Error(err),err):callback(RED,node,msg,response))
524
+ )
593
525
  } catch (ex) {
594
- error(node,ex,"Transform function error");
595
- return;
526
+ console.log("JSONata source:",node.JSONataSource)
527
+ error(node,ex,"JSONata source function error")
528
+ return
529
+ }
530
+ }
531
+ if(node.actionTarget=="JSON"&& node.JSONataTarget){
532
+ try{
533
+ if(!jsonata) jsonata=require('jsonata')
534
+ node.JSONataTargetExpression = jsonata(node.JSONataTarget)
535
+ node.setData1=node.setData
536
+ node.setData=(RED,node,msg,data,callback)=>{
537
+ node.JSONataTargetExpression.evaluate(data,{msg:msg,RED:RED,node:node},
538
+ (err,data)=>{
539
+ if(err) error(node,ex,"JSONata target evaluate error")
540
+ node.setData1(RED,node,msg,data,callback)
541
+ }
542
+ )
543
+ }
544
+ } catch (ex) {
545
+ console.log("JSONata Target:",node.JSONataTarget)
546
+ error(node,ex,"JSONata target function error")
547
+ return
596
548
  }
597
549
  }
598
-
599
550
  const typeValidate="invalid"+node.actionSource;
600
551
  node.invalidSourceType=typeValidate in functions &! ["XLSX","XLSXObject"].includes(node.actionTarget)?functions[typeValidate]:(()=>false);
601
552
  try {
@@ -605,17 +556,22 @@ module.exports = function (RED) {
605
556
  error(node,ex,node.actionSource+"\nto "+node.actionTarget + " not implemented")
606
557
  return;
607
558
  }
608
- node.processMsg=node.sendInFunction?this.transform
609
- :(RED,node,msg,data)=>node.setData(RED,node,msg,node.transform(RED,node,msg,data));
559
+ // node.processMsg=node.sendInFunction?this.transform
560
+ // :(RED,node,msg,data,callback)=>node.setData(RED,node,msg,node.transform(RED,node,msg,data),callback);
610
561
  this.status({fill:"green",shape:"ring",text:"Ready"});
611
562
  node.on("input", function(msg) {
612
563
  if(logger.active) logger.send({label:"input",msgid:msg._msgid,topic:msg.topic});
613
564
  try{
614
- const data=node.getData(RED,node,msg);
615
- if(node.invalidSourceType(data)) throw Error("expected source data type "+node.actionSource);
616
- node.processMsg(RED,node,msg,data);
565
+ node.getData(RED,node,msg,(RED,node,msg,data)=>{
566
+ if(node.invalidSourceType(data)) {
567
+ msg.error=node.actionSource+" to "+node.actionTarget + " expected source data type "+node.actionSource;
568
+ error(node,Error(msg.error),"Error(s)");
569
+ node.send([null,msg]);
570
+ }
571
+ node.transform(RED,node,msg,data,(RED,node,msg,dataTransformed)=>node.setData(RED,node,msg,dataTransformed,()=>node.send([msg]) ))
572
+ })
617
573
  } catch (ex) {
618
- if(logger.active) logger.sendErrorAndDump("on input error",ex)
574
+ logger.sendErrorAndDump("on input error",ex)
619
575
  msg.error=node.actionSource+" to "+node.actionTarget + " " +ex.message;
620
576
  error(node,Error(msg.error),"Error(s)");
621
577
  node.send([null,msg]);