@node-red/nodes 4.0.5 → 4.0.6

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.
@@ -111,8 +111,6 @@ module.exports = function(RED) {
111
111
  throw new Error(RED._("function.error.externalModuleNotAllowed"));
112
112
  }
113
113
 
114
-
115
-
116
114
  var functionText = "var results = null;"+
117
115
  "results = (async function(msg,__send__,__done__){ "+
118
116
  "var __msgid__ = msg._msgid;"+
@@ -166,7 +164,13 @@ module.exports = function(RED) {
166
164
  Buffer:Buffer,
167
165
  Date: Date,
168
166
  RED: {
169
- util: RED.util
167
+ util: {
168
+ ...RED.util,
169
+ getSetting: function (_node, name, _flow) {
170
+ // Ensure `node` argument is the Function node and do not allow flow to be overridden.
171
+ return RED.util.getSetting(node, name);
172
+ }
173
+ }
170
174
  },
171
175
  __node__: {
172
176
  id: node.id,
@@ -253,7 +253,13 @@ module.exports = function(RED) {
253
253
  if (node.allowrate && m.hasOwnProperty("rate") && !isNaN(parseFloat(m.rate))) {
254
254
  node.rate = m.rate;
255
255
  }
256
- send(m);
256
+ if (msg.hasOwnProperty("reset")) {
257
+ if (msg.hasOwnProperty("flush")) {
258
+ node.buffer.push({msg: m, send: send, done: done});
259
+ }
260
+ }
261
+ else { send(m); }
262
+
257
263
  node.reportDepth();
258
264
  node.intervalID = setInterval(sendMsgFromBuffer, node.rate);
259
265
  done();
@@ -285,42 +291,23 @@ module.exports = function(RED) {
285
291
  }
286
292
  }
287
293
  else if (!msg.hasOwnProperty("reset")) {
288
- if (maxKeptMsgsCount(node) > 0) {
289
- if (node.intervalID === -1) {
290
- node.send(msg);
291
- node.intervalID = setInterval(sendMsgFromBuffer, node.rate);
292
- } else {
293
- if (node.allowrate && msg.hasOwnProperty("rate") && !isNaN(parseFloat(msg.rate)) && node.rate !== msg.rate) {
294
- node.rate = msg.rate;
295
- clearInterval(node.intervalID);
296
- node.intervalID = setInterval(sendMsgFromBuffer, node.rate);
297
- }
298
- if (node.buffer.length < _maxKeptMsgsCount) {
299
- var m = RED.util.cloneMessage(msg);
300
- node.buffer.push({msg: m, send: send, done: done});
301
- } else {
302
- node.trace("dropped due to buffer overflow. msg._msgid = " + msg._msgid);
303
- node.droppedMsgs++;
304
- }
305
- }
306
- } else {
307
- if (node.allowrate && msg.hasOwnProperty("rate") && !isNaN(parseFloat(msg.rate))) {
308
- node.rate = msg.rate;
309
- }
310
- var timeSinceLast;
311
- if (node.lastSent) {
312
- timeSinceLast = process.hrtime(node.lastSent);
313
- }
314
- if (!node.lastSent) { // ensuring that we always send the first message
315
- node.lastSent = process.hrtime();
316
- send(msg);
317
- }
318
- else if ( ( (timeSinceLast[0] * SECONDS_TO_NANOS) + timeSinceLast[1] ) > (node.rate * MILLIS_TO_NANOS) ) {
319
- node.lastSent = process.hrtime();
320
- send(msg);
321
- } else if (node.outputs === 2) {
322
- send([null,msg])
323
- }
294
+ if (node.allowrate && msg.hasOwnProperty("rate") && !isNaN(parseFloat(msg.rate))) {
295
+ node.rate = msg.rate;
296
+ }
297
+ var timeSinceLast;
298
+ if (node.lastSent) {
299
+ timeSinceLast = process.hrtime(node.lastSent);
300
+ }
301
+ if (!node.lastSent) { // ensuring that we always send the first message
302
+ node.lastSent = process.hrtime();
303
+ send(msg);
304
+ }
305
+ else if ( ( (timeSinceLast[0] * SECONDS_TO_NANOS) + timeSinceLast[1] ) > (node.rate * MILLIS_TO_NANOS) ) {
306
+ node.lastSent = process.hrtime();
307
+ send(msg);
308
+ }
309
+ else if (node.outputs === 2) {
310
+ send([null,msg])
324
311
  }
325
312
  done();
326
313
  }
@@ -24,6 +24,14 @@ module.exports = function(RED) {
24
24
  this.op2 = n.op2 || "0";
25
25
  this.op1type = n.op1type || "str";
26
26
  this.op2type = n.op2type || "str";
27
+ // If the op1/2type is 'date', then we need to leave op1/2 alone so that
28
+ // evaluateNodeProperty works as expected.
29
+ if (this.op1type === 'date' && this.op1 === '1') {
30
+ this.op1 = ''
31
+ }
32
+ if (this.op2type === 'date' && this.op2 === '0') {
33
+ this.op2 = ''
34
+ }
27
35
  this.second = (n.outputs == 2) ? true : false;
28
36
  this.topic = n.topic || "topic";
29
37
 
@@ -193,7 +201,7 @@ module.exports = function(RED) {
193
201
  if (node.op2type !== "nul") {
194
202
  var promise = Promise.resolve();
195
203
  msg2 = RED.util.cloneMessage(msg);
196
- if (node.op2type === "flow" || node.op2type === "global") {
204
+ if (node.op2type === "flow" || node.op2type === "global" || node.op2type === "date") {
197
205
  promise = new Promise((resolve,reject) => {
198
206
  RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg,(err,value) => {
199
207
  if (err) {
@@ -213,7 +221,6 @@ module.exports = function(RED) {
213
221
  }
214
222
  else {
215
223
  msg2.payload = node.topics[topic].m2;
216
- if (node.op2type === "date") { msg2.payload = Date.now(); }
217
224
  if (node.second === true) { msgInfo.send([null,msg2]); }
218
225
  else { msgInfo.send(msg2); }
219
226
  }
@@ -367,20 +367,21 @@ module.exports = function(RED) {
367
367
  const sendHeadersAlways = node.hdrout === "all"
368
368
  const sendHeaders = !dontSendHeaders && (sendHeadersOnce || sendHeadersAlways)
369
369
  const quoteables = [node.sep, node.quo, "\n", "\r"]
370
- const templateQuoteables = [',', '"', "\n", "\r"]
370
+ const templateQuoteables = [node.sep, node.quo, "\n", "\r"]
371
+ const templateQuoteablesStrict = [',', '"', "\n", "\r"]
371
372
  let badTemplateWarnOnce = true
372
373
 
373
374
  const columnStringToTemplateArray = function (col, sep) {
374
375
  // NOTE: enforce strict column template parsing in RFC4180 mode
375
376
  const parsed = csv.parse(col, { separator: sep, quote: node.quo, outputStyle: 'array', strict: true })
376
- if (parsed.headers.length > 0) { node.goodtmpl = true } else { node.goodtmpl = false }
377
- return parsed.headers.length ? parsed.headers : null
377
+ if (parsed.data?.length === 1) { node.goodtmpl = true } else { node.goodtmpl = false }
378
+ return node.goodtmpl ? parsed.data[0] : null
378
379
  }
379
- const templateArrayToColumnString = function (template, keepEmptyColumns) {
380
- // NOTE: enforce strict column template parsing in RFC4180 mode
381
- const parsed = csv.parse('', {headers: template, headersOnly:true, separator: ',', quote: node.quo, outputStyle: 'array', strict: true })
380
+ const templateArrayToColumnString = function (template, keepEmptyColumns, separator = ',', quotables = templateQuoteablesStrict) {
381
+ // NOTE: defaults to strict column template parsing (commas and double quotes)
382
+ const parsed = csv.parse('', {headers: template, headersOnly:true, separator, quote: node.quo, outputStyle: 'array', strict: true })
382
383
  return keepEmptyColumns
383
- ? parsed.headers.map(e => addQuotes(e || '', { separator: ',', quoteables: templateQuoteables}))
384
+ ? parsed.headers.map(e => addQuotes(e || '', { separator, quoteables: quotables })).join(separator)
384
385
  : parsed.header // exclues empty columns
385
386
  // TODO: resolve inconsistency between CSV->JSON and JSON->CSV
386
387
  // CSV->JSON: empty columns are excluded
@@ -447,7 +448,7 @@ module.exports = function(RED) {
447
448
  template = Object.keys(inputData[0]) || ['']
448
449
  }
449
450
  }
450
- stringBuilder.push(templateArrayToColumnString(template, true))
451
+ stringBuilder.push(templateArrayToColumnString(template, true, node.sep, templateQuoteables)) // use user set separator for output data.
451
452
  if (sendHeadersOnce) { node.hdrSent = true }
452
453
  }
453
454
 
@@ -483,6 +484,7 @@ module.exports = function(RED) {
483
484
  node.warn(RED._("csv.errors.obj_csv"))
484
485
  badTemplateWarnOnce = false
485
486
  }
487
+ template = Object.keys(row) || ['']
486
488
  const rowData = []
487
489
  for (let header in inputData[0]) {
488
490
  if (row.hasOwnProperty(header)) {
@@ -518,7 +520,7 @@ module.exports = function(RED) {
518
520
 
519
521
  // join lines, don't forget to add the last new line
520
522
  msg.payload = stringBuilder.join(node.ret) + node.ret
521
- msg.columns = templateArrayToColumnString(template)
523
+ msg.columns = templateArrayToColumnString(template) // always strict commas + double quotes for
522
524
  if (msg.payload !== '') { send(msg) }
523
525
  done()
524
526
  }
@@ -615,16 +617,15 @@ module.exports = function(RED) {
615
617
  }
616
618
  if (msg.parts.index + 1 === msg.parts.count) {
617
619
  msg.payload = node.store
618
- msg.columns = csvParseResult.header
619
- // msg._mode = 'RFC4180 mode'
620
+ // msg.columns = csvParseResult.header
621
+ msg.columns = templateArrayToColumnString(csvParseResult.headers) // always strict commas + double quotes for msg.columns
620
622
  delete msg.parts
621
623
  send(msg)
622
624
  node.store = []
623
625
  }
624
626
  }
625
627
  else {
626
- msg.columns = csvParseResult.header
627
- // msg._mode = 'RFC4180 mode'
628
+ msg.columns = templateArrayToColumnString(csvParseResult.headers) // always strict commas + double quotes for msg.columns
628
629
  msg.payload = data
629
630
  send(msg); // finally send the array
630
631
  }
@@ -633,7 +634,8 @@ module.exports = function(RED) {
633
634
  const len = data.length
634
635
  for (let row = 0; row < len; row++) {
635
636
  const newMessage = RED.util.cloneMessage(msg)
636
- newMessage.columns = csvParseResult.header
637
+ // newMessage.columns = csvParseResult.header
638
+ newMessage.columns = templateArrayToColumnString(csvParseResult.headers) // always strict commas + double quotes for msg.columns
637
639
  newMessage.payload = data[row]
638
640
  if (!has_parts) {
639
641
  newMessage.parts = {
@@ -339,7 +339,7 @@ module.exports = function(RED) {
339
339
  }
340
340
  else {
341
341
  msg.filename = filename;
342
- var lines = Buffer.from([]);
342
+ const bufferArray = [];
343
343
  var spare = "";
344
344
  var count = 0;
345
345
  var type = "buffer";
@@ -397,7 +397,7 @@ module.exports = function(RED) {
397
397
  }
398
398
  }
399
399
  else {
400
- lines = Buffer.concat([lines,chunk]);
400
+ bufferArray.push(chunk);
401
401
  }
402
402
  }
403
403
  })
@@ -413,10 +413,11 @@ module.exports = function(RED) {
413
413
  })
414
414
  .on('end', function() {
415
415
  if (node.chunk === false) {
416
+ const buffer = Buffer.concat(bufferArray);
416
417
  if (node.format === "utf8") {
417
- msg.payload = decode(lines, node.encoding);
418
+ msg.payload = decode(buffer, node.encoding);
418
419
  }
419
- else { msg.payload = lines; }
420
+ else { msg.payload = buffer; }
420
421
  nodeSend(msg);
421
422
  }
422
423
  else if (node.format === "lines") {
@@ -48,7 +48,8 @@
48
48
  <dl class="message-properties">
49
49
  <dt>action <span class="property-type">string</span></dt>
50
50
  <dd>the name of the action the node should perform. Available actions are: <code>"connect"</code>,
51
- <code>"disconnect"</code>, <code>"subscribe"</code> and <code>"unsubscribe"</code>.</dd>
51
+ <code>"disconnect"</code>, <code>"getSubscriptions"</code>, <code>"subscribe"</code> and
52
+ <code>"unsubscribe"</code>.</dd>
52
53
  <dt class="optional">topic <span class="property-type">string|object|array</span></dt>
53
54
  <dd>For the <code>"subscribe"</code> and <code>"unsubscribe"</code> actions, this property
54
55
  provides the topic. It can be set as either:<ul>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node-red/nodes",
3
- "version": "4.0.5",
3
+ "version": "4.0.6",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",