mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Allow nested msg properties in msg/flow/global expressions (#2822)
* Allow nested msg properties in msg/flow/global expressions * Remove typo in RED.utils Co-authored-by: Nick O'Leary <knolleary@users.noreply.github.com>
This commit is contained in:
85
packages/node_modules/@node-red/util/lib/util.js
vendored
85
packages/node_modules/@node-red/util/lib/util.js
vendored
@@ -189,11 +189,17 @@ function createError(code, message) {
|
||||
*
|
||||
* For example, `a["b"].c` returns `['a','b','c']`
|
||||
*
|
||||
* If `msg` is provided, any internal cross-references will be evaluated against that
|
||||
* object. Otherwise, it will return a nested set of properties
|
||||
*
|
||||
* For example, without msg set, 'a[msg.foo]' returns `['a', [ 'msg', 'foo'] ]`
|
||||
* But if msg is set to '{"foo": "bar"}', 'a[msg.foo]' returns `['a', 'bar' ]`
|
||||
*
|
||||
* @param {String} str - the property expression
|
||||
* @return {Array} the normalised expression
|
||||
* @memberof @node-red/util_util
|
||||
*/
|
||||
function normalisePropertyExpression(str) {
|
||||
function normalisePropertyExpression(str, msg, toString) {
|
||||
// This must be kept in sync with validatePropertyExpression
|
||||
// in editor/js/ui/utils.js
|
||||
|
||||
@@ -205,6 +211,7 @@ function normalisePropertyExpression(str) {
|
||||
var start = 0;
|
||||
var inString = false;
|
||||
var inBox = false;
|
||||
var boxExpression = false;
|
||||
var quoteChar;
|
||||
var v;
|
||||
for (var i=0;i<length;i++) {
|
||||
@@ -247,8 +254,54 @@ function normalisePropertyExpression(str) {
|
||||
if (i===length-1) {
|
||||
throw createError("INVALID_EXPR","Invalid property expression: unterminated expression");
|
||||
}
|
||||
// Next char is either a quote or a number
|
||||
if (!/["'\d]/.test(str[i+1])) {
|
||||
// Start of a new expression. If it starts with msg it is a nested expression
|
||||
// Need to scan ahead to find the closing bracket
|
||||
if (/^msg[.\[]/.test(str.substring(i+1))) {
|
||||
var depth = 1;
|
||||
var inLocalString = false;
|
||||
var localStringQuote;
|
||||
for (var j=i+1;j<length;j++) {
|
||||
if (/["']/.test(str[j])) {
|
||||
if (inLocalString) {
|
||||
if (str[j] === localStringQuote) {
|
||||
inLocalString = false
|
||||
}
|
||||
} else {
|
||||
inLocalString = true;
|
||||
localStringQuote = str[j]
|
||||
}
|
||||
}
|
||||
if (str[j] === '[') {
|
||||
depth++;
|
||||
} else if (str[j] === ']') {
|
||||
depth--;
|
||||
}
|
||||
if (depth === 0) {
|
||||
try {
|
||||
if (msg) {
|
||||
var crossRefProp = getMessageProperty(msg, str.substring(i+1,j));
|
||||
if (crossRefProp === undefined) {
|
||||
throw createError("INVALID_EXPR","Invalid expression: undefined reference at position "+(i+1)+" : "+str.substring(i+1,j))
|
||||
}
|
||||
parts.push(crossRefProp)
|
||||
} else {
|
||||
parts.push(normalisePropertyExpression(str.substring(i+1,j), msg));
|
||||
}
|
||||
inBox = false;
|
||||
i = j;
|
||||
start = j+1;
|
||||
break;
|
||||
} catch(err) {
|
||||
throw createError("INVALID_EXPR","Invalid expression started at position "+(i+1))
|
||||
}
|
||||
}
|
||||
}
|
||||
if (depth > 0) {
|
||||
throw createError("INVALID_EXPR","Invalid property expression: unmatched '[' at position "+i);
|
||||
}
|
||||
continue;
|
||||
} else if (!/["'\d]/.test(str[i+1])) {
|
||||
// Next char is either a quote or a number
|
||||
throw createError("INVALID_EXPR","Invalid property expression: unexpected "+str[i+1]+" at position "+(i+1));
|
||||
}
|
||||
start = i+1;
|
||||
@@ -294,6 +347,23 @@ function normalisePropertyExpression(str) {
|
||||
if (start < length) {
|
||||
parts.push(str.substring(start));
|
||||
}
|
||||
|
||||
if (toString) {
|
||||
var result = parts.shift();
|
||||
while(parts.length > 0) {
|
||||
var p = parts.shift();
|
||||
if (typeof p === 'string') {
|
||||
if (/"/.test(p)) {
|
||||
p = "'"+p+"'";
|
||||
} else {
|
||||
p = '"'+p+'"';
|
||||
}
|
||||
}
|
||||
result = result+"["+p+"]";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return parts;
|
||||
}
|
||||
|
||||
@@ -340,8 +410,7 @@ function getMessageProperty(msg,expr) {
|
||||
*/
|
||||
function getObjectProperty(msg,expr) {
|
||||
var result = null;
|
||||
var msgPropParts = normalisePropertyExpression(expr);
|
||||
var m;
|
||||
var msgPropParts = normalisePropertyExpression(expr,msg);
|
||||
msgPropParts.reduce(function(obj, key) {
|
||||
result = (typeof obj[key] !== "undefined" ? obj[key] : undefined);
|
||||
return result;
|
||||
@@ -381,7 +450,7 @@ function setObjectProperty(msg,prop,value,createMissing) {
|
||||
if (typeof createMissing === 'undefined') {
|
||||
createMissing = (typeof value !== 'undefined');
|
||||
}
|
||||
var msgPropParts = normalisePropertyExpression(prop);
|
||||
var msgPropParts = normalisePropertyExpression(prop, msg);
|
||||
var depth = 0;
|
||||
var length = msgPropParts.length;
|
||||
var obj = msg;
|
||||
@@ -553,6 +622,10 @@ function evaluateNodeProperty(value, type, node, msg, callback) {
|
||||
}
|
||||
} else if ((type === 'flow' || type === 'global') && node) {
|
||||
var contextKey = parseContextStore(value);
|
||||
if (/\[msg/.test(contextKey.key)) {
|
||||
// The key has a nest msg. reference to evaluate first
|
||||
contextKey.key = normalisePropertyExpression(contextKey.key, msg, true)
|
||||
}
|
||||
result = node.context()[type].get(contextKey.key,contextKey.store,callback);
|
||||
if (callback) {
|
||||
return;
|
||||
|
Reference in New Issue
Block a user