1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Implement node property typing

See https://github.com/node-red/designs/pull/37
This commit is contained in:
Nick O'Leary 2021-01-08 14:19:12 +00:00
parent 7913b3cbc2
commit ea2e3f25d8
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
10 changed files with 145 additions and 53 deletions

View File

@ -343,17 +343,29 @@ RED.history = (function() {
if (ev.changes.hasOwnProperty(i)) { if (ev.changes.hasOwnProperty(i)) {
inverseEv.changes[i] = ev.node[i]; inverseEv.changes[i] = ev.node[i];
if (ev.node._def.defaults && ev.node._def.defaults[i] && ev.node._def.defaults[i].type) { if (ev.node._def.defaults && ev.node._def.defaults[i] && ev.node._def.defaults[i].type) {
// This is a config node property // This property is a reference to another node or nodes.
var currentConfigNode = RED.nodes.node(ev.node[i]); var nodeList = ev.node[i];
if (currentConfigNode) { if (!Array.isArray(nodeList)) {
nodeList = [nodeList];
}
nodeList.forEach(function(id) {
var currentConfigNode = RED.nodes.node(id);
if (currentConfigNode && currentConfigNode._def.category === "config") {
currentConfigNode.users.splice(currentConfigNode.users.indexOf(ev.node),1); currentConfigNode.users.splice(currentConfigNode.users.indexOf(ev.node),1);
RED.events.emit("nodes:change",currentConfigNode); RED.events.emit("nodes:change",currentConfigNode);
} }
var newConfigNode = RED.nodes.node(ev.changes[i]); });
if (newConfigNode) { nodeList = ev.changes[i];
if (!Array.isArray(nodeList)) {
nodeList = [nodeList];
}
nodeList.forEach(function(id) {
var newConfigNode = RED.nodes.node(id);
if (newConfigNode && newConfigNode._def.category === "config") {
newConfigNode.users.push(ev.node); newConfigNode.users.push(ev.node);
RED.events.emit("nodes:change",newConfigNode); RED.events.emit("nodes:change",newConfigNode);
} }
});
} }
ev.node[i] = ev.changes[i]; ev.node[i] = ev.changes[i];
} }

View File

@ -164,6 +164,21 @@ RED.nodes = (function() {
// TODO: too tightly coupled into palette UI // TODO: too tightly coupled into palette UI
} }
if (def.defaults) {
for (var d in def.defaults) {
if (def.defaults.hasOwnProperty(d)) {
if (def.defaults[d].type) {
try {
def.defaults[d]._type = parseNodePropertyTypeString(def.defaults[d].type)
} catch(err) {
console.warn(err);
}
}
}
}
}
RED.events.emit("registry:node-type-added",nt); RED.events.emit("registry:node-type-added",nt);
}, },
removeNodeType: function(nt) { removeNodeType: function(nt) {
@ -193,6 +208,59 @@ RED.nodes = (function() {
return (1+Math.random()*4294967295).toString(16); return (1+Math.random()*4294967295).toString(16);
} }
function parseNodePropertyTypeString(typeString) {
typeString = typeString.trim();
var c;
var pos = 0;
var isArray = /\[\]$/.test(typeString);
if (isArray) {
typeString = typeString.substring(0,typeString.length-2);
}
var l = typeString.length;
var inBrackets = false;
var inToken = false;
var currentToken = "";
var types = [];
while (pos < l) {
c = typeString[pos];
if (inToken) {
if (c === "|") {
types.push(currentToken.trim())
currentToken = "";
inToken = false;
} else if (c === ")") {
types.push(currentToken.trim())
currentToken = "";
inBrackets = false;
inToken = false;
} else {
currentToken += c;
}
} else {
if (c === "(") {
if (inBrackets) {
throw new Error("Invalid character '"+c+"' at position "+pos)
}
inBrackets = true;
} else if (c !== " ") {
inToken = true;
currentToken = c;
}
}
pos++;
}
currentToken = currentToken.trim();
if (currentToken.length > 0) {
types.push(currentToken)
}
return {
types: types,
array: isArray
}
}
function addNode(n) { function addNode(n) {
if (n.type.indexOf("subflow") !== 0) { if (n.type.indexOf("subflow") !== 0) {
n["_"] = n._def._; n["_"] = n._def._;
@ -787,16 +855,29 @@ RED.nodes = (function() {
if (node.type !== "subflow") { if (node.type !== "subflow") {
var convertedNode = RED.nodes.convertNode(node); var convertedNode = RED.nodes.convertNode(node);
for (var d in node._def.defaults) { for (var d in node._def.defaults) {
if (node._def.defaults[d].type && node[d] in configNodes) { if (node._def.defaults[d].type) {
var confNode = configNodes[node[d]]; var nodeList = node[d];
var exportable = registry.getNodeType(node._def.defaults[d].type).exportable; if (!Array.isArray(nodeList)) {
if ((exportable == null || exportable)) { nodeList = [nodeList];
if (!(node[d] in exportedConfigNodes)) {
exportedConfigNodes[node[d]] = true;
set.push(confNode);
} }
nodeList = nodeList.filter(function(id) {
if (id in configNodes) {
var confNode = configNodes[id];
if (confNode._def.exportable !== false) {
if (!(id in exportedConfigNodes)) {
exportedConfigNodes[id] = true;
set.push(confNode);
return true;
}
}
return false;
}
return true;
})
if (nodeList.length === 0) {
convertedNode[d] = Array.isArray(node[d])?[]:""
} else { } else {
convertedNode[d] = ""; convertedNode[d] = Array.isArray(node[d])?nodeList:nodeList[0]
} }
} }
} }
@ -1587,15 +1668,6 @@ RED.nodes = (function() {
} }
} }
} }
// TODO: make this a part of the node definition so it doesn't have to
// be hardcoded here
var nodeTypeArrayReferences = {
"catch":"scope",
"status":"scope",
"complete": "scope",
"link in":"links",
"link out":"links"
}
// Remap all wires and config node references // Remap all wires and config node references
for (i=0;i<new_nodes.length;i++) { for (i=0;i<new_nodes.length;i++) {
@ -1624,19 +1696,24 @@ RED.nodes = (function() {
} }
for (var d3 in n._def.defaults) { for (var d3 in n._def.defaults) {
if (n._def.defaults.hasOwnProperty(d3)) { if (n._def.defaults.hasOwnProperty(d3)) {
if (n._def.defaults[d3].type && node_map[n[d3]]) { if (n._def.defaults[d3].type) {
configNode = node_map[n[d3]]; var nodeList = n[d3];
n[d3] = configNode.id; if (!Array.isArray(nodeList)) {
if (configNode.users.indexOf(n) === -1) { nodeList = [nodeList];
configNode.users.push(n);
} }
} else if (nodeTypeArrayReferences.hasOwnProperty(n.type) && nodeTypeArrayReferences[n.type] === d3 && n[d3] !== undefined && n[d3] !== null) { nodeList = nodeList.map(function(id) {
for (var j = 0;j<n[d3].length;j++) { var node = node_map[id];
if (node_map[n[d3][j]]) { if (node) {
n[d3][j] = node_map[n[d3][j]].id; if (node._def.category === 'config') {
if (node.users.indexOf(n) === -1) {
node.users.push(n);
} }
} }
return node.id;
}
return id;
})
n[d3] = Array.isArray(n[d3])?nodeList:nodeList[0];
} }
} }
} }

View File

@ -186,6 +186,7 @@ var RED = (function() {
RED.workspaces.show(currentHash.substring(6)); RED.workspaces.show(currentHash.substring(6));
} }
} catch(err) { } catch(err) {
console.warn(err);
RED.notify( RED.notify(
RED._("event.importError", {message: err.message}), RED._("event.importError", {message: err.message}),
{ {

View File

@ -442,8 +442,9 @@ RED.editor = (function() {
for (var d in definition.defaults) { for (var d in definition.defaults) {
if (definition.defaults.hasOwnProperty(d)) { if (definition.defaults.hasOwnProperty(d)) {
if (definition.defaults[d].type) { if (definition.defaults[d].type) {
if (!definition.defaults[d]._type.array) {
var configTypeDef = RED.nodes.getType(definition.defaults[d].type); var configTypeDef = RED.nodes.getType(definition.defaults[d].type);
if (configTypeDef) { if (configTypeDef && configTypeDef.category === 'config') {
if (configTypeDef.exclusive) { if (configTypeDef.exclusive) {
prepareConfigNodeButton(node,d,definition.defaults[d].type,prefix); prepareConfigNodeButton(node,d,definition.defaults[d].type,prefix);
} else { } else {
@ -453,6 +454,7 @@ RED.editor = (function() {
console.log("Unknown type:", definition.defaults[d].type); console.log("Unknown type:", definition.defaults[d].type);
preparePropertyEditor(node,d,prefix,definition.defaults); preparePropertyEditor(node,d,prefix,definition.defaults);
} }
}
} else { } else {
preparePropertyEditor(node,d,prefix,definition.defaults); preparePropertyEditor(node,d,prefix,definition.defaults);
} }

View File

@ -338,7 +338,7 @@ RED.sidebar.info = (function() {
count++; count++;
propRow = $('<tr class="red-ui-help-info-property-row'+(expandedSections.property?"":" hide")+'"><td></td><td></td></tr>').appendTo(tableBody); propRow = $('<tr class="red-ui-help-info-property-row'+(expandedSections.property?"":" hide")+'"><td></td><td></td></tr>').appendTo(tableBody);
$(propRow.children()[0]).text(n); $(propRow.children()[0]).text(n);
if (defaults[n].type) { if (defaults[n].type && !defaults[n]._type.array) {
var configNode = RED.nodes.node(val); var configNode = RED.nodes.node(val);
if (!configNode) { if (!configNode) {
RED.utils.createObjectElement(undefined).appendTo(propRow.children()[1]); RED.utils.createObjectElement(undefined).appendTo(propRow.children()[1]);

View File

@ -131,10 +131,10 @@
width: 120px; width: 120px;
background-size: contain; background-size: contain;
position: relative; position: relative;
&:not(.red-ui-palette-node-config):first-child { &:not(.red-ui-palette-node-config):not(.red-ui-palette-node-small):first-child {
margin-top: 15px; margin-top: 15px;
} }
&:not(.red-ui-palette-node-config):last-child { &:not(.red-ui-palette-node-config):not(.red-ui-palette-node-small):first-child {
margin-bottom: 15px; margin-bottom: 15px;
} }
} }

View File

@ -18,7 +18,7 @@
color:"#c0edc0", color:"#c0edc0",
defaults: { defaults: {
name: {value:""}, name: {value:""},
scope: {value:[]}, scope: {value:[], type:"*[]"},
uncaught: {value:false} uncaught: {value:false}
}, },
inputs:0, inputs:0,

View File

@ -30,7 +30,7 @@
color:"#e49191", color:"#e49191",
defaults: { defaults: {
name: {value:""}, name: {value:""},
scope: {value:null}, scope: {value:null, type:"*[]"},
uncaught: {value:false} uncaught: {value:false}
}, },
inputs:0, inputs:0,

View File

@ -26,7 +26,7 @@
color:"#94c1d0", color:"#94c1d0",
defaults: { defaults: {
name: {value:""}, name: {value:""},
scope: {value:null} scope: {value:null, type:"*[]"}
}, },
inputs:0, inputs:0,
outputs:1, outputs:1,

View File

@ -187,7 +187,7 @@
color:"#ddd",//"#87D8CF", color:"#ddd",//"#87D8CF",
defaults: { defaults: {
name: {value:""}, name: {value:""},
links: { value: [] } links: { value: [], type:"link out[]" }
}, },
inputs:0, inputs:0,
outputs:1, outputs:1,
@ -216,7 +216,7 @@
color:"#ddd",//"#87D8CF", color:"#ddd",//"#87D8CF",
defaults: { defaults: {
name: {value:""}, name: {value:""},
links: { value: []} links: { value: [], type:"link in[]"}
}, },
align:"right", align:"right",
inputs:1, inputs:1,