dmn-eval-js-es5
Version:
Evaluation of DMN 1.1 decision tables, limited to S-FEEL (Simple Friendly Enough Expression Language), es5 browser compatible
437 lines (416 loc) • 20 kB
JavaScript
'use strict';
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
/*
*
* ©2016-2017 EdgeVerve Systems Limited (a fully owned Infosys subsidiary),
* Bangalore, India. All Rights Reserved.
*
*/
var Big = require('big.js');
var _ = require('lodash');
var _require = require('./value'),
valueT = _require.valueT,
valueInverseT = _require.valueInverseT,
valueDT = _require.valueDT,
valueInverseDT = _require.valueInverseDT,
valueDTD = _require.valueDTD,
valueInverseDTD = _require.valueInverseDTD,
valueYMD = _require.valueYMD,
valueInverseYMD = _require.valueInverseYMD;
var _require2 = require('../built-in-functions'),
date = _require2.date,
time = _require2.time,
dateandtime = _require2['date and time'];
/*
dateTimeComponent contains the list of properties required for comparison.
property collection is in the order of priority of check
priority order is essential for inequality check
for inequality check the property appearing first in the list needs to be checked first
before moving on to the next properties in the list
*/
var dateTimeComponent = {
time: ['hour', 'minute', 'second', 'time offset'],
date: ['year', 'month', 'day'],
dateandtime: ['year', 'month', 'day', 'hour', 'minute', 'second', 'time offset']
};
var presence = function presence() {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return args.reduce(function (acc, arg) {
return acc && (arg || arg === 0);
}, true);
};
var typeEq = function typeEq() {
for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
return args.reduce(function (acc, arg) {
return acc && (typeof arg === 'undefined' ? 'undefined' : _typeof(arg)) === acc ? typeof arg === 'undefined' ? 'undefined' : _typeof(arg) : false;
}, _typeof(args[0]));
}; // eslint-disable-line
var presencetypeEq = function presencetypeEq() {
return presence.apply(undefined, arguments) && typeEq.apply(undefined, arguments) && true;
};
var anyUndefined = function anyUndefined(x, y) {
return x === undefined || y === undefined;
};
var getUndefined = function getUndefined(x, y) {
if (x === undefined) {
return x;
} else if (y === undefined) {
return y;
}
throw new Error('Neither x nor y is undefined');
};
var operatorMap = {
'<': _.curry(function (x, y) {
if (anyUndefined(x, y)) {
return getUndefined(x, y);
}
try {
if (presencetypeEq(x, y)) {
if (typeof x === 'number' && typeof y === 'number') {
return Big(x).lt(y);
} else if (typeof x === 'string' && typeof y === 'string') {
return x < y;
} else if (x instanceof Date && y instanceof Date) {
return x < y;
} else if (x.isDate && y.isDate) {
var checkLt = checkInequality('<', '>'); // eslint-disable-line no-use-before-define
return checkLt(x, y, dateTimeComponent.date) > 0;
} else if (x.isDateTime && y.isDateTime) {
return valueDT(x) < valueDT(y);
} else if (x.isTime && y.isTime) {
// make y with the same offset as x before comparison
var xOffset = x['time offset'];
y.utcOffset(xOffset);
return valueT(x) < valueT(y);
} else if (x.isDtd && y.isDtd) {
return valueDTD(x) < valueDTD(y);
} else if (x.isYmd && y.isYmd) {
return valueYMD(x) < valueYMD(y);
}
throw new Error((x.type || (typeof x === 'undefined' ? 'undefined' : _typeof(x))) + ' < ' + (y.type || (typeof y === 'undefined' ? 'undefined' : _typeof(y))) + ' : operation unsupported for one or more operands types');
}
throw new Error(((typeof x === 'undefined' ? 'undefined' : _typeof(x)) && x) + ' < ' + ((typeof y === 'undefined' ? 'undefined' : _typeof(y)) && y) + ' : operation invalid for one or more operands types');
} catch (err) {
throw err;
}
}),
'<=': _.curry(function (x, y) {
if (anyUndefined(x, y)) {
return getUndefined(x, y);
}
try {
if (presencetypeEq(x, y)) {
if (typeof x === 'number' && typeof y === 'number') {
return Big(x).lte(y);
} else if (typeof x === 'string' && typeof y === 'string') {
return x <= y;
} else if (x instanceof Date && y instanceof Date) {
return x <= y;
} else if (x.isDate && y.isDate) {
var checkLt = checkInequality('<', '>'); // eslint-disable-line no-use-before-define
return checkLt(x, y, dateTimeComponent.date) >= 0; // eslint-disable-line no-use-before-define
} else if (x.isDateTime && y.isDateTime) {
return valueDT(x) <= valueDT(y);
} else if (x.isTime && y.isTime) {
// make y with the same offset as x before comparison
var xOffset = x['time offset'];
y.utcOffset(xOffset);
return valueT(x) <= valueT(y);
} else if (x.isDtd && y.isDtd) {
return valueDTD(x) <= valueDTD(y);
} else if (x.isYmd && y.isYmd) {
return valueYMD(x) <= valueYMD(y);
}
throw new Error((x.type || (typeof x === 'undefined' ? 'undefined' : _typeof(x))) + ' <= ' + (y.type || (typeof y === 'undefined' ? 'undefined' : _typeof(y))) + ' : operation unsupported for one or more operands types');
}
throw new Error(((typeof x === 'undefined' ? 'undefined' : _typeof(x)) && x) + ' <= ' + ((typeof y === 'undefined' ? 'undefined' : _typeof(y)) && y) + ' : operation invalid for one or more operands types');
} catch (err) {
throw err;
}
}),
'>': _.curry(function (x, y) {
if (anyUndefined(x, y)) {
return getUndefined(x, y);
}
try {
if (presencetypeEq(x, y)) {
if (typeof x === 'number' && typeof y === 'number') {
return Big(x).gt(y);
} else if (typeof x === 'string' && typeof y === 'string') {
return x > y;
} else if (x instanceof Date && y instanceof Date) {
return x > y;
} else if (x.isDate && y.isDate) {
var checkGt = checkInequality('>', '<'); // eslint-disable-line no-use-before-define
return checkGt(x, y, dateTimeComponent.date) > 0;
} else if (x.isDateTime && y.isDateTime) {
return valueDT(x) > valueDT(y);
} else if (x.isTime && y.isTime) {
// make y with the same offset as x before comparison
var xOffset = x['time offset'];
y.utcOffset(xOffset);
return valueT(x) > valueT(y);
} else if (x.isDtd && y.isDtd) {
return valueDTD(x) > valueDTD(y);
} else if (x.isYmd && y.isYmd) {
return valueYMD(x) > valueYMD(y);
}
throw new Error((x.type || (typeof x === 'undefined' ? 'undefined' : _typeof(x))) + ' > ' + (y.type || (typeof y === 'undefined' ? 'undefined' : _typeof(y))) + ' : operation unsupported for one or more operands types');
}
throw new Error(((typeof x === 'undefined' ? 'undefined' : _typeof(x)) && x) + ' > ' + ((typeof y === 'undefined' ? 'undefined' : _typeof(y)) && y) + ' : operation invalid for one or more operands types');
} catch (err) {
throw err;
}
}),
'>=': _.curry(function (x, y) {
if (anyUndefined(x, y)) {
return getUndefined(x, y);
}
try {
if (presencetypeEq(x, y)) {
if (typeof x === 'number' && typeof y === 'number') {
return Big(x).gte(y);
} else if (typeof x === 'string' && typeof y === 'string') {
return x >= y;
} else if (x instanceof Date && y instanceof Date) {
return x >= y;
} else if (x.isDate && y.isDate) {
var checkGt = checkInequality('>', '<'); // eslint-disable-line no-use-before-define
return checkGt(x, y, dateTimeComponent.date) >= 0; // eslint-disable-line no-use-before-define
} else if (x.isDateTime && y.isDateTime) {
return valueDT(x) >= valueDT(y);
} else if (x.isTime && y.isTime) {
// make y with the same offset as x before comparison
var xOffset = x['time offset'];
y.utcOffset(xOffset);
return valueT(x) >= valueT(y);
} else if (x.isDtd && y.isDtd) {
return valueDTD(x) >= valueDTD(y);
} else if (x.isYmd && y.isYmd) {
return valueYMD(x) >= valueYMD(y);
}
throw new Error((x.type || (typeof x === 'undefined' ? 'undefined' : _typeof(x))) + ' >= ' + (y.type || (typeof y === 'undefined' ? 'undefined' : _typeof(y))) + ' : operation unsupported for one or more operands types');
}
throw new Error(((typeof x === 'undefined' ? 'undefined' : _typeof(x)) && x) + ' >= ' + ((typeof y === 'undefined' ? 'undefined' : _typeof(y)) && y) + ' : operation invalid for one or more operands types');
} catch (err) {
throw err;
}
}),
'==': _.curry(function (x, y) {
if (anyUndefined(x, y)) {
return getUndefined(x, y);
}
try {
if (x === null && y === null) {
return true;
} else if (x === null !== (y === null)) {
return false;
} else if (typeof x === 'number' && typeof y === 'number') {
return Big(x).eq(y);
} else if (typeof x === 'string' && typeof y === 'string') {
return x === y;
} else if (x instanceof Date && y instanceof Date) {
return x.getTime() === y.getTime();
} else if (typeof x === 'boolean' && typeof y === 'boolean') {
return x === y;
} else if (x.isDate && y.isDate) {
return checkEquality(x, y, dateTimeComponent.date); // eslint-disable-line no-use-before-define
} else if (x.isDateTime && y.isDateTime) {
// make y with the same offset as x before comparison
var xOffset = x['time offset'];
y.utcOffset(xOffset);
return checkEquality(x, y, dateTimeComponent.dateandtime); // eslint-disable-line no-use-before-define
} else if (x.isTime && y.isTime) {
// make y with the same offset as x before comparison
var _xOffset = x['time offset'];
y.utcOffset(_xOffset);
return checkEquality(x, y, dateTimeComponent.time); // eslint-disable-line no-use-before-define
} else if (x.isDtd && y.isDtd) {
return valueDTD(x) === valueDTD(y);
} else if (x.isYmd && y.isYmd) {
return valueYMD(x) === valueYMD(y);
} else if (x.isList && y.isList) {
return _.isEqual(x, y);
}
throw new Error((x.type || (typeof x === 'undefined' ? 'undefined' : _typeof(x))) + ' = ' + (y.type || (typeof y === 'undefined' ? 'undefined' : _typeof(y))) + ' : operation unsupported for one or more operands types');
} catch (err) {
throw err;
}
}),
'!=': _.curry(function (x, y) {
try {
var equalsValue = operatorMap['=='](x, y);
if (equalsValue !== undefined) {
equalsValue = !equalsValue;
}
return equalsValue;
} catch (err) {
throw err;
}
}),
'||': _.curry(function (x, y) {
return x || y;
}),
'&&': _.curry(function (x, y) {
return x && y;
}),
'+': _.curry(function (x, y) {
if (anyUndefined(x, y)) {
return getUndefined(x, y);
}
if (presence(x, y)) {
if (typeof x === 'number' && typeof y === 'number') {
return Number(Big(x).plus(y));
} else if (typeof x === 'string' && typeof y === 'string') {
return x + y;
} else if (typeof x === 'string' && typeof y === 'number' || typeof x === 'number' && typeof y === 'string') {
return x + y;
} else if ((x.isDateTime || x.isDate) && (y.isDateTime || y.isDate)) {
throw new Error(x.type + ' + ' + y.type + ' : operation unsupported for one or more operands types');
} else if (x.isTime && y.isTime) {
throw new Error(x.type + ' + ' + y.type + ' : operation unsupported for one or more operands types');
} else if (x.isYmd && y.isYmd) {
return valueInverseYMD(valueYMD(x) + valueYMD(y));
} else if (x.isDtd && y.isDtd) {
return valueInverseDTD(valueDTD(x) + valueDTD(y));
} else if (x.isDateTime && y.isYmd) {
return dateandtime(date(x.year + y.years + Math.floor((x.month + y.months) / 12), x.month + y.months - Math.floor((x.month + y.months) / 12) * 12, x.day), time(x));
} else if (x.isDate && y.isYmd) {
return date(x.year + y.years + Math.floor((x.month + y.months) / 12), x.month + y.months - Math.floor((x.month + y.months) / 12) * 12, x.day);
} else if (x.isYmd && (y.isDateTime || y.isDate)) {
return dateandtime(date(y.year + x.years + Math.floor((y.month + x.months) / 12), y.month + x.months - Math.floor((y.month + x.months) / 12) * 12, y.day), time(y));
} else if ((x.isDateTime || x.isDate) && y.isDtd) {
return valueInverseDT(valueDT(x) + valueDTD(y), x['time offset']);
} else if (x.isDtd && (y.isDateTime || y.isDate)) {
return valueInverseDT(valueDT(y) + valueDTD(x), y['time offset']);
} else if (x.isTime && y.isDtd) {
return valueInverseT(valueT(x) + valueDTD(y), x['time offset']);
} else if (x.isDtd && y.isTime) {
return valueInverseT(valueT(y) + valueDTD(x), y['time offset']);
}
throw new Error((x.type || (typeof x === 'undefined' ? 'undefined' : _typeof(x))) + ' + ' + (y.type || (typeof y === 'undefined' ? 'undefined' : _typeof(y))) + ' : operation unsupported for one or more operands types');
}
throw new Error(((typeof x === 'undefined' ? 'undefined' : _typeof(x)) && x) + ' + ' + ((typeof y === 'undefined' ? 'undefined' : _typeof(y)) && y) + ' : operation invalid for one or more operands types');
}),
'-': _.curry(function (x, y) {
if (anyUndefined(x, y)) {
return getUndefined(x, y);
}
if (!x && y) {
return -y;
}
if (presence(x, y)) {
if (typeof x === 'number' && typeof y === 'number') {
return Number(Big(x).minus(y));
} else if (typeof x === 'string' && typeof y === 'string') {
throw new Error(x.type + ' - ' + y.type + ' : operation unsupported for one or more operands types');
} else if ((x.isDateTime || x.isDate) && (y.isDateTime || y.isDate)) {
return valueInverseDTD(valueDT(x) - valueDT(y));
} else if (x.isTime && y.isTime) {
return valueInverseDTD(valueT(x) - valueT(y));
} else if (x.isYmd && y.isYmd) {
return valueInverseYMD(valueYMD(x) - valueYMD(y));
} else if (x.isDtd && y.isDtd) {
return valueInverseDTD(valueDTD(x) - valueDTD(y));
} else if (x.isDateTime && y.isYmd) {
return dateandtime(date(x.year - y.years + Math.floor((x.month - y.months) / 12), x.month - y.months - Math.floor((x.month - y.months) / 12) * 12, x.day), time(x));
} else if (x.isDate && y.isYmd) {
return date(x.year - y.years + Math.floor((x.month - y.months) / 12), x.month - y.months - Math.floor((x.month - y.months) / 12) * 12, x.day);
} else if (x.isYmd && (y.isDateTime || y.isDate)) {
throw new Error(x.type + ' - ' + y.type + ' : operation unsupported for one or more operands types');
} else if ((x.isDateTime || x.isDate) && y.isDtd) {
return valueInverseDT(valueDT(x) - valueDTD(y), x['time offset']);
} else if (x.isDtd && (y.isDateTime || y.isDate)) {
throw new Error(x.type + ' - ' + y.type + ' : operation unsupported for one or more operands types');
} else if (x.isTime && y.isDtd) {
return valueInverseT(valueT(x) - valueDTD(y), x['time offset']);
} else if (x.isDtd && y.isTime) {
throw new Error(x.type + ' - ' + y.type + ' : operation unsupported for one or more operands types');
}
throw new Error((x.type || (typeof x === 'undefined' ? 'undefined' : _typeof(x))) + ' - ' + (y.type || (typeof y === 'undefined' ? 'undefined' : _typeof(y))) + ' : operation unsupported for one or more operands types');
}
throw new Error(((typeof x === 'undefined' ? 'undefined' : _typeof(x)) && x) + ' - ' + ((typeof y === 'undefined' ? 'undefined' : _typeof(y)) && y) + ' : operation invalid for one or more operands types');
}),
'*': _.curry(function (x, y) {
if (anyUndefined(x, y)) {
return getUndefined(x, y);
}
if (presence(x, y)) {
if (typeof x === 'number' && typeof y === 'number') {
return Number(Big(x).times(y));
} else if (x.isYmd && typeof y === 'number') {
return valueInverseYMD(valueYMD(x) * y);
} else if (typeof x === 'number' && y.isYmd) {
return valueInverseYMD(x * valueYMD(y));
} else if (x.isDtd && typeof y === 'number') {
return valueInverseDTD(valueDTD(x) * y);
} else if (typeof x === 'number' && y.isDtd) {
return valueInverseDTD(x * valueDTD(y));
}
throw new Error((x.type || (typeof x === 'undefined' ? 'undefined' : _typeof(x))) + ' * ' + (y.type || (typeof y === 'undefined' ? 'undefined' : _typeof(y))) + ' : operation unsupported for one or more operands types');
}
throw new Error(((typeof x === 'undefined' ? 'undefined' : _typeof(x)) && x) + ' * ' + ((typeof y === 'undefined' ? 'undefined' : _typeof(y)) && y) + ' : operation invalid for one or more operands types');
}),
'/': _.curry(function (x, y) {
if (anyUndefined(x, y)) {
return getUndefined(x, y);
}
if (presence(x, y)) {
if (typeof x === 'number' && typeof y === 'number') {
return Number(Big(x).div(y));
} else if (x.isYmd && typeof y === 'number') {
return y === 0 ? null : valueInverseYMD(valueYMD(x) / y);
} else if (typeof x === 'number' && y.isYmd) {
return x === 0 ? null : valueInverseYMD(valueYMD(y) / x);
} else if (x.isDtd && typeof y === 'number') {
return y === 0 ? null : valueInverseDTD(valueDTD(x) / y);
} else if (typeof x === 'number' && y.isDtd) {
return x === 0 ? null : valueInverseDTD(valueDTD(y) / x);
}
throw new Error((x.type || (typeof x === 'undefined' ? 'undefined' : _typeof(x))) + ' / ' + (y.type || (typeof y === 'undefined' ? 'undefined' : _typeof(y))) + ' : operation unsupported for one or more operands types');
}
throw new Error(((typeof x === 'undefined' ? 'undefined' : _typeof(x)) && x) + ' / ' + ((typeof y === 'undefined' ? 'undefined' : _typeof(y)) && y) + ' : operation invalid for one or more operands types');
}),
'**': _.curry(function (x, y) {
if (anyUndefined(x, y)) {
return getUndefined(x, y);
}
if (presence(x, y)) {
if (typeof x === 'number' && typeof y === 'number') {
return Number(Big(x).pow(y));
}
throw new Error((x.type || (typeof x === 'undefined' ? 'undefined' : _typeof(x))) + ' ** ' + (y.type || (typeof y === 'undefined' ? 'undefined' : _typeof(y))) + ' : operation unsupported for one or more operands types');
}
throw new Error(((typeof x === 'undefined' ? 'undefined' : _typeof(x)) && x) + ' ** ' + ((typeof y === 'undefined' ? 'undefined' : _typeof(y)) && y) + ' : operation invalid for one or more operands types');
})
};
function checkEquality(x, y, props) {
return props.reduce(function (recur, next) {
return recur && x[next] === y[next];
}, true);
}
function checkInequality(opTrue, opFalse) {
var fnTrue = operatorMap[opTrue];
var fnFalse = operatorMap[opFalse];
return function (x, y, props) {
return props.reduce(function (recur, next) {
if (recur !== 0) {
return recur;
}
if (fnTrue(x[next], y[next])) {
return 1;
}
if (fnFalse(x[next], y[next])) {
return -1;
}
return 0;
}, 0);
};
}
module.exports = function (operator) {
return operatorMap[operator];
};