@node-red/nodes 4.0.4 → 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:
|
|
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
|
-
|
|
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 (
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
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
|
}
|
package/core/parsers/70-CSV.js
CHANGED
|
@@ -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 = [
|
|
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.
|
|
377
|
-
return
|
|
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:
|
|
381
|
-
const parsed = csv.parse('', {headers: template, headersOnly:true, separator
|
|
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
|
|
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
|
-
|
|
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.
|
|
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 = {
|
package/core/storage/10-file.js
CHANGED
|
@@ -339,7 +339,7 @@ module.exports = function(RED) {
|
|
|
339
339
|
}
|
|
340
340
|
else {
|
|
341
341
|
msg.filename = filename;
|
|
342
|
-
|
|
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
|
-
|
|
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(
|
|
418
|
+
msg.payload = decode(buffer, node.encoding);
|
|
418
419
|
}
|
|
419
|
-
else { msg.payload =
|
|
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>"
|
|
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>
|