diff --git a/packages/node_modules/@node-red/nodes/core/function/15-change.js b/packages/node_modules/@node-red/nodes/core/function/15-change.js index b1bc881a5..0eb18eff3 100644 --- a/packages/node_modules/@node-red/nodes/core/function/15-change.js +++ b/packages/node_modules/@node-red/nodes/core/function/15-change.js @@ -216,7 +216,7 @@ module.exports = function(RED) { RED.util.setMessageProperty(msg,property,undefined); } else if (rule.t === 'set') { if (!RED.util.setMessageProperty(msg,property,value)) { - node.warn(RED._("change.errors.no-override",{prop:property})); + node.warn(RED._("change.errors.no-override",{property:property})); } } else if (rule.t === 'change') { current = RED.util.getMessageProperty(msg,property); diff --git a/packages/node_modules/@node-red/nodes/locales/en-US/messages.json b/packages/node_modules/@node-red/nodes/locales/en-US/messages.json index eea9b1b59..db3da0ff8 100755 --- a/packages/node_modules/@node-red/nodes/locales/en-US/messages.json +++ b/packages/node_modules/@node-red/nodes/locales/en-US/messages.json @@ -672,7 +672,7 @@ "invalid-from": "Invalid 'from' property: __error__", "invalid-json": "Invalid 'to' JSON property", "invalid-expr": "Invalid JSONata expression: __error__", - "no-override": "Can't overwrite primitive type with object __prop__." + "no-override": "Cannot set property of non-object type: __property__" } }, "range": { diff --git a/packages/node_modules/@node-red/util/lib/util.js b/packages/node_modules/@node-red/util/lib/util.js index e5e270723..f69ca890a 100644 --- a/packages/node_modules/@node-red/util/lib/util.js +++ b/packages/node_modules/@node-red/util/lib/util.js @@ -371,14 +371,14 @@ function setObjectProperty(msg,prop,value,createMissing) { var length = msgPropParts.length; var obj = msg; var key; - var flag = true; for (var i=0;i 1 && ((typeof obj[key] !== "object" && typeof obj[key] !== "function") || obj[key] === null)) { - //console.log("Can't override primitive type with object."); - flag = false; + // Break out early as we cannot create a property beneath + // this type of value + return false; } obj = obj[key]; } else if (createMissing) { @@ -389,7 +389,7 @@ function setObjectProperty(msg,prop,value,createMissing) { } obj = obj[key]; } else { - return null; + return false; } } else if (typeof key === 'number') { // obj is an array @@ -402,7 +402,7 @@ function setObjectProperty(msg,prop,value,createMissing) { } obj = obj[key]; } else { - return null; + return false; } } else { obj = obj[key]; @@ -420,11 +420,11 @@ function setObjectProperty(msg,prop,value,createMissing) { if (typeof obj === "object" && obj !== null) { obj[key] = value; } else { - //console.log("Can't override primitive type with object."); - flag = false; - } + // Cannot set a property of a non-object/array + return false; + } } - return flag; + return true; } /*! diff --git a/test/unit/@node-red/util/lib/util_spec.js b/test/unit/@node-red/util/lib/util_spec.js index f8c77d68a..aa46bc0e1 100644 --- a/test/unit/@node-red/util/lib/util_spec.js +++ b/test/unit/@node-red/util/lib/util_spec.js @@ -189,7 +189,8 @@ describe("@node-red/util/util", function() { // setMessageProperty strips off `msg.` prefixes. // setObjectProperty does not var obj = {}; - util.setObjectProperty(obj,"msg.a","bar"); + var result = util.setObjectProperty(obj,"msg.a","bar"); + result.should.be.true(); obj.should.have.property("msg"); obj.msg.should.have.property("a","bar"); }) @@ -197,59 +198,111 @@ describe("@node-red/util/util", function() { describe('setMessageProperty', function() { it('sets a property', function() { var msg = {a:"foo"}; - util.setMessageProperty(msg,"msg.a","bar"); + var result = util.setMessageProperty(msg,"msg.a","bar"); + result.should.be.true(); msg.a.should.eql('bar'); }); it('sets a deep level property', function() { var msg = {a:{b:{c:"foo"}}}; - util.setMessageProperty(msg,"msg.a.b.c","bar"); + var result = util.setMessageProperty(msg,"msg.a.b.c","bar"); + result.should.be.true(); msg.a.b.c.should.eql('bar'); }); it('creates missing parent properties by default', function() { var msg = {a:{}}; - util.setMessageProperty(msg,"msg.a.b.c","bar"); + var result = util.setMessageProperty(msg,"msg.a.b.c","bar"); + result.should.be.true(); msg.a.b.c.should.eql('bar'); }) it('does not create missing parent properties', function() { var msg = {a:{}}; - util.setMessageProperty(msg,"msg.a.b.c","bar",false); + var result = util.setMessageProperty(msg,"msg.a.b.c","bar",false); + result.should.be.false(); should.not.exist(msg.a.b); }) - it('does not create missing parent properties with array', function () { + it('does not create missing parent properties of array', function () { var msg = {a:{}}; - util.setMessageProperty(msg, "msg.a.b[1].c", "bar", false); + var result = util.setMessageProperty(msg, "msg.a.b[1].c", "bar", false); + result.should.be.false(); should.not.exist(msg.a.b); }) + + it('does not create missing parent properties of string', function() { + var msg = {a:"foo"}; + var result = util.setMessageProperty(msg, "msg.a.b.c", "bar", false); + result.should.be.false(); + should.not.exist(msg.a.b); + }) + it('does not set property of existing string property', function() { + var msg = {a:"foo"}; + var result = util.setMessageProperty(msg, "msg.a.b", "bar", false); + result.should.be.false(); + should.not.exist(msg.a.b); + }) + + it('does not set property of existing number property', function() { + var msg = {a:123}; + var result = util.setMessageProperty(msg, "msg.a.b", "bar", false); + result.should.be.false(); + should.not.exist(msg.a.b); + }) + it('does not create missing parent properties of number', function() { + var msg = {a:123}; + var result = util.setMessageProperty(msg, "msg.a.b.c", "bar", false); + result.should.be.false(); + should.not.exist(msg.a.b); + }) + + it('does not set property of existing boolean property', function() { + var msg = {a:true}; + var result = util.setMessageProperty(msg, "msg.a.b", "bar", false); + result.should.be.false(); + should.not.exist(msg.a.b); + }) + it('does not create missing parent properties of boolean', function() { + var msg = {a:true}; + var result = util.setMessageProperty(msg, "msg.a.b.c", "bar", false); + result.should.be.false(); + should.not.exist(msg.a.b); + }) + + it('deletes property if value is undefined', function() { var msg = {a:{b:{c:"foo"}}}; - util.setMessageProperty(msg,"msg.a.b.c",undefined); + var result = util.setMessageProperty(msg,"msg.a.b.c",undefined); + result.should.be.true(); should.not.exist(msg.a.b.c); }) it('does not create missing parent properties if value is undefined', function() { var msg = {a:{}}; - util.setMessageProperty(msg,"msg.a.b.c",undefined); + var result = util.setMessageProperty(msg,"msg.a.b.c",undefined); + result.should.be.false(); should.not.exist(msg.a.b); }); it('sets a property with array syntax', function() { var msg = {a:{b:["foo",{c:["",""]}]}}; - util.setMessageProperty(msg,"msg.a.b[1].c[1]","bar"); + var result = util.setMessageProperty(msg,"msg.a.b[1].c[1]","bar"); + result.should.be.true(); msg.a.b[1].c[1].should.eql('bar'); }); it('creates missing array elements - final property', function() { var msg = {a:[]}; - util.setMessageProperty(msg,"msg.a[2]","bar"); + var result = util.setMessageProperty(msg,"msg.a[2]","bar"); + result.should.be.true(); msg.a.should.have.length(3); msg.a[2].should.eql("bar"); }); it('creates missing array elements - mid property', function() { var msg = {}; - util.setMessageProperty(msg,"msg.a[2].b","bar"); + var result = util.setMessageProperty(msg,"msg.a[2].b","bar"); + result.should.be.true(); msg.a.should.have.length(3); msg.a[2].b.should.eql("bar"); }); it('creates missing array elements - multi-arrays', function() { var msg = {}; - util.setMessageProperty(msg,"msg.a[2][2]","bar"); + var result = util.setMessageProperty(msg,"msg.a[2][2]","bar"); + result.should.be.true(); msg.a.should.have.length(3); msg.a.should.be.instanceOf(Array); msg.a[2].should.have.length(3); @@ -258,19 +311,22 @@ describe("@node-red/util/util", function() { }); it('does not create missing array elements - mid property', function () { var msg = {a:[]}; - util.setMessageProperty(msg, "msg.a[1][1]", "bar", false); + var result = util.setMessageProperty(msg, "msg.a[1][1]", "bar", false); + result.should.be.false(); msg.a.should.empty(); }); it('does not create missing array elements - final property', function() { var msg = {a:{}}; - util.setMessageProperty(msg,"msg.a.b[2]","bar",false); + var result = util.setMessageProperty(msg,"msg.a.b[2]","bar",false); + result.should.be.false(); should.not.exist(msg.a.b); // check it has not been misinterpreted msg.a.should.not.have.property("b[2]"); }); it('deletes property inside array if value is undefined', function() { var msg = {a:[1,2,3]}; - util.setMessageProperty(msg,"msg.a[1]",undefined); + var result = util.setMessageProperty(msg,"msg.a[1]",undefined); + result.should.be.true(); msg.a.should.have.length(2); msg.a[0].should.eql(1); msg.a[1].should.eql(3); @@ -511,7 +567,7 @@ describe("@node-red/util/util", function() { result.should.eql('foo'); }); it('accesses moment from an expression', function() { - var expr = util.prepareJSONataExpression('$moment("2020-05-27", "YYYY-MM-DD").add("days", 7).add("months", 1).format("YYYY-MM-DD")',{}); + var expr = util.prepareJSONataExpression('$moment("2020-05-27", "YYYY-MM-DD").add(7, "days").add(1, "months").format("YYYY-MM-DD")',{}); var result = util.evaluateJSONataExpression(expr,{}); result.should.eql('2020-07-03'); });