mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Merge branch 'dev' into search-options
This commit is contained in:
commit
c07eddbd97
32
CHANGELOG.md
32
CHANGELOG.md
@ -1,3 +1,35 @@
|
||||
#### 2.2.2: Maintenance Release
|
||||
|
||||
Nodes
|
||||
|
||||
- Fix "close timed out" error when performing full deploy or modifying broker node. (#3451) @Steve-Mcl
|
||||
|
||||
|
||||
#### 2.2.1: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
||||
- Handle mixed-cased filter terms in keyboard shortcut dialog (#3444) @knolleary
|
||||
- Prevent duplicate links being added between nodes (#3442) @knolleary
|
||||
- Fix to hide tooltip after removing subflow tab (#3391) @HiroyasuNishiyama
|
||||
- Fix node validation to be applied to config node (#3397) @HiroyasuNishiyama
|
||||
- Fix: Dont add wires to undo buffer twice (#3437) @Steve-Mcl
|
||||
|
||||
Runtime
|
||||
|
||||
- Improve module location parsing (of stack info) when adding hook (#3447) @Steve-Mcl
|
||||
- Fix substitution of NR_NODE_PATH (#3445) @HiroyasuNishiyama
|
||||
- Remove console.log when ignoring disabled module (#3439) @knolleary
|
||||
- Improve "Unexpected Node Error" logging (#3446) @Steve-Mcl
|
||||
|
||||
Nodes
|
||||
|
||||
- Debug: Fix no-prototype-builtins bug in debug node and utils (#3394) @Alkarex
|
||||
- Delay: Fix Japanese message of delay node (#3434)
|
||||
- Allow nbRateUnits to be undefined when validating (#3443) @knolleary
|
||||
- Coding help for recently added node-red Predefined Environment Variables (#3440) @Steve-Mcl
|
||||
|
||||
|
||||
#### 2.2.0: Milestone Release
|
||||
|
||||
Editor
|
||||
|
26
package.json
26
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "node-red",
|
||||
"version": "2.2.0",
|
||||
"version": "2.2.2",
|
||||
"description": "Low-code programming for event-driven applications",
|
||||
"homepage": "http://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
@ -28,7 +28,7 @@
|
||||
"dependencies": {
|
||||
"acorn": "8.7.0",
|
||||
"acorn-walk": "8.2.0",
|
||||
"ajv": "8.9.0",
|
||||
"ajv": "8.10.0",
|
||||
"async-mutex": "0.3.2",
|
||||
"basic-auth": "2.0.1",
|
||||
"bcryptjs": "2.4.3",
|
||||
@ -36,7 +36,7 @@
|
||||
"cheerio": "1.0.0-rc.10",
|
||||
"clone": "2.1.2",
|
||||
"content-type": "1.0.4",
|
||||
"cookie": "0.4.1",
|
||||
"cookie": "0.4.2",
|
||||
"cookie-parser": "1.4.6",
|
||||
"cors": "2.8.5",
|
||||
"cronosjs": "1.7.1",
|
||||
@ -50,32 +50,32 @@
|
||||
"hash-sum": "2.0.0",
|
||||
"hpagent": "0.1.2",
|
||||
"https-proxy-agent": "5.0.0",
|
||||
"i18next": "21.6.10",
|
||||
"i18next": "21.6.11",
|
||||
"iconv-lite": "0.6.3",
|
||||
"is-utf8": "0.2.1",
|
||||
"js-yaml": "3.14.1",
|
||||
"json-stringify-safe": "5.0.1",
|
||||
"jsonata": "1.8.5",
|
||||
"jsonata": "1.8.6",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"media-typer": "1.1.0",
|
||||
"memorystore": "1.6.6",
|
||||
"memorystore": "1.6.7",
|
||||
"mime": "3.0.0",
|
||||
"moment-timezone": "0.5.34",
|
||||
"mqtt": "4.3.4",
|
||||
"mqtt": "4.3.5",
|
||||
"multer": "1.4.4",
|
||||
"mustache": "4.2.0",
|
||||
"node-red-admin": "^2.2.1",
|
||||
"node-red-admin": "^2.2.3",
|
||||
"nopt": "5.0.0",
|
||||
"oauth2orize": "1.11.1",
|
||||
"on-headers": "1.0.2",
|
||||
"passport": "0.5.2",
|
||||
"passport-http-bearer": "1.0.1",
|
||||
"passport-oauth2-client-password": "0.1.2",
|
||||
"raw-body": "2.4.2",
|
||||
"raw-body": "2.4.3",
|
||||
"semver": "7.3.5",
|
||||
"tar": "6.1.11",
|
||||
"tough-cookie": "4.0.0",
|
||||
"uglify-js": "3.15.0",
|
||||
"uglify-js": "3.15.1",
|
||||
"uuid": "8.3.2",
|
||||
"ws": "7.5.6",
|
||||
"xml2js": "0.4.23"
|
||||
@ -84,7 +84,7 @@
|
||||
"bcrypt": "5.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"dompurify": "2.3.4",
|
||||
"dompurify": "2.3.5",
|
||||
"grunt": "1.4.1",
|
||||
"grunt-chmod": "~1.1.1",
|
||||
"grunt-cli": "~1.4.3",
|
||||
@ -113,11 +113,11 @@
|
||||
"node-red-node-test-helper": "^0.2.7",
|
||||
"nodemon": "2.0.15",
|
||||
"proxy": "^1.0.2",
|
||||
"sass": "1.49.0",
|
||||
"sass": "1.49.7",
|
||||
"should": "13.2.3",
|
||||
"sinon": "11.1.2",
|
||||
"stoppable": "^1.1.0",
|
||||
"supertest": "6.2.1"
|
||||
"supertest": "6.2.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-api",
|
||||
"version": "2.2.0",
|
||||
"version": "2.2.2",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@ -16,15 +16,15 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "2.2.0",
|
||||
"@node-red/editor-client": "2.2.0",
|
||||
"@node-red/util": "2.2.2",
|
||||
"@node-red/editor-client": "2.2.2",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "1.19.1",
|
||||
"clone": "2.1.2",
|
||||
"cors": "2.8.5",
|
||||
"express-session": "1.17.2",
|
||||
"express": "4.17.2",
|
||||
"memorystore": "1.6.6",
|
||||
"memorystore": "1.6.7",
|
||||
"mime": "3.0.0",
|
||||
"multer": "1.4.4",
|
||||
"mustache": "4.2.0",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-client",
|
||||
"version": "2.2.0",
|
||||
"version": "2.2.2",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -600,6 +600,14 @@ RED.nodes = (function() {
|
||||
RED.events.emit('nodes:add',n);
|
||||
}
|
||||
function addLink(l) {
|
||||
if (nodeLinks[l.source.id]) {
|
||||
const isUnique = nodeLinks[l.source.id].out.every(function(link) {
|
||||
return link.sourcePort !== l.sourcePort || link.target.id !== l.target.id
|
||||
})
|
||||
if (!isUnique) {
|
||||
return
|
||||
}
|
||||
}
|
||||
links.push(l);
|
||||
if (l.source) {
|
||||
// Possible the node hasn't been added yet
|
||||
|
@ -350,6 +350,15 @@ RED.popover = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
target.on("remove", function (ev) {
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
if (active) {
|
||||
active = false;
|
||||
setTimeout(closePopup,delay.hide);
|
||||
}
|
||||
});
|
||||
if (trigger === 'hover') {
|
||||
target.on('mouseenter',function(e) {
|
||||
clearTimeout(timer);
|
||||
|
@ -334,6 +334,9 @@ RED.deploy = (function() {
|
||||
var invalidNodes = [];
|
||||
|
||||
RED.nodes.eachConfig(function(node) {
|
||||
if (node.valid === undefined) {
|
||||
RED.editor.validateNode(node);
|
||||
}
|
||||
if (!node.valid && !node.d) {
|
||||
invalidNodes.push(getNodeInfo(node));
|
||||
}
|
||||
|
@ -577,7 +577,7 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
createMonacoCompletionItem("set (flow context)", 'flow.set("${1:name}", ${1:value});','Set a value in flow context',range),
|
||||
createMonacoCompletionItem("get (global context)", 'global.get("${1:name}");','Get a value from global context',range),
|
||||
createMonacoCompletionItem("set (global context)", 'global.set("${1:name}", ${1:value});','Set a value in global context',range),
|
||||
createMonacoCompletionItem("get (env)", 'env.get("${1:name}");','Get env variable value',range),
|
||||
createMonacoCompletionItem("get (env)", 'env.get("${1|NR_NODE_ID,NR_NODE_NAME,NR_NODE_PATH,NR_GROUP_ID,NR_GROUP_NAME,NR_FLOW_ID,NR_FLOW_NAME|}");','Get env variable value',range),
|
||||
createMonacoCompletionItem("cloneMessage (RED.util)", 'RED.util.cloneMessage(${1:msg});',
|
||||
["```typescript",
|
||||
"RED.util.cloneMessage<T extends registry.NodeMessage>(msg: T): T",
|
||||
|
@ -625,7 +625,7 @@ RED.keyboard = (function() {
|
||||
pane.find("#red-ui-settings-tab-keyboard-filter").searchBox({
|
||||
delay: 100,
|
||||
change: function() {
|
||||
var filterValue = $(this).val().trim();
|
||||
var filterValue = $(this).val().trim().toLowerCase();
|
||||
if (filterValue === "") {
|
||||
shortcutList.editableList('filter', null);
|
||||
} else {
|
||||
|
@ -119,6 +119,7 @@ RED.search = (function() {
|
||||
val = extractFlag(val,"config",flags);
|
||||
val = extractFlag(val,"subflow",flags);
|
||||
val = extractFlag(val,"hidden",flags);
|
||||
val = extractFlag(val,"modified",flags);
|
||||
// uses:<node-id>
|
||||
val = extractValue(val,"uses",flags);
|
||||
|
||||
@ -164,6 +165,11 @@ RED.search = (function() {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (flags.hasOwnProperty("modified")) {
|
||||
if (!node.node.changed && !node.node.moved) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (flags.hasOwnProperty("hidden")) {
|
||||
// Only tabs can be hidden
|
||||
if (node.node.type !== 'tab') {
|
||||
|
@ -2338,14 +2338,21 @@ RED.view = (function() {
|
||||
var removedSubflowStatus;
|
||||
var subflowInstances = [];
|
||||
var historyEvents = [];
|
||||
|
||||
var addToRemovedLinks = function(links) {
|
||||
if(!links) { return; }
|
||||
var _links = Array.isArray(links) ? links : [links];
|
||||
_links.forEach(function(l) {
|
||||
removedLinks.push(l);
|
||||
selectedLinks.remove(l);
|
||||
})
|
||||
}
|
||||
if (reconnectWires) {
|
||||
var reconnectResult = RED.nodes.detachNodes(movingSet.nodes())
|
||||
var addedLinks = reconnectResult.newLinks;
|
||||
if (addedLinks.length > 0) {
|
||||
historyEvents.push({ t:'add', links: addedLinks })
|
||||
}
|
||||
removedLinks = removedLinks.concat(reconnectResult.removedLinks)
|
||||
addToRemovedLinks(reconnectResult.removedLinks)
|
||||
}
|
||||
|
||||
var startDirty = RED.nodes.dirty();
|
||||
@ -2377,7 +2384,7 @@ RED.view = (function() {
|
||||
var removedEntities = RED.nodes.remove(node.id);
|
||||
removedNodes.push(node);
|
||||
removedNodes = removedNodes.concat(removedEntities.nodes);
|
||||
removedLinks = removedLinks.concat(removedEntities.links);
|
||||
addToRemovedLinks(removedNodes.removedLinks);
|
||||
if (node.g) {
|
||||
var group = RED.nodes.group(node.g);
|
||||
if (selectedGroups.indexOf(group) === -1) {
|
||||
@ -2410,20 +2417,20 @@ RED.view = (function() {
|
||||
if (removedSubflowOutputs.length > 0) {
|
||||
result = RED.subflow.removeOutput(removedSubflowOutputs);
|
||||
if (result) {
|
||||
removedLinks = removedLinks.concat(result.links);
|
||||
addToRemovedLinks(result.links);
|
||||
}
|
||||
}
|
||||
// Assume 0/1 inputs
|
||||
if (removedSubflowInputs.length == 1) {
|
||||
result = RED.subflow.removeInput();
|
||||
if (result) {
|
||||
removedLinks = removedLinks.concat(result.links);
|
||||
addToRemovedLinks(result.links);
|
||||
}
|
||||
}
|
||||
if (removedSubflowStatus) {
|
||||
result = RED.subflow.removeStatus();
|
||||
if (result) {
|
||||
removedLinks = removedLinks.concat(result.links);
|
||||
addToRemovedLinks(result.links);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -428,6 +428,9 @@ RED.workspaces = (function() {
|
||||
}
|
||||
}
|
||||
})
|
||||
RED.actions.add("core:list-modified-nodes",function() {
|
||||
RED.actions.invoke("core:search","is:modified ");
|
||||
})
|
||||
RED.actions.add("core:list-hidden-flows",function() {
|
||||
RED.actions.invoke("core:search","is:hidden ");
|
||||
})
|
||||
|
@ -263,6 +263,20 @@ declare class global {
|
||||
static keys(store: string, callback: Function);
|
||||
}
|
||||
declare class env {
|
||||
/** Get an environment variable value */
|
||||
static get(name:string);
|
||||
/**
|
||||
* Get an environment variable value
|
||||
*
|
||||
* Predefined node-red variables...
|
||||
* * `NR_NODE_ID` - the ID of the node
|
||||
* * `NR_NODE_NAME` - the Name of the node
|
||||
* * `NR_NODE_PATH` - the Path of the node
|
||||
* * `NR_GROUP_ID` - the ID of the containing group
|
||||
* * `NR_GROUP_NAME` - the Name of the containing group
|
||||
* * `NR_FLOW_ID` - the ID of the flow the node is on
|
||||
* * `NR_FLOW_NAME` - the Name of the flow the node is on
|
||||
* @param name Name of the environment variable to get
|
||||
* @example
|
||||
* ```const flowName = env.get("NR_FLOW_NAME");```
|
||||
*/
|
||||
static get(name:string) :string;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ module.exports = function(RED) {
|
||||
var debuglength = RED.settings.debugMaxLength || 1000;
|
||||
var useColors = RED.settings.debugUseColors || false;
|
||||
util.inspect.styles.boolean = "red";
|
||||
const { hasOwnProperty } = Object.prototype;
|
||||
|
||||
function DebugNode(n) {
|
||||
var hasEditExpression = (n.targetType === "jsonata");
|
||||
@ -107,7 +108,7 @@ module.exports = function(RED) {
|
||||
}
|
||||
})
|
||||
this.on("input", function(msg, send, done) {
|
||||
if (msg.hasOwnProperty("status") && msg.status.hasOwnProperty("source") && msg.status.source.hasOwnProperty("id") && (msg.status.source.id === node.id)) {
|
||||
if (hasOwnProperty.call(msg, "status") && hasOwnProperty.call(msg.status, "source") && hasOwnProperty.call(msg.status.source, "id") && (msg.status.source.id === node.id)) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
@ -118,17 +119,17 @@ module.exports = function(RED) {
|
||||
var st = (typeof output === 'string') ? output : util.inspect(output);
|
||||
var fill = "grey";
|
||||
var shape = "dot";
|
||||
if (typeof output === 'object' && output.hasOwnProperty("fill") && output.hasOwnProperty("shape") && output.hasOwnProperty("text")) {
|
||||
if (typeof output === 'object' && hasOwnProperty.call(output, "fill") && hasOwnProperty.call(output, "shape") && hasOwnProperty.call(output, "text")) {
|
||||
fill = output.fill;
|
||||
shape = output.shape;
|
||||
st = output.text;
|
||||
}
|
||||
if (node.statusType === "auto") {
|
||||
if (msg.hasOwnProperty("error")) {
|
||||
if (hasOwnProperty.call(msg, "error")) {
|
||||
fill = "red";
|
||||
st = msg.error.message;
|
||||
}
|
||||
if (msg.hasOwnProperty("status")) {
|
||||
if (hasOwnProperty.call(msg, "status")) {
|
||||
fill = msg.status.fill || "grey";
|
||||
shape = msg.status.shape || "ring";
|
||||
st = msg.status.text || "";
|
||||
@ -194,7 +195,7 @@ module.exports = function(RED) {
|
||||
|
||||
function sendDebug(msg) {
|
||||
// don't put blank errors in sidebar (but do add to logs)
|
||||
//if ((msg.msg === "") && (msg.hasOwnProperty("level")) && (msg.level === 20)) { return; }
|
||||
//if ((msg.msg === "") && (hasOwnProperty.call(msg, "level")) && (msg.level === 20)) { return; }
|
||||
msg = RED.util.encodeObject(msg,{maxLength:debuglength});
|
||||
RED.comms.publish("debug",msg);
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ module.exports = function(RED) {
|
||||
catch(e) { return false;}
|
||||
}
|
||||
else if (b === "null") { return a === null; }
|
||||
else if (b === "number") { return typeof a === b && !isNaN(a) }
|
||||
else { return typeof a === b && !Array.isArray(a) && !Buffer.isBuffer(a) && a !== null; }
|
||||
},
|
||||
'head': function(a, b, c, d, parts) {
|
||||
|
@ -115,7 +115,7 @@
|
||||
timeoutUnits: {value:"seconds"},
|
||||
rate: {value:"1", required:true, validate:function(v) { return RED.validators.number(v) && (v >= 0); }},
|
||||
nbRateUnits: {value:"1", required:false,
|
||||
validate:function(v) { return RED.validators.number(v) && (v >= 0); }},
|
||||
validate:function(v) { return v === undefined || (RED.validators.number(v) && (v >= 0)); }},
|
||||
rateUnits: {value: "second"},
|
||||
randomFirst: {value:"1", required:true, validate:function(v) { return RED.validators.number(v) && (v >= 0); }},
|
||||
randomLast: {value:"5", required:true, validate:function(v) { return RED.validators.number(v) && (v >= 0); }},
|
||||
|
@ -637,24 +637,8 @@ module.exports = function(RED) {
|
||||
|
||||
node.deregister = function(mqttNode,done) {
|
||||
delete node.users[mqttNode.id];
|
||||
if (node.closing) {
|
||||
return done();
|
||||
}
|
||||
if (Object.keys(node.users).length === 0) {
|
||||
if (node.client && node.client.connected) {
|
||||
// Send close message
|
||||
if (node.closeMessage) {
|
||||
node.publish(node.closeMessage,function(err) {
|
||||
node.client.end(done);
|
||||
});
|
||||
} else {
|
||||
node.client.end(done);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
if (node.client) { node.client.end(); }
|
||||
return done();
|
||||
}
|
||||
if (!node.closing && node.connected && Object.keys(node.users).length === 0) {
|
||||
node.disconnect();
|
||||
}
|
||||
done();
|
||||
};
|
||||
@ -663,6 +647,7 @@ module.exports = function(RED) {
|
||||
}
|
||||
node.connect = function (callback) {
|
||||
if (node.canConnect()) {
|
||||
node.closing = false;
|
||||
node.connecting = true;
|
||||
setStatusConnecting(node, true);
|
||||
try {
|
||||
@ -672,6 +657,7 @@ module.exports = function(RED) {
|
||||
let callbackDone = false; //prevent re-connects causing node.client.on('connect' firing callback multiple times
|
||||
// Register successful connect or reconnect handler
|
||||
node.client.on('connect', function (connack) {
|
||||
node.closing = false;
|
||||
node.connecting = false;
|
||||
node.connected = true;
|
||||
if(!callbackDone && typeof callback == "function") {
|
||||
@ -740,6 +726,7 @@ module.exports = function(RED) {
|
||||
reasonCode: rc,
|
||||
reasonString: rs
|
||||
}
|
||||
node.connected = false;
|
||||
node.log(RED._("mqtt.state.broker-disconnected", details));
|
||||
setStatusDisconnected(node, true);
|
||||
});
|
||||
@ -764,25 +751,31 @@ module.exports = function(RED) {
|
||||
}
|
||||
};
|
||||
node.disconnect = function (callback) {
|
||||
const _callback = function () {
|
||||
const _callback = function (resetNodeConnectedState) {
|
||||
setStatusDisconnected(node, true);
|
||||
node.connecting = false;
|
||||
node.connected = false;
|
||||
if(resetNodeConnectedState) {
|
||||
node.closing = true;
|
||||
node.connecting = false;
|
||||
node.connected = false;
|
||||
}
|
||||
callback && typeof callback == "function" && callback();
|
||||
};
|
||||
|
||||
if(node.client) {
|
||||
if(node.client.connected && node.closeMessage) {
|
||||
node.publish(node.closeMessage, function (err) {
|
||||
node.client.end(_callback);
|
||||
});
|
||||
} else if(node.client.connected || node.client.reconnecting) {
|
||||
node.client.end(_callback);
|
||||
} else if(node.client.disconnecting || node.client.connected === false) {
|
||||
_callback();
|
||||
}
|
||||
if(node.closing) {
|
||||
return _callback(false);
|
||||
}
|
||||
var endCallBack = function endCallBack() {
|
||||
}
|
||||
if(node.connected && node.closeMessage) {
|
||||
node.publish(node.closeMessage, function (err) {
|
||||
node.client.end(endCallBack);
|
||||
_callback(true);
|
||||
});
|
||||
} else if(node.connected) {
|
||||
node.client.end(endCallBack);
|
||||
_callback(true);
|
||||
} else {
|
||||
_callback();
|
||||
_callback(false);
|
||||
}
|
||||
}
|
||||
node.subscriptionIds = {};
|
||||
@ -1074,6 +1067,8 @@ module.exports = function(RED) {
|
||||
node.brokerConn.unsubscribe(node.topic,node.id, removed);
|
||||
}
|
||||
node.brokerConn.deregister(node, done);
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@ -1134,7 +1129,11 @@ module.exports = function(RED) {
|
||||
}
|
||||
node.brokerConn.register(node);
|
||||
node.on('close', function(done) {
|
||||
node.brokerConn.deregister(node,done);
|
||||
if (node.brokerConn) {
|
||||
node.brokerConn.deregister(node,done);
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
node.error(RED._("mqtt.errors.missing-config"));
|
||||
|
@ -291,8 +291,8 @@
|
||||
"hour": "時間",
|
||||
"days": "日",
|
||||
"day": "日",
|
||||
"between": "頻度",
|
||||
"and": "回/",
|
||||
"between": "範囲",
|
||||
"and": "〜",
|
||||
"rate": "流量",
|
||||
"msgper": "メッセージ/",
|
||||
"queuemsg": "中間メッセージをキューに追加",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/nodes",
|
||||
"version": "2.2.0",
|
||||
"version": "2.2.2",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -17,12 +17,12 @@
|
||||
"dependencies": {
|
||||
"acorn": "8.7.0",
|
||||
"acorn-walk": "8.2.0",
|
||||
"ajv": "8.9.0",
|
||||
"ajv": "8.10.0",
|
||||
"body-parser": "1.19.1",
|
||||
"cheerio": "1.0.0-rc.10",
|
||||
"content-type": "1.0.4",
|
||||
"cookie-parser": "1.4.6",
|
||||
"cookie": "0.4.1",
|
||||
"cookie": "0.4.2",
|
||||
"cors": "2.8.5",
|
||||
"cronosjs": "1.7.1",
|
||||
"denque": "2.0.1",
|
||||
@ -36,11 +36,11 @@
|
||||
"is-utf8": "0.2.1",
|
||||
"js-yaml": "3.14.1",
|
||||
"media-typer": "1.1.0",
|
||||
"mqtt": "4.3.4",
|
||||
"mqtt": "4.3.5",
|
||||
"multer": "1.4.4",
|
||||
"mustache": "4.2.0",
|
||||
"on-headers": "1.0.2",
|
||||
"raw-body": "2.4.2",
|
||||
"raw-body": "2.4.3",
|
||||
"tough-cookie": "4.0.0",
|
||||
"uuid": "8.3.2",
|
||||
"ws": "7.5.6",
|
||||
|
@ -353,7 +353,6 @@ async function loadPluginConfig(fileInfo) {
|
||||
*/
|
||||
function loadNodeSet(node) {
|
||||
if (!node.enabled) {
|
||||
console.log("BAIL ON",node.id)
|
||||
return Promise.resolve(node);
|
||||
} else {
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/registry",
|
||||
"version": "2.2.0",
|
||||
"version": "2.2.2",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@ -16,11 +16,11 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "2.2.0",
|
||||
"@node-red/util": "2.2.2",
|
||||
"clone": "2.1.2",
|
||||
"fs-extra": "10.0.0",
|
||||
"semver": "7.3.5",
|
||||
"tar": "6.1.11",
|
||||
"uglify-js": "3.15.0"
|
||||
"uglify-js": "3.15.1"
|
||||
}
|
||||
}
|
||||
|
@ -77,15 +77,16 @@ function createNode(flow,config) {
|
||||
if (typeof nodeTypeConstructor === "function") {
|
||||
var conf = clone(config);
|
||||
delete conf.credentials;
|
||||
for (var p in conf) {
|
||||
if (conf.hasOwnProperty(p)) {
|
||||
mapEnvVarProperties(conf,p,flow,conf);
|
||||
}
|
||||
}
|
||||
try {
|
||||
Object.defineProperty(conf,'_module', {value: typeRegistry.getNodeInfo(type), enumerable: false, writable: true })
|
||||
Object.defineProperty(conf,'_flow', {value: flow, enumerable: false, writable: true })
|
||||
Object.defineProperty(conf,'_path', {value: `${flow.path}/${config._alias||config.id}`, enumerable: false, writable: true })
|
||||
|
||||
for (var p in conf) {
|
||||
if (conf.hasOwnProperty(p)) {
|
||||
mapEnvVarProperties(conf,p,flow,conf);
|
||||
}
|
||||
}
|
||||
newNode = new nodeTypeConstructor(conf);
|
||||
} catch (err) {
|
||||
Log.log({
|
||||
|
@ -503,10 +503,25 @@ function log_helper(self, level, msg) {
|
||||
o.name = self.name;
|
||||
}
|
||||
// See https://github.com/node-red/node-red/issues/3327
|
||||
// See https://github.com/node-red/node-red/issues/3389
|
||||
|
||||
let srcError;
|
||||
if (msg instanceof Error) {
|
||||
srcError = msg;//use existing err object for actual stack
|
||||
} else {
|
||||
srcError = new Error(msg);//generate a new error for generate a stack
|
||||
}
|
||||
try {
|
||||
self._flow.log(o);
|
||||
if(self instanceof Node && self._flow) {
|
||||
self._flow.log(o);
|
||||
} else {
|
||||
//if self._flow is not present, this is not a node-red Node
|
||||
//Set info to "Node object is not a node-red Node" to point out the `Node type` problem in log
|
||||
logUnexpectedError(self, srcError, "Node object is not a node-red Node")
|
||||
}
|
||||
} catch(err) {
|
||||
logUnexpectedError(self, err)
|
||||
//build an unexpected error report indicating using the original error (for better stack trace)
|
||||
logUnexpectedError(self, srcError, `An error occured attempting to make a log entry: ${err}`)
|
||||
}
|
||||
}
|
||||
/**
|
||||
@ -531,7 +546,7 @@ Node.prototype.error = function(logMessage,msg) {
|
||||
logMessage = logMessage || "";
|
||||
}
|
||||
var handled = false;
|
||||
if (msg && typeof msg === 'object') {
|
||||
if (this._flow && msg && typeof msg === 'object') {
|
||||
handled = this._flow.handleError(this,logMessage,msg);
|
||||
}
|
||||
if (!handled) {
|
||||
@ -619,27 +634,34 @@ function inspectObject(flow) {
|
||||
}
|
||||
}
|
||||
|
||||
function logUnexpectedError(node, error) {
|
||||
let moduleInfo = node._module?`${node._module.module}@${node._module.version}`:"undefined"
|
||||
Log.error(`
|
||||
function logUnexpectedError(node, error, info) {
|
||||
const header = `
|
||||
********************************************************************
|
||||
Unexpected Node Error
|
||||
${error.stack}
|
||||
Node:
|
||||
Type: ${node.type}
|
||||
Module: ${moduleInfo}
|
||||
ID: ${node._alias||node.id}
|
||||
Properties:
|
||||
${inspectObject(node)}
|
||||
Flow: ${node._flow?node._flow.path:'undefined'}
|
||||
Type: ${node._flow?node._flow.TYPE:'undefined'}
|
||||
Properties:
|
||||
${node._flow?inspectObject(node._flow):'undefined'}
|
||||
********************************************************************`;
|
||||
|
||||
const footer = `
|
||||
Please report this issue, including the information logged above:
|
||||
https://github.com/node-red/node-red/issues/
|
||||
********************************************************************
|
||||
`)
|
||||
********************************************************************`;
|
||||
|
||||
let detail = [`Info:\n ${info || 'No additional info'}`];
|
||||
|
||||
//Include Error info?
|
||||
if(error && error.stack){
|
||||
detail.push(`Stack:\n ${error.stack}`)
|
||||
}
|
||||
//Include Node info?
|
||||
if(node && (node._module || node.type)){
|
||||
const moduleInfo = node._module?`${node._module.module}@${node._module.version}`:"undefined";
|
||||
const id = node._alias||node.id||"undefined";
|
||||
detail.push(`Node:\n Type: ${node.type}\n Module: ${moduleInfo}\n ID: ${id}\n Properties:\n ${inspectObject(node)}`)
|
||||
}
|
||||
//Include Flow info?
|
||||
if(node && node._flow){
|
||||
detail.push(`Flow: ${node._flow.path}\n Type: ${node._flow.TYPE}\n Properties:\n ${inspectObject(node._flow)}`)
|
||||
}
|
||||
Log.error(`${header}\n${detail.join("\n")}\n${footer}`);
|
||||
}
|
||||
|
||||
module.exports = Node;
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/runtime",
|
||||
"version": "2.2.0",
|
||||
"version": "2.2.2",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@ -16,8 +16,8 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/registry": "2.2.0",
|
||||
"@node-red/util": "2.2.0",
|
||||
"@node-red/registry": "2.2.2",
|
||||
"@node-red/util": "2.2.2",
|
||||
"async-mutex": "0.3.2",
|
||||
"clone": "2.1.2",
|
||||
"express": "4.17.2",
|
||||
|
@ -67,8 +67,25 @@ function add(hookId, callback) {
|
||||
throw new Error("Hook "+hookId+" already registered")
|
||||
}
|
||||
// Get location of calling code
|
||||
let callModule;
|
||||
const stack = new Error().stack;
|
||||
const callModule = stack.split("\n")[2].split("(")[1].slice(0,-1);
|
||||
const stackEntries = stack.split("\n").slice(1);//drop 1st line (error message)
|
||||
const stackEntry2 = stackEntries[1];//get 2nd stack entry
|
||||
if (stackEntry2) {
|
||||
try {
|
||||
if (stackEntry2.indexOf(" (") >= 0) {
|
||||
callModule = stackEntry2.split("(")[1].slice(0, -1);
|
||||
} else {
|
||||
callModule = stackEntry2.split(" ").slice(-1)[0];
|
||||
}
|
||||
} catch (error) {
|
||||
Log.debug(`Unable to determined module when adding hook '${hookId}'. Stack:\n${stackEntries.join("\n")}`);
|
||||
callModule = "unknown:0:0";
|
||||
}
|
||||
} else {
|
||||
Log.debug(`Unable to determined module when adding hook '${hookId}'. Stack:\n${stackEntries.join("\n")}`);
|
||||
callModule = "unknown:0:0";
|
||||
}
|
||||
Log.debug(`Adding hook '${hookId}' from ${callModule}`);
|
||||
|
||||
const hookItem = {cb:callback, location: callModule, previousHook: null, nextHook: null }
|
||||
|
41
packages/node_modules/@node-red/util/lib/util.js
vendored
41
packages/node_modules/@node-red/util/lib/util.js
vendored
@ -24,6 +24,17 @@ const jsonata = require("jsonata");
|
||||
const moment = require("moment-timezone");
|
||||
const safeJSONStringify = require("json-stringify-safe");
|
||||
const util = require("util");
|
||||
const { hasOwnProperty } = Object.prototype;
|
||||
|
||||
/**
|
||||
* Safely returns the object construtor name.
|
||||
* @return {String} the name of the object constructor if it exists, empty string otherwise.
|
||||
*/
|
||||
function constructorName(obj) {
|
||||
// Note: This function could be replaced by optional chaining in Node.js 14+:
|
||||
// obj?.constructor?.name
|
||||
return obj && obj.constructor ? obj.constructor.name : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a psuedo-unique-random id.
|
||||
@ -171,7 +182,7 @@ function compareObjects(obj1,obj2) {
|
||||
}
|
||||
for (var k in obj1) {
|
||||
/* istanbul ignore else */
|
||||
if (obj1.hasOwnProperty(k)) {
|
||||
if (hasOwnProperty.call(obj1, k)) {
|
||||
if (!compareObjects(obj1[k],obj2[k])) {
|
||||
return false;
|
||||
}
|
||||
@ -462,7 +473,7 @@ function setObjectProperty(msg,prop,value,createMissing) {
|
||||
for (var i=0;i<length-1;i++) {
|
||||
key = msgPropParts[i];
|
||||
if (typeof key === 'string' || (typeof key === 'number' && !Array.isArray(obj))) {
|
||||
if (obj.hasOwnProperty(key)) {
|
||||
if (hasOwnProperty.call(obj, key)) {
|
||||
if (length > 1 && ((typeof obj[key] !== "object" && typeof obj[key] !== "function") || obj[key] === null)) {
|
||||
// Break out early as we cannot create a property beneath
|
||||
// this type of value
|
||||
@ -561,7 +572,7 @@ function getSetting(node, name, flow_) {
|
||||
* @memberof @node-red/util_util
|
||||
*/
|
||||
function evaluateEnvProperty(value, node) {
|
||||
var flow = (node && node.hasOwnProperty("_flow")) ? node._flow : null;
|
||||
var flow = (node && hasOwnProperty.call(node, "_flow")) ? node._flow : null;
|
||||
var result;
|
||||
if (/^\${[^}]+}$/.test(value)) {
|
||||
// ${ENV_VAR}
|
||||
@ -785,7 +796,7 @@ function normaliseNodeTypeName(name) {
|
||||
function encodeObject(msg,opts) {
|
||||
try {
|
||||
var debuglength = 1000;
|
||||
if (opts && opts.hasOwnProperty('maxLength')) {
|
||||
if (opts && hasOwnProperty.call(opts, 'maxLength')) {
|
||||
debuglength = opts.maxLength;
|
||||
}
|
||||
var msgType = typeof msg.msg;
|
||||
@ -795,7 +806,7 @@ function encodeObject(msg,opts) {
|
||||
if (msg.msg.name) {
|
||||
errorMsg.name = msg.msg.name;
|
||||
}
|
||||
if (msg.msg.hasOwnProperty('message')) {
|
||||
if (hasOwnProperty.call(msg.msg, 'message')) {
|
||||
errorMsg.message = msg.msg.message;
|
||||
} else {
|
||||
errorMsg.message = msg.msg.toString();
|
||||
@ -809,7 +820,7 @@ function encodeObject(msg,opts) {
|
||||
}
|
||||
} else if (msg.msg && msgType === 'object') {
|
||||
try {
|
||||
msg.format = msg.msg.constructor.name || "Object";
|
||||
msg.format = constructorName(msg.msg) || "Object";
|
||||
// Handle special case of msg.req/res objects from HTTP In node
|
||||
if (msg.format === "IncomingMessage" || msg.format === "ServerResponse") {
|
||||
msg.format = "Object";
|
||||
@ -836,7 +847,7 @@ function encodeObject(msg,opts) {
|
||||
length: msg.msg.length
|
||||
}
|
||||
}
|
||||
} else if (msg.msg && msg.msg.constructor.name === "Set") {
|
||||
} else if (constructorName(msg.msg) === "Set") {
|
||||
msg.format = "set["+msg.msg.size+"]";
|
||||
msg.msg = {
|
||||
__enc__: true,
|
||||
@ -845,7 +856,7 @@ function encodeObject(msg,opts) {
|
||||
length: msg.msg.size
|
||||
}
|
||||
needsStringify = true;
|
||||
} else if (msg.msg && msg.msg.constructor.name === "Map") {
|
||||
} else if (constructorName(msg.msg) === "Map") {
|
||||
msg.format = "map";
|
||||
msg.msg = {
|
||||
__enc__: true,
|
||||
@ -854,7 +865,7 @@ function encodeObject(msg,opts) {
|
||||
length: msg.msg.size
|
||||
}
|
||||
needsStringify = true;
|
||||
} else if (msg.msg && msg.msg.constructor.name === "RegExp") {
|
||||
} else if (constructorName(msg.msg) === "RegExp") {
|
||||
msg.format = 'regexp';
|
||||
msg.msg = msg.msg.toString();
|
||||
}
|
||||
@ -904,25 +915,25 @@ function encodeObject(msg,opts) {
|
||||
if (value.length > debuglength) {
|
||||
value.data = value.data.slice(0,debuglength);
|
||||
}
|
||||
} else if (value.constructor.name === "ServerResponse") {
|
||||
} else if (constructorName(value) === "ServerResponse") {
|
||||
value = "[internal]"
|
||||
} else if (value.constructor.name === "Socket") {
|
||||
} else if (constructorName(value) === "Socket") {
|
||||
value = "[internal]"
|
||||
} else if (value.constructor.name === "Set") {
|
||||
} else if (constructorName(value) === "Set") {
|
||||
value = {
|
||||
__enc__: true,
|
||||
type: "set",
|
||||
data: Array.from(value).slice(0,debuglength),
|
||||
length: value.size
|
||||
}
|
||||
} else if (value.constructor.name === "Map") {
|
||||
} else if (constructorName(value) === "Map") {
|
||||
value = {
|
||||
__enc__: true,
|
||||
type: "map",
|
||||
data: Object.fromEntries(Array.from(value.entries()).slice(0,debuglength)),
|
||||
length: value.size
|
||||
}
|
||||
} else if (value.constructor.name === "RegExp") {
|
||||
} else if (constructorName(value) === "RegExp") {
|
||||
value = {
|
||||
__enc__: true,
|
||||
type: "regexp",
|
||||
@ -974,7 +985,7 @@ function encodeObject(msg,opts) {
|
||||
if (e.name) {
|
||||
errorMsg.name = e.name;
|
||||
}
|
||||
if (e.hasOwnProperty('message')) {
|
||||
if (hasOwnProperty.call(e, 'message')) {
|
||||
errorMsg.message = 'encodeObject Error: ['+e.message + '] Value: '+util.inspect(msg.msg);
|
||||
} else {
|
||||
errorMsg.message = 'encodeObject Error: ['+e.toString() + '] Value: '+util.inspect(msg.msg);
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/util",
|
||||
"version": "2.2.0",
|
||||
"version": "2.2.2",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -16,9 +16,9 @@
|
||||
],
|
||||
"dependencies": {
|
||||
"fs-extra": "10.0.0",
|
||||
"i18next": "21.6.10",
|
||||
"i18next": "21.6.11",
|
||||
"json-stringify-safe": "5.0.1",
|
||||
"jsonata": "1.8.5",
|
||||
"jsonata": "1.8.6",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"moment-timezone": "0.5.34"
|
||||
}
|
||||
|
12
packages/node_modules/node-red/package.json
vendored
12
packages/node_modules/node-red/package.json
vendored
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "node-red",
|
||||
"version": "2.2.0",
|
||||
"version": "2.2.2",
|
||||
"description": "Low-code programming for event-driven applications",
|
||||
"homepage": "http://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
@ -31,15 +31,15 @@
|
||||
"flow"
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/editor-api": "2.2.0",
|
||||
"@node-red/runtime": "2.2.0",
|
||||
"@node-red/util": "2.2.0",
|
||||
"@node-red/nodes": "2.2.0",
|
||||
"@node-red/editor-api": "2.2.2",
|
||||
"@node-red/runtime": "2.2.2",
|
||||
"@node-red/util": "2.2.2",
|
||||
"@node-red/nodes": "2.2.2",
|
||||
"basic-auth": "2.0.1",
|
||||
"bcryptjs": "2.4.3",
|
||||
"express": "4.17.2",
|
||||
"fs-extra": "10.0.0",
|
||||
"node-red-admin": "^2.2.1",
|
||||
"node-red-admin": "^2.2.3",
|
||||
"nopt": "5.0.0",
|
||||
"semver": "7.3.5"
|
||||
},
|
||||
|
@ -242,6 +242,142 @@ describe('inject node', function() {
|
||||
});
|
||||
|
||||
|
||||
it('inject name of node as environment variable by substitution ', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topnic: "t1", payload: "${NR_NODE_NAME}", payloadType: "str", wires: [["n2"]], z: "flow"},
|
||||
{id: "n2", type: "helper"}];
|
||||
helper.load(injectNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
msg.should.have.property("payload", "NAME");
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
|
||||
it('inject id of node as environment variable by substitution ', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topnic: "t1", payload: "${NR_NODE_ID}", payloadType: "str", wires: [["n2"]], z: "flow"},
|
||||
{id: "n2", type: "helper"}];
|
||||
helper.load(injectNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
msg.should.have.property("payload", "n1");
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
|
||||
it('inject path of node as environment variable by substitution ', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topnic: "t1", payload: "${NR_NODE_PATH}", payloadType: "str", wires: [["n2"]], z: "flow"},
|
||||
{id: "n2", type: "helper"}];
|
||||
helper.load(injectNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
msg.should.have.property("payload", "flow/n1");
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('inject name of flow as environment variable by substitution ', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topnic: "t1", payload: "${NR_FLOW_NAME}", payloadType: "str", wires: [["n2"]], z: "flow"},
|
||||
{id: "n2", type: "helper"},
|
||||
{id: "flow", type: "tab", label: "FLOW" },
|
||||
];
|
||||
helper.load(injectNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
msg.should.have.property("payload", "FLOW");
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
|
||||
it('inject id of flow as environment variable ', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topnic: "t1", payload: "${NR_FLOW_ID}", payloadType: "str", wires: [["n2"]], z: "flow"},
|
||||
{id: "n2", type: "helper"},
|
||||
{id: "flow", type: "tab", name: "FLOW" },
|
||||
];
|
||||
helper.load(injectNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
msg.should.have.property("payload", "flow");
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
|
||||
it('inject name of group as environment variable by substitution ', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topnic: "t1", payload: "${NR_GROUP_NAME}", payloadType: "str", wires: [["n2"]], z: "flow", g: "g0"},
|
||||
{id: "n2", type: "helper"},
|
||||
{id: "g0", type: "group", name: "GROUP" },
|
||||
];
|
||||
helper.load(injectNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
msg.should.have.property("payload", "GROUP");
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
|
||||
it('inject id of group as environment variable by substitution ', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topnic: "t1", payload: "${NR_GROUP_ID}", payloadType: "str", wires: [["n2"]], z: "flow", g: "g0"},
|
||||
{id: "n2", type: "helper"},
|
||||
{id: "g0", type: "group", name: "GROUP" },
|
||||
];
|
||||
helper.load(injectNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
msg.should.have.property("payload", "g0");
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('sets the value of flow context property', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", topic: "t1", payload: "flowValue", payloadType: "flow", wires: [["n2"]], z: "flow"},
|
||||
{id: "n2", type: "helper"}];
|
||||
|
@ -265,6 +265,38 @@ describe('debug node', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should publish an object with no-prototype-builtins', function(done) {
|
||||
const flow = [{id:"n1", type:"debug" }];
|
||||
helper.load(debugNode, flow, function() {
|
||||
const n1 = helper.getNode("n1");
|
||||
const payload = Object.create(null);
|
||||
payload.type = 'foo';
|
||||
websocket_test(function() {
|
||||
n1.emit("input", {payload: payload});
|
||||
}, function(msg) {
|
||||
JSON.parse(msg).should.eql([{
|
||||
topic:"debug",
|
||||
data:{id:"n1",msg:'{"type":"foo"}',property:"payload",format:"Object",path:"global"}
|
||||
}]);
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should publish an object with overriden hasOwnProperty', function(done) {
|
||||
const flow = [{id:"n1", type:"debug" }];
|
||||
helper.load(debugNode, flow, function() {
|
||||
const n1 = helper.getNode("n1");
|
||||
websocket_test(function() {
|
||||
n1.emit("input", {payload: {type:'foo', hasOwnProperty: null}});
|
||||
}, function(msg) {
|
||||
JSON.parse(msg).should.eql([{
|
||||
topic:"debug",
|
||||
data:{id:"n1",msg:'{"type":"foo","hasOwnProperty":null}',property:"payload",format:"Object",path:"global"}
|
||||
}]);
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should publish an array', function(done) {
|
||||
var flow = [{id:"n1", type:"debug" }];
|
||||
helper.load(debugNode, flow, function() {
|
||||
|
@ -310,6 +310,12 @@ describe('switch Node', function() {
|
||||
it('should check if payload if of type number 0', function(done) {
|
||||
genericSwitchTest("istype", "number", true, true, 0, done);
|
||||
});
|
||||
it('should check if payload if of type number NaN', function(done) {
|
||||
genericSwitchTest("istype", "number", true, false, parseInt("banana"), done);
|
||||
});
|
||||
it('should check if payload if of type number Infinity', function(done) {
|
||||
genericSwitchTest("istype", "number", true, true, 1/0, done);
|
||||
});
|
||||
it('should check if payload if of type boolean true', function(done) {
|
||||
genericSwitchTest("istype", "boolean", true, true, true, done);
|
||||
});
|
||||
|
@ -830,6 +830,24 @@ describe("@node-red/util/util", function() {
|
||||
resultJson.b.should.have.property("__enc__", true);
|
||||
resultJson.b.should.have.property("type", "undefined");
|
||||
});
|
||||
it('object with no prototype builtins', function() {
|
||||
const payload = new Object(null);
|
||||
payload.c = 3;
|
||||
var msg = { msg:{b:payload} };
|
||||
var result = util.encodeObject(msg);
|
||||
result.format.should.eql("Object");
|
||||
var resultJson = JSON.parse(result.msg);
|
||||
resultJson.should.have.property("b");
|
||||
resultJson.b.should.have.property("c", 3);
|
||||
});
|
||||
it('object with overriden hasOwnProperty', function() {
|
||||
var msg = { msg:{b:{hasOwnProperty:null}} };
|
||||
var result = util.encodeObject(msg);
|
||||
result.format.should.eql("Object");
|
||||
var resultJson = JSON.parse(result.msg);
|
||||
resultJson.should.have.property("b");
|
||||
resultJson.b.should.have.property("hasOwnProperty");
|
||||
});
|
||||
it('object with Map property', function() {
|
||||
const m = new Map();
|
||||
m.set("a",1);
|
||||
|
Loading…
Reference in New Issue
Block a user