iotagent-node-lib
Version:
IoT Agent library to interface with NGSI Context Broker
183 lines (166 loc) • 6.17 kB
JavaScript
/*
* Copyright 2016 Telefonica Investigación y Desarrollo, S.A.U
*
* This file is part of fiware-iotagent-lib
*
* fiware-iotagent-lib is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* fiware-iotagent-lib is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with fiware-iotagent-lib.
* If not, seehttp://www.gnu.org/licenses/.
*
* For those usages not covered by the GNU Affero General Public License
* please contact with::daniel.moranjimenez@telefonica.com
*
* Developed by: Federico M. Facca - Martel Innovate
*/
/* eslint-disable consistent-return */
/* eslint-disable no-self-assign */
/* eslint-disable no-unused-vars */
const jexl = require('jexl');
const errors = require('../errors');
const logger = require('logops');
const fillService = require('../services/common/domain').fillService;
const config = require('../commonConfig');
const baseTranformsMap = require('../jexlTranformsMap.js').map;
let logContext = {
op: 'IoTAgentNGSI.JEXL'
};
function parse(expression, context, callback) {
let result;
let error;
try {
result = jexl.evalSync(expression, context);
//avoid undefined result
result = result !== undefined ? result : null;
logger.debug(logContext, 'parse expression %j over %j result %j ', expression, context, result);
} catch (e) {
error = new errors.InvalidExpression(expression);
if (callback) {
callback(error);
} else {
throw error;
}
}
if (callback) {
callback(null, result);
} else {
return result;
}
}
function extractContext(attributeList) {
const context = {};
let value;
for (let i = 0; i < attributeList.length; i++) {
if (isNaN(attributeList[i].value)) {
value = attributeList[i].value;
} else {
let floatValue = Number.parseFloat(attributeList[i].value);
if (!Number.isNaN(floatValue) && !Number.isInteger(floatValue)) {
value = floatValue;
} else if (!Number.isNaN(Number.parseInt(attributeList[i].value))) {
value = Number.parseInt(attributeList[i].value);
} else if (String(attributeList[i].value) === 'true') {
value = true;
} else if (String(attributeList[i].value) === 'false') {
value = false;
} else {
value = attributeList[i].value;
}
}
if (attributeList[i].name) {
context[attributeList[i].name] = value;
}
/*jshint camelcase: false */
if (attributeList[i].object_id) {
context[attributeList[i].object_id] = value;
}
/*jshint camelcase: true */
}
return context;
}
function applyExpression(expression, context, typeInformation) {
logContext = fillService(logContext, typeInformation);
// Delete null values from context. Related:
// https://github.com/telefonicaid/iotagent-node-lib/issues/1440
// https://github.com/TomFrost/Jexl/issues/133
deleteNullsAndNaN(context);
const result = parse(expression, context);
logger.debug(logContext, 'applyExpression %j over %j result %j ', expression, context, result);
const expressionResult = result !== undefined ? result : expression;
return expressionResult;
}
function deleteNullsAndNaN(object) {
for (let key in object) {
if (object[key] === null || Number.isNaN(object[key])) {
delete object[key];
}
}
}
function isTransform(identifier) {
return jexl.getTransform(identifier) !== (null || undefined);
}
function contextAvailable(expression, context) {
let error;
try {
jexl.evalSync(expression, context);
return true;
} catch (e) {
logger.info(logContext, 'Wrong expression found %j over %j, it will be ignored', expression, context);
return false;
}
}
function checkTransformationMap(tranformsMap) {
let error = null;
let message = 'No trasformations were added to JEXL Parser';
let resultMap = {};
if (typeof tranformsMap != 'object') {
error = true;
} else if (
tranformsMap === null ||
(tranformsMap && Object.keys(tranformsMap).length === 0 && tranformsMap.constructor === Object)
) {
//default
} else {
//detecting wrong transformations
let wrongList = [];
for (var transformation in tranformsMap) {
if (typeof tranformsMap[transformation] != 'function') {
wrongList.push(transformation);
} else {
resultMap[transformation] = tranformsMap[transformation];
}
}
if (wrongList.length === 0) {
message = 'Trasformations can be added to JEXL parser';
} else {
message = wrongList.toString() + ' must be a function';
}
}
return [error, message, resultMap];
}
function setTransforms(configMap) {
//Check provided transforms since they are provided by user
//Note that in case of name conflict, baseTransformsMap would take precedence
const tranformsMap = { ...configMap, ...baseTranformsMap };
var [error, message, cleanTranformsMap] = checkTransformationMap(tranformsMap);
if (!error) {
//merge baseTransformation with provided map
jexl.addTransforms(cleanTranformsMap);
}
logger.info(logContext, message);
}
exports.extractContext = extractContext;
exports.contextAvailable = contextAvailable;
exports.applyExpression = applyExpression;
exports.parse = parse;
exports.checkTransformationMap = checkTransformationMap;
exports.setTransforms = setTransforms;