@node-red/nodes 1.3.3 → 1.3.7

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.
@@ -214,7 +214,7 @@
214
214
  for (var i=0,l=props.length; i<l; i++) {
215
215
  if (i > 0) lab += "\n";
216
216
  if (i === 5) {
217
- lab += " + "+(props.length-4);
217
+ lab += "... +"+(props.length-5);
218
218
  break;
219
219
  }
220
220
  lab += props[i].p+": ";
@@ -636,7 +636,7 @@
636
636
  url: "inject/"+this.id,
637
637
  type:"POST",
638
638
  success: function(resp) {
639
- RED.notify(node._("inject.success",{label:label}),{type:"success",id:"inject"});
639
+ RED.notify(node._("inject.success",{label:label}),{type:"success",id:"inject", timeout: 2000});
640
640
  },
641
641
  error: function(jqXHR,textStatus,errorThrown) {
642
642
  if (jqXHR.status == 404) {
@@ -129,9 +129,9 @@
129
129
  RED.history.push(historyEvent);
130
130
  RED.view.redraw();
131
131
  if (xhr.status == 200) {
132
- RED.notify(node._("debug.notification.activated",{label:label}),"success");
132
+ RED.notify(node._("debug.notification.activated",{label:label}),{type: "success", timeout: 2000});
133
133
  } else if (xhr.status == 201) {
134
- RED.notify(node._("debug.notification.deactivated",{label:label}),"success");
134
+ RED.notify(node._("debug.notification.deactivated",{label:label}),{type: "success", timeout: 2000});
135
135
  }
136
136
  });
137
137
  }
@@ -2,7 +2,8 @@ module.exports = function(RED) {
2
2
  "use strict";
3
3
  var util = require("util");
4
4
  var events = require("events");
5
- //var path = require("path");
5
+ const fs = require("fs-extra");
6
+ const path = require("path");
6
7
  var debuglength = RED.settings.debugMaxLength || 1000;
7
8
  var useColors = RED.settings.debugUseColors || false;
8
9
  util.inspect.styles.boolean = "red";
@@ -249,11 +250,34 @@ module.exports = function(RED) {
249
250
  }
250
251
  });
251
252
 
253
+ let cachedDebugView;
254
+ RED.httpAdmin.get("/debug/view/view.html", function(req,res) {
255
+ if (!cachedDebugView) {
256
+ fs.readFile(path.join(__dirname,"lib","debug","view.html")).then(data => {
257
+ let customStyles = "";
258
+ try {
259
+ let customStyleList = RED.settings.editorTheme.page._.css || [];
260
+ customStyleList.forEach(style => {
261
+ customStyles += `<link rel="stylesheet" href="../../${style}">\n`
262
+ })
263
+ } catch(err) {}
264
+ cachedDebugView = data.toString().replace("<!-- INSERT-THEME-CSS -->",customStyles)
265
+ res.set('Content-Type', 'text/html');
266
+ res.send(cachedDebugView).end();
267
+ }).catch(err => {
268
+ res.sendStatus(404);
269
+ })
270
+ } else {
271
+ res.send(cachedDebugView).end();
272
+ }
273
+
274
+ });
275
+
252
276
  // As debug/view/debug-utils.js is loaded via <script> tag, it won't get
253
277
  // the auth header attached. So do not use RED.auth.needsPermission here.
254
278
  RED.httpAdmin.get("/debug/view/*",function(req,res) {
255
279
  var options = {
256
- root: __dirname + '/lib/debug/',
280
+ root: path.join(__dirname,"lib","debug"),
257
281
  dotfiles: 'deny'
258
282
  };
259
283
  res.sendFile(req.params[0], options);
@@ -2,6 +2,7 @@
2
2
  <head>
3
3
  <link rel="stylesheet" href="../../red/style.min.css">
4
4
  <link rel="stylesheet" href="../../vendor/font-awesome/css/font-awesome.min.css">
5
+ <!-- INSERT-THEME-CSS -->
5
6
  <title>Node-RED Debug Tools</title>
6
7
  </head>
7
8
  <body class="red-ui-editor red-ui-debug-window">
@@ -74,21 +74,21 @@
74
74
  <div id="func-tab-init" style="display:none">
75
75
  <div class="form-row node-text-editor-row" style="position:relative">
76
76
  <div style="height: 250px; min-height:150px;" class="node-text-editor" id="node-input-init-editor" ></div>
77
- <div style="position: absolute; right:0; bottom: calc(100% - 20px);"><button id="node-init-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
77
+ <div style="position: absolute; right:0; bottom: calc(100% - 20px); z-Index: 10;"><button id="node-init-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
78
78
  </div>
79
79
  </div>
80
80
 
81
81
  <div id="func-tab-body" style="display:none">
82
82
  <div class="form-row node-text-editor-row" style="position:relative">
83
83
  <div style="height: 220px; min-height:150px;" class="node-text-editor" id="node-input-func-editor" ></div>
84
- <div style="position: absolute; right:0; bottom: calc(100% - 20px);"><button id="node-function-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
84
+ <div style="position: absolute; right:0; bottom: calc(100% - 20px); z-Index: 10;"><button id="node-function-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
85
85
  </div>
86
86
  </div>
87
87
 
88
88
  <div id="func-tab-finalize" style="display:none">
89
89
  <div class="form-row node-text-editor-row" style="position:relative">
90
90
  <div style="height: 250px; min-height:150px;" class="node-text-editor" id="node-input-finalize-editor" ></div>
91
- <div style="position: absolute; right:0; bottom: calc(100% - 20px);"><button id="node-finalize-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
91
+ <div style="position: absolute; right:0; bottom: calc(100% - 20px); z-Index: 10;"><button id="node-finalize-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
92
92
  </div>
93
93
  </div>
94
94
 
@@ -19,6 +19,8 @@ module.exports = function(RED) {
19
19
 
20
20
  var util = require("util");
21
21
  var vm = require("vm");
22
+ var acorn = require("acorn");
23
+ var acornWalk = require("acorn-walk");
22
24
 
23
25
  function sendResults(node,send,_msgid,msgs,cloneFirstMessage) {
24
26
  if (msgs == null) {
@@ -102,14 +104,7 @@ module.exports = function(RED) {
102
104
  throw new Error(RED._("function.error.externalModuleNotAllowed"));
103
105
  }
104
106
 
105
- var handleNodeDoneCall = true;
106
107
 
107
- // Check to see if the Function appears to call `node.done()`. If so,
108
- // we will assume it is well written and does actually call node.done().
109
- // Otherwise, we will call node.done() after the function returns regardless.
110
- if (/node\.done\s*\(\s*\)/.test(node.func)) {
111
- handleNodeDoneCall = false;
112
- }
113
108
 
114
109
  var functionText = "var results = null;"+
115
110
  "results = (async function(msg,__send__,__done__){ "+
@@ -130,6 +125,26 @@ module.exports = function(RED) {
130
125
  "};\n"+
131
126
  node.func+"\n"+
132
127
  "})(msg,__send__,__done__);";
128
+
129
+ var handleNodeDoneCall = true;
130
+
131
+ // Check to see if the Function appears to call `node.done()`. If so,
132
+ // we will assume it is well written and does actually call node.done().
133
+ // Otherwise, we will call node.done() after the function returns regardless.
134
+ if (/node\.done\s*\(\s*\)/.test(functionText)) {
135
+ // We have spotted the code contains `node.done`. It could be in a comment
136
+ // so need to do the extra work to parse the AST and examine it properly.
137
+ acornWalk.simple(acorn.parse(functionText,{ecmaVersion: "latest"} ), {
138
+ CallExpression(astNode) {
139
+ if (astNode.callee && astNode.callee.object) {
140
+ if (astNode.callee.object.name === "node" && astNode.callee.property.name === "done") {
141
+ handleNodeDoneCall = false;
142
+ }
143
+ }
144
+ }
145
+ })
146
+ }
147
+
133
148
  var finScript = null;
134
149
  var finOpt = null;
135
150
  node.topic = n.topic;
@@ -366,7 +381,8 @@ module.exports = function(RED) {
366
381
  __node__.error("Cannot send from close function");
367
382
  }
368
383
  };
369
- `+node.fin +`})();`;
384
+ `+node.fin +`
385
+ })();`;
370
386
  finOpt = createVMOpt(node, " cleanup");
371
387
  finScript = new vm.Script(finText, finOpt);
372
388
  }
@@ -489,4 +505,3 @@ module.exports = function(RED) {
489
505
  });
490
506
  RED.library.register("functions");
491
507
  };
492
-
@@ -217,6 +217,10 @@ module.exports = function(RED) {
217
217
 
218
218
  function applyRules(node, msg, property,state,done) {
219
219
  if (!state) {
220
+ if (node.rules.length === 0) {
221
+ done(undefined, []);
222
+ return;
223
+ }
220
224
  state = {
221
225
  currentRule: 0,
222
226
  elseflag: true,
@@ -45,9 +45,9 @@
45
45
  </div>
46
46
  <div id="random-details" class="form-row">
47
47
  <label for="node-input-randomFirst"><i class="fa fa-clock-o"></i> <span data-i18n="delay.between"></span></label>
48
- <input type="text" id="node-input-randomFirst" placeholder="" style="text-align:end; width:30px !important">
49
- <span data-i18n="delay.and"></span>
50
- <input type="text" id="node-input-randomLast" placeholder="" style="text-align:end; width:30px !important">
48
+ <input type="text" id="node-input-randomFirst" placeholder="" style="text-align:end; width:50px !important">
49
+ &nbsp;<span data-i18n="delay.and"></span>&nbsp;
50
+ <input type="text" id="node-input-randomLast" placeholder="" style="text-align:end; width:50px !important">
51
51
  <select id="node-input-randomUnits" style="width:140px !important">
52
52
  <option value="milliseconds" data-i18n="delay.milisecs"></option>
53
53
  <option value="seconds" data-i18n="delay.secs"></option>
@@ -812,10 +812,7 @@
812
812
  default: !this.expiry ? 'none':'num',
813
813
  types: [typedInputNoneOpt, 'num']
814
814
  });
815
- $("#node-input-contentType").on('change', function (event, type, value, urg) {
816
- console.log(event);
817
- console.log("ct change",type,value, urg);
818
- }).typedInput({
815
+ $("#node-input-contentType").typedInput({
819
816
  default: getDefaultContentType(this.contentType),
820
817
  types: contentTypeOpts
821
818
  })
@@ -38,18 +38,18 @@ module.exports = function(RED) {
38
38
  if (this.hdrout === true) { this.hdrout = "all"; }
39
39
  var tmpwarn = true;
40
40
  var node = this;
41
- var re = new RegExp(node.sep+'(?=(?:(?:[^"]*"){2})*[^"]*$)','g');
41
+ var re = new RegExp(node.sep.replace(/[-[\]{}()*+!<=:?.\/\\^$|#\s,]/g,'\\$&') + '(?=(?:(?:[^"]*"){2})*[^"]*$)','g');
42
42
 
43
43
  // pass in an array of column names to be trimmed, de-quoted and retrimmed
44
44
  var clean = function(col,sep) {
45
- if (sep) { re = new RegExp(sep+'(?=(?:(?:[^"]*"){2})*[^"]*$)','g'); }
45
+ if (sep) { re = new RegExp(sep.replace(/[-[\]{}()*+!<=:?.\/\\^$|#\s,]/g,'\\$&') +'(?=(?:(?:[^"]*"){2})*[^"]*$)','g'); }
46
46
  col = col.trim().split(re) || [""];
47
47
  col = col.map(x => x.replace(/"/g,'').trim());
48
48
  if ((col.length === 1) && (col[0] === "")) { node.goodtmpl = false; }
49
49
  else { node.goodtmpl = true; }
50
50
  return col;
51
51
  }
52
- var template = clean(node.template);
52
+ var template = clean(node.template,',');
53
53
  var notemplate = template.length === 1 && template[0] === '';
54
54
  node.hdrSent = false;
55
55
 
@@ -185,7 +185,7 @@ module.exports = function(RED) {
185
185
  if ((node.hdrin === true) && first) { // if the template is in the first line
186
186
  if ((line[i] === "\n")||(line[i] === "\r")||(line.length - i === 1)) { // look for first line break
187
187
  if (line.length - i === 1) { tmp += line[i]; }
188
- template = clean(tmp);
188
+ template = clean(tmp,node.sep);
189
189
  first = false;
190
190
  }
191
191
  else { tmp += line[i]; }
@@ -203,7 +203,7 @@ module.exports = function(RED) {
203
203
  if ( template[j] && (template[j] !== "") ) {
204
204
  // if no value between separators ('1,,"3"...') or if the line beings with separator (',1,"2"...') treat value as null
205
205
  if (line[i-1] === node.sep || line[i-1].includes('\n','\r')) k[j] = null;
206
- if ( (k[j] !== null && node.parsestrings === true) && reg.test(k[j]) ) { k[j] = parseFloat(k[j]); }
206
+ if ( (k[j] !== null && node.parsestrings === true) && reg.test(k[j].trim()) ) { k[j] = parseFloat(k[j].trim()); }
207
207
  if (node.include_null_values && k[j] === null) o[template[j]] = k[j];
208
208
  if (node.include_empty_strings && k[j] === "") o[template[j]] = k[j];
209
209
  if (k[j] !== null && k[j] !== "") o[template[j]] = k[j];
@@ -218,7 +218,7 @@ module.exports = function(RED) {
218
218
  if ( template[j] && (template[j] !== "") ) {
219
219
  // if separator before end of line, set null value ie. '1,2,"3"\n1,2,\n1,2,3'
220
220
  if (line[i-1] === node.sep) k[j] = null;
221
- if ( (k[j] !== null && node.parsestrings === true) && reg.test(k[j]) ) { k[j] = parseFloat(k[j]); }
221
+ if ( (k[j] !== null && node.parsestrings === true) && reg.test(k[j].trim()) ) { k[j] = parseFloat(k[j].trim()); }
222
222
  else { if (k[j] !== null) k[j].replace(/\r$/,''); }
223
223
  if (node.include_null_values && k[j] === null) o[template[j]] = k[j];
224
224
  if (node.include_empty_strings && k[j] === "") o[template[j]] = k[j];
@@ -242,7 +242,7 @@ module.exports = function(RED) {
242
242
  if (!node.goodtmpl) { template[j] = "col"+(j+1); }
243
243
 
244
244
  if ( template[j] && (template[j] !== "") ) {
245
- if ( (k[j] !== null && node.parsestrings === true) && reg.test(k[j]) ) { k[j] = parseFloat(k[j]); }
245
+ if ( (k[j] !== null && node.parsestrings === true) && reg.test(k[j].trim()) ) { k[j] = parseFloat(k[j].trim()); }
246
246
  else { if (k[j] !== null) k[j].replace(/\r$/,''); }
247
247
  if (node.include_null_values && k[j] === null) o[template[j]] = k[j];
248
248
  if (node.include_empty_strings && k[j] === "") o[template[j]] = k[j];
@@ -23,9 +23,13 @@ module.exports = function(RED) {
23
23
  var getAllDirs = function (dir, filelist) {
24
24
  filelist = filelist || [];
25
25
  fs.readdirSync(dir).forEach(file => {
26
- if (fs.statSync(path.join(dir, file)).isDirectory() ) {
27
- filelist.push(path.join(dir, file));
28
- getAllDirs(path.join(dir, file), filelist);
26
+ try {
27
+ if (fs.statSync(path.join(dir, file)).isDirectory() ) {
28
+ filelist.push(path.join(dir, file));
29
+ getAllDirs(path.join(dir, file), filelist);
30
+ }
31
+ } catch (error) {
32
+ //should we raise an error?
29
33
  }
30
34
  });
31
35
  return filelist;
@@ -1,18 +1,18 @@
1
1
  [
2
2
  {
3
- "id": "2ebdd51e.c5d17a",
3
+ "id": "b05816ab.7f2b08",
4
4
  "type": "comment",
5
- "z": "4b63452d.672afc",
6
- "name": "Convert array of JavaScript objects to CSV with column name header",
7
- "info": "CSV node can convert an array of JavaScript objects to multi-line CSV text with column name header at first line.",
8
- "x": 390,
9
- "y": 1200,
5
+ "z": "c6ffdacd.d887e8",
6
+ "name": "Specify column names in input message",
7
+ "info": "Column names can be specified by `columns` property of incoming message.\n",
8
+ "x": 240,
9
+ "y": 200,
10
10
  "wires": []
11
11
  },
12
12
  {
13
- "id": "2b4d538d.ada07c",
13
+ "id": "39205b5c.690684",
14
14
  "type": "inject",
15
- "z": "4b63452d.672afc",
15
+ "z": "c6ffdacd.d887e8",
16
16
  "name": "",
17
17
  "props": [
18
18
  {
@@ -30,41 +30,41 @@
30
30
  "topic": "",
31
31
  "payload": "",
32
32
  "payloadType": "date",
33
- "x": 260,
34
- "y": 1260,
33
+ "x": 200,
34
+ "y": 260,
35
35
  "wires": [
36
36
  [
37
- "3e5c9e8.5065b62"
37
+ "526b59ba.2fa068"
38
38
  ]
39
39
  ]
40
40
  },
41
41
  {
42
- "id": "db02c7be.0984e8",
42
+ "id": "b78a407e.2d083",
43
43
  "type": "csv",
44
- "z": "4b63452d.672afc",
44
+ "z": "c6ffdacd.d887e8",
45
45
  "name": "",
46
46
  "sep": ",",
47
47
  "hdrin": false,
48
48
  "hdrout": "all",
49
49
  "multi": "one",
50
50
  "ret": "\\n",
51
- "temp": "kind,price",
51
+ "temp": "",
52
52
  "skip": "0",
53
53
  "strings": true,
54
54
  "include_empty_strings": "",
55
55
  "include_null_values": "",
56
- "x": 600,
57
- "y": 1260,
56
+ "x": 750,
57
+ "y": 260,
58
58
  "wires": [
59
59
  [
60
- "61f8b772.ddb1f8"
60
+ "8b7084dd.986f68"
61
61
  ]
62
62
  ]
63
63
  },
64
64
  {
65
- "id": "3e5c9e8.5065b62",
65
+ "id": "526b59ba.2fa068",
66
66
  "type": "template",
67
- "z": "4b63452d.672afc",
67
+ "z": "c6ffdacd.d887e8",
68
68
  "name": "JS object",
69
69
  "field": "payload",
70
70
  "fieldType": "msg",
@@ -72,18 +72,18 @@
72
72
  "syntax": "plain",
73
73
  "template": "[\n {\n \"kind\": \"Apple\",\n \"price\": 100,\n \"origin\": \"Canada\"\n },\n {\n \"kind\": \"Orange\",\n \"price\": 120,\n \"origin\": \"USA\"\n },\n {\n \"kind\": \"Banana\",\n \"price\": 80,\n \"origin\": \"Philippines\"\n }\n]",
74
74
  "output": "json",
75
- "x": 430,
76
- "y": 1260,
75
+ "x": 370,
76
+ "y": 260,
77
77
  "wires": [
78
78
  [
79
- "db02c7be.0984e8"
79
+ "b204077a.227778"
80
80
  ]
81
81
  ]
82
82
  },
83
83
  {
84
- "id": "61f8b772.ddb1f8",
84
+ "id": "8b7084dd.986f68",
85
85
  "type": "debug",
86
- "z": "4b63452d.672afc",
86
+ "z": "c6ffdacd.d887e8",
87
87
  "name": "",
88
88
  "active": true,
89
89
  "tosidebar": true,
@@ -92,8 +92,35 @@
92
92
  "complete": "false",
93
93
  "statusVal": "",
94
94
  "statusType": "auto",
95
- "x": 780,
96
- "y": 1260,
95
+ "x": 930,
96
+ "y": 260,
97
97
  "wires": []
98
+ },
99
+ {
100
+ "id": "b204077a.227778",
101
+ "type": "change",
102
+ "z": "c6ffdacd.d887e8",
103
+ "name": "",
104
+ "rules": [
105
+ {
106
+ "t": "set",
107
+ "p": "columns",
108
+ "pt": "msg",
109
+ "to": "kind,price",
110
+ "tot": "str"
111
+ }
112
+ ],
113
+ "action": "",
114
+ "property": "",
115
+ "from": "",
116
+ "to": "",
117
+ "reg": false,
118
+ "x": 570,
119
+ "y": 260,
120
+ "wires": [
121
+ [
122
+ "b78a407e.2d083"
123
+ ]
124
+ ]
98
125
  }
99
126
  ]
@@ -21,9 +21,10 @@
21
21
  the body of the message.</p>
22
22
  <p>The function is expected to return a message object (or multiple message objects), but can choose
23
23
  to return nothing in order to halt a flow.</p>
24
- <p>The <b>Setup</b> tab contains code that will be run whenever the node is started.
25
- The <b>Close</b> tab contains code that will be run when the node is stopped.</p>
26
- <p>If an promise object is returned from the setup code, input message processing starts after its completion.</p>
24
+ <p>The <b>On Start</b> tab contains code that will be run whenever the node is started.
25
+ The <b>On Stop</b> tab contains code that will be run when the node is stopped.</p>
26
+ <p>If the On Start code returns a Promise object, the node will not start handling messages
27
+ until the promise is resolved.</p>
27
28
  <h3>Details</h3>
28
29
  <p>See the <a target="_blank" href="http://nodered.org/docs/writing-functions.html">online documentation</a>
29
30
  for more information on writing functions.</p>
@@ -19,8 +19,8 @@
19
19
  <p>入力メッセージは<code>msg</code>という名称のJavaScriptオブジェクトで受け渡されます。</p>
20
20
  <p><code>msg</code>オブジェクトは<code>msg.payload</code>プロパティにメッセージ本体を保持するのが慣例です。</p>
21
21
  <p>通常、コードはメッセージオブジェクト(もしくは複数のメッセージオブジェクト)を返却します。後続フローの実行を停止したい場合は、オブジェクトを返却しなくてもかまいません。</p>
22
- <p>Node-REDの開始時もしくはフローの設定をデプロイした際実行される初期化コードを<b>初期化処理</b>タブに、ノードの停止もしくは再デプロイ時に実行される終了処理コードを<b>終了処理</b>タブに指定できます。</p>
23
- <p>初期化処理タブの返却値としてPromiseを返却すると、入力メッセージの処理を開始する前にその完了を待ちます。</p>
22
+ <p><b>初期化処理</b>タブにはノードの開始時に実行されるコードを、<b>終了処理</b>タブにはノードの終了時に実行されるコードを指定します。</p>
23
+ <p>初期化処理タブの返却値としてPromiseオブジェクトを返却すると、入力メッセージの処理を開始する前にその完了を待ちます。</p>
24
24
  <h3>詳細</h3>
25
25
  <p>コードの書き方の詳細については、<a target="_blank" href="http://nodered.org/docs/writing-functions.html">オンラインドキュメント</a>を参照してください。</p>
26
26
  <h4>メッセージの送信</h4>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node-red/nodes",
3
- "version": "1.3.3",
3
+ "version": "1.3.7",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
@@ -15,6 +15,8 @@
15
15
  }
16
16
  ],
17
17
  "dependencies": {
18
+ "acorn": "8.3.0",
19
+ "acorn-walk": "8.1.0",
18
20
  "ajv": "6.12.6",
19
21
  "body-parser": "1.19.0",
20
22
  "cheerio": "0.22.0",
@@ -37,7 +39,7 @@
37
39
  "on-headers": "1.0.2",
38
40
  "raw-body": "2.4.1",
39
41
  "request": "2.88.0",
40
- "ws": "6.2.1",
42
+ "ws": "6.2.2",
41
43
  "xml2js": "0.4.23",
42
44
  "iconv-lite": "0.6.2"
43
45
  }