From a6cbceed28f680f702f8a2ba1d6d81a5f25a214e Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Mon, 4 Mar 2024 16:32:31 +0000 Subject: [PATCH] Upgrade to JSONata 2.x --- package.json | 2 +- .../node_modules/@node-red/util/lib/util.js | 13 +- .../node_modules/@node-red/util/package.json | 2 +- test/unit/@node-red/util/lib/util_spec.js | 111 ++++++++++++++---- 4 files changed, 96 insertions(+), 32 deletions(-) diff --git a/package.json b/package.json index 9943d3203..173e4c929 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "is-utf8": "0.2.1", "js-yaml": "4.1.0", "json-stringify-safe": "5.0.1", - "jsonata": "1.8.6", + "jsonata": "2.0.4", "lodash.clonedeep": "^4.5.0", "media-typer": "1.1.0", "memorystore": "1.6.7", diff --git a/packages/node_modules/@node-red/util/lib/util.js b/packages/node_modules/@node-red/util/lib/util.js index ea5ffbbe3..b62c36f6b 100644 --- a/packages/node_modules/@node-red/util/lib/util.js +++ b/packages/node_modules/@node-red/util/lib/util.js @@ -769,12 +769,15 @@ function evaluateJSONataExpression(expr,msg,callback) { }); } } else { - log.warn('Deprecated API warning: Calls to RED.util.evaluateJSONataExpression must include a callback. '+ - 'This will not be optional in Node-RED 4.0. Please identify the node from the following stack '+ - 'and check for an update on npm. If none is available, please notify the node author.') - log.warn(new Error().stack) + const error = new Error('Calls to RED.util.evaluateJSONataExpression must include a callback.') + throw error } - return expr.evaluate(context, bindings, callback); + + expr.evaluate(context, bindings).then(result => { + callback(null, result) + }).catch(err => { + callback(err) + }) } /** diff --git a/packages/node_modules/@node-red/util/package.json b/packages/node_modules/@node-red/util/package.json index 7b8e87129..be92977de 100644 --- a/packages/node_modules/@node-red/util/package.json +++ b/packages/node_modules/@node-red/util/package.json @@ -18,7 +18,7 @@ "fs-extra": "11.1.1", "i18next": "21.10.0", "json-stringify-safe": "5.0.1", - "jsonata": "1.8.6", + "jsonata": "2.0.4", "lodash.clonedeep": "^4.5.0", "moment": "2.29.4", "moment-timezone": "0.5.43" diff --git a/test/unit/@node-red/util/lib/util_spec.js b/test/unit/@node-red/util/lib/util_spec.js index 3bab2739a..524b3fd41 100644 --- a/test/unit/@node-red/util/lib/util_spec.js +++ b/test/unit/@node-red/util/lib/util_spec.js @@ -441,9 +441,16 @@ describe("@node-red/util/util", function() { },{}); result.should.eql("123"); }); - it('returns jsonata result', function () { - var result = util.evaluateNodeProperty('$abs(-1)','jsonata',{},{}); - result.should.eql(1); + it('returns jsonata result', function (done) { + util.evaluateNodeProperty('$abs(-1)','jsonata',{},{}, (err, result) => { + try { + result.should.eql(1); + done() + } catch (error) { + done(error) + } + + }); }); it('returns null', function() { var result = util.evaluateNodeProperty(null,'null'); @@ -601,51 +608,105 @@ describe("@node-red/util/util", function() { }); }); describe('evaluateJSONataExpression', function() { - it('evaluates an expression', function() { + it('evaluates an expression', function(done) { var expr = util.prepareJSONataExpression('payload',{}); - var result = util.evaluateJSONataExpression(expr,{payload:"hello"}); - result.should.eql("hello"); + util.evaluateJSONataExpression(expr,{payload:"hello"}, (err, result) => { + try { + result.should.eql("hello"); + done() + } catch (error) { + done(error) + } + }); }); it('evaluates a legacyMode expression', function() { var expr = util.prepareJSONataExpression('msg.payload',{}); - var result = util.evaluateJSONataExpression(expr,{payload:"hello"}); - result.should.eql("hello"); + util.evaluateJSONataExpression(expr,{payload:"hello"}, (err, result) => { + try { + result.should.eql("hello"); + done() + } catch (error) { + done(error) + } + }); }); it('accesses flow context from an expression', function() { var expr = util.prepareJSONataExpression('$flowContext("foo")',{context:function() { return {flow:{get: function(key) { return {'foo':'bar'}[key]}}}}}); - var result = util.evaluateJSONataExpression(expr,{payload:"hello"}); - result.should.eql("bar"); + util.evaluateJSONataExpression(expr,{payload:"hello"}, (err, result) => { + try { + result.should.eql("bar"); + done() + } catch (error) { + done(error) + } + }); }); it('accesses undefined environment variable from an expression', function() { var expr = util.prepareJSONataExpression('$env("UTIL_ENV")',{}); - var result = util.evaluateJSONataExpression(expr,{}); - result.should.eql(''); - }); + util.evaluateJSONataExpression(expr,{}, (err, result) => { + try { + result.should.eql(""); + done() + } catch (error) { + done(error) + } + }); + }); it('accesses environment variable from an expression', function() { process.env.UTIL_ENV = 'foo'; var expr = util.prepareJSONataExpression('$env("UTIL_ENV")',{}); - var result = util.evaluateJSONataExpression(expr,{}); - result.should.eql('foo'); - }); + util.evaluateJSONataExpression(expr,{}, (err, result) => { + try { + result.should.eql("foo"); + done() + } catch (error) { + done(error) + } + }); + }); it('accesses moment from an expression', function() { 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'); + util.evaluateJSONataExpression(expr,{}, (err, result) => { + try { + result.should.eql("2020-07-03"); + done() + } catch (error) { + done(error) + } + }); }); it('accesses moment-timezone from an expression', function() { var expr = util.prepareJSONataExpression('$moment("2013-11-18 11:55Z").tz("Asia/Taipei").format()',{}); - var result = util.evaluateJSONataExpression(expr,{}); - result.should.eql('2013-11-18T19:55:00+08:00'); + util.evaluateJSONataExpression(expr,{}, (err, result) => { + try { + result.should.eql("2013-11-18T19:55:00+08:00"); + done() + } catch (error) { + done(error) + } + }); }); it('handles non-existant flow context variable', function() { var expr = util.prepareJSONataExpression('$flowContext("nonExistant")',{context:function() { return {flow:{get: function(key) { return {'foo':'bar'}[key]}}}}}); - var result = util.evaluateJSONataExpression(expr,{payload:"hello"}); - should.not.exist(result); - }); + util.evaluateJSONataExpression(expr,{payload:"hello"}, (err, result) => { + try { + should.not.exist(result); + done() + } catch (error) { + done(error) + } + }); + }); it('handles non-existant global context variable', function() { var expr = util.prepareJSONataExpression('$globalContext("nonExistant")',{context:function() { return {global:{get: function(key) { return {'foo':'bar'}[key]}}}}}); - var result = util.evaluateJSONataExpression(expr,{payload:"hello"}); - should.not.exist(result); + util.evaluateJSONataExpression(expr,{payload:"hello"}, (err, result) => { + try { + should.not.exist(result); + done() + } catch (error) { + done(error) + } + }); }); it('handles async flow context access', function(done) { var expr = util.prepareJSONataExpression('$flowContext("foo")',{context:function() { return {flow:{get: function(key,store,callback) { setTimeout(()=>{callback(null,{'foo':'bar'}[key])},10)}}}}});