• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

telefonicaid / iotagent-node-lib / 21668626121

04 Feb 2026 10:52AM UTC coverage: 79.378% (-0.01%) from 79.388%
21668626121

push

github

web-flow
Merge pull request #1758 from telefonicaid/task/change_log_level_add_extra_jexl_transforms

change log level at extra jexl transformation map

2047 of 2755 branches covered (74.3%)

Branch coverage included in aggregate %.

1 of 2 new or added lines in 1 file covered. (50.0%)

3950 of 4800 relevant lines covered (82.29%)

282.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

71.54
/lib/plugins/jexlParser.js
1
/*
2
 * Copyright 2016 Telefonica Investigación y Desarrollo, S.A.U
3
 *
4
 * This file is part of fiware-iotagent-lib
5
 *
6
 * fiware-iotagent-lib is free software: you can redistribute it and/or
7
 * modify it under the terms of the GNU Affero General Public License as
8
 * published by the Free Software Foundation, either version 3 of the License,
9
 * or (at your option) any later version.
10
 *
11
 * fiware-iotagent-lib is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
 * See the GNU Affero General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Affero General Public
17
 * License along with fiware-iotagent-lib.
18
 * If not, seehttp://www.gnu.org/licenses/.
19
 *
20
 * For those usages not covered by the GNU Affero General Public License
21
 * please contact with::daniel.moranjimenez@telefonica.com
22
 *
23
 * Developed by: Federico M. Facca - Martel Innovate
24
 */
25

26
/* eslint-disable consistent-return */
27
/* eslint-disable no-self-assign */
28
/* eslint-disable no-unused-vars */
29

30
const jexl = require('jexl');
1✔
31
const errors = require('../errors');
1✔
32
const logger = require('logops');
1✔
33
const fillService = require('../services/common/domain').fillService;
1✔
34
const config = require('../commonConfig');
1✔
35
const baseTranformsMap = require('../jexlTranformsMap.js').map;
1✔
36
let logContext = {
1✔
37
    op: 'IoTAgentNGSI.JEXL'
38
};
39

40
function parse(expression, context, callback) {
41
    let result;
42
    let error;
43

44
    try {
386✔
45
        result = jexl.evalSync(expression, context);
386✔
46
        //avoid undefined result
47
        result = result !== undefined ? result : null;
372✔
48
        logger.debug(logContext, 'parse expression %j over %j result %j ', expression, context, result);
372✔
49
    } catch (e) {
50
        error = new errors.InvalidExpression(expression);
14✔
51
        if (callback) {
14✔
52
            callback(error);
1✔
53
        } else {
54
            throw error;
13✔
55
        }
56
    }
57

58
    if (callback) {
373✔
59
        callback(null, result);
56✔
60
    } else {
61
        return result;
317✔
62
    }
63
}
64

65
function extractContext(attributeList) {
66
    const context = {};
4✔
67
    let value;
68

69
    for (let i = 0; i < attributeList.length; i++) {
4✔
70
        if (isNaN(attributeList[i].value)) {
21!
71
            value = attributeList[i].value;
21✔
72
        } else {
73
            let floatValue = Number.parseFloat(attributeList[i].value);
×
74
            if (!Number.isNaN(floatValue) && !Number.isInteger(floatValue)) {
×
75
                value = floatValue;
×
76
            } else if (!Number.isNaN(Number.parseInt(attributeList[i].value))) {
×
77
                value = Number.parseInt(attributeList[i].value);
×
78
            } else if (String(attributeList[i].value) === 'true') {
×
79
                value = true;
×
80
            } else if (String(attributeList[i].value) === 'false') {
×
81
                value = false;
×
82
            } else {
83
                value = attributeList[i].value;
×
84
            }
85
        }
86
        if (attributeList[i].name) {
21!
87
            context[attributeList[i].name] = value;
21✔
88
        }
89
        /*jshint camelcase: false */
90
        if (attributeList[i].object_id) {
21!
91
            context[attributeList[i].object_id] = value;
×
92
        }
93
        /*jshint camelcase: true */
94
    }
95

96
    return context;
4✔
97
}
98

99
function applyExpression(expression, context, typeInformation) {
100
    logContext = fillService(logContext, typeInformation);
330✔
101
    // Delete null values from context. Related:
102
    // https://github.com/telefonicaid/iotagent-node-lib/issues/1440
103
    // https://github.com/TomFrost/Jexl/issues/133
104
    deleteNullsAndNaN(context);
330✔
105
    const result = parse(expression, context);
330✔
106
    logger.debug(logContext, 'applyExpression %j over %j result %j ', expression, context, result);
317✔
107
    const expressionResult = result !== undefined ? result : expression;
317!
108
    return expressionResult;
317✔
109
}
110

111
function deleteNullsAndNaN(object) {
112
    for (let key in object) {
330✔
113
        if (object[key] === null || Number.isNaN(object[key])) {
3,239✔
114
            delete object[key];
165✔
115
        }
116
    }
117
}
118

119
function isTransform(identifier) {
120
    return jexl.getTransform(identifier) !== (null || undefined);
×
121
}
122

123
function contextAvailable(expression, context) {
124
    let error;
125
    try {
×
126
        jexl.evalSync(expression, context);
×
127
        return true;
×
128
    } catch (e) {
129
        logger.info(logContext, 'Wrong expression found %j over %j, it will be ignored', expression, context);
×
130
        return false;
×
131
    }
132
}
133

134
function checkTransformationMap(tranformsMap) {
135
    let error = null;
7✔
136
    let message = 'No transformations were added to JEXL Parser';
7✔
137
    let resultMap = {};
7✔
138

139
    if (typeof tranformsMap != 'object') {
7✔
140
        error = true;
1✔
141
    } else if (
6✔
142
        tranformsMap === null ||
17✔
143
        (tranformsMap && Object.keys(tranformsMap).length === 0 && tranformsMap.constructor === Object)
144
    ) {
145
        //default
146
    } else {
147
        //detecting wrong transformations
148
        let wrongList = [];
4✔
149
        for (var transformation in tranformsMap) {
4✔
150
            if (typeof tranformsMap[transformation] != 'function') {
95✔
151
                wrongList.push(transformation);
2✔
152
            } else {
153
                resultMap[transformation] = tranformsMap[transformation];
93✔
154
            }
155
        }
156
        if (wrongList.length === 0) {
4✔
157
            message = 'Transformations can be added to JEXL parser';
3✔
158
        } else {
159
            message = wrongList.toString() + ' must be a function';
1✔
160
        }
161
    }
162
    return [error, message, resultMap];
7✔
163
}
164

165
function setTransforms(configMap) {
166
    //Check provided transforms since they are provided by user
167
    //Note that in case of name conflict, baseTransformsMap would take precedence
168
    const tranformsMap = { ...configMap, ...baseTranformsMap };
2✔
169
    var [error, message, cleanTranformsMap] = checkTransformationMap(tranformsMap);
2✔
170
    if (!error) {
2!
171
        //merge baseTransformation with provided map
172
        jexl.addTransforms(cleanTranformsMap);
2✔
173
        logger.info(logContext, message);
2✔
174
    } else {
NEW
175
        logger.warn(logContext, message);
×
176
    }
177
}
178

179
exports.extractContext = extractContext;
1✔
180
exports.contextAvailable = contextAvailable;
1✔
181
exports.applyExpression = applyExpression;
1✔
182
exports.parse = parse;
1✔
183
exports.checkTransformationMap = checkTransformationMap;
1✔
184
exports.setTransforms = setTransforms;
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc