Code Monkey home page Code Monkey logo

feel's People

Contributors

angel-m-r avatar deostroll avatar kvsrohit avatar olivieralbertini avatar pktippa avatar pragyandas avatar raghav135 avatar rameshchoudhary avatar sambitkumarpatra avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

feel's Issues

Add new DMN 1.2 numeric built-in functions

DMN 1.2 adds new numeric built-in functions to those already present in DMN 1.1. It is easy to add these to the library.

Here is my take, which adds the following functions (and also validates arguments to be numbers):

  • abs
  • modulo
  • sqrt
  • log
  • exp
  • odd
  • even

Here is the text of utils\built-in-functions\numbers\index.js after the changes:


// Validate that arg is a number and throw if it is not.
function num(arg, functionName) {
  if (typeof arg === 'number') {
    return arg;
  }
  throw new Error(`Type Error : "${functionName}" built-in function expects a number but "${typeof arg}" encountered`);
}

const decimal = (n, scale) => num(n, 'decimal').toFixed(num(scale, 'decimal'));

const floor = n => Math.floor(num(n, 'floor'));

const ceiling = n => Math.ceil(num(n, 'ceiling'));

const abs = n => Math.abs(num(n, 'abs'));

const modulo = (n, modulus) => num(n, 'modulus') % num(modulus, 'modulus');

const sqrt = n => Math.sqrt(num(n, 'sqrt'));

const log = n => Math.log(num(n, 'log'));

const exp = n => Math.exp(num(n, 'exp'));

const odd = n => num(n, 'odd') % 2 === 1;

const even = n => num(n, 'even') % 2 === 0;

module.exports = {
  decimal,
  floor,
  ceiling,
  abs,
  modulo,
  sqrt,
  log,
  exp,
  odd,
  even,
};

date_and_time isn't working as expected in execute_decision_table

Hi everybody!

We're using js-feel for a week now but struggling in using date_and_time as payload. Here is a simple example code sniped, which should return the result "is greater" because 2018-06-09 is a greater date than 2017-06-08. But it doesn't it always returns "default", means no match.

So what's wrong here:

it("evaluate js feel with examples for date", function (done) {
	let payload = {
		inputDate: Date.parse("2018-06-09T00:00:00Z")
	};

	let decisionTable = {
		hitPolicy: 'U',
		inputExpressionList: ['inputDate'],
		outputs: ['ComparedDatesResult'],
		inputValuesList:
		['> date_and_time("2017-06-09T00:00:00Z"),< date_and_time("2017-06-09T00:00:00Z"),-'],
		outputValues: [['"is greater"', '"is less"', '"default"']],
		ruleList:
		[
			['> date_and_time("2017-06-09T00:00:00Z")', '"is greater"'],
			['< date_and_time("2017-06-09T00:00:00Z")',	'"is less"'],
			['-', '"default"']
		],
		context: null
	};

	jsFeel.decisionTable.execute_decision_table("test table with date", decisionTable, payload, (err, results) => {
		console.log(results);
		done();
	});
});

list indexing should be one-based

List indexing and several list functions are defined in the DMN spec as being one-based, not zero based.

Rule: data[2]
context: {data: ["hug", "kiss", "slap"]}
Expected result: "kiss"

DMN 1.1 spec, p124, Table 54 says the index is a 0 scale number, which means integer instead of real. It does not mean zero-based. Section 10.3.4.4 List functions, Table 61, page 132, the semantics for the "remove" function clearly show the use of one-based index. Unfortunately, "sublist" and "insert before" examples in the spec appear incorrect!!!

Page 148 of the DMN 1.2 spec has the examples corrected for these two functions.

I have tried this at https://nikku.github.io/feel-playground and that implementation uses one-based indexing.

not(true) seems not to work

In the following test suite, the tests 'evaluates true = true' and 'evaluates true = false' are evaluated correctly, showing the js-feel implementation seems to work properly, however the tests 'not(true)' and 'not(false)' evaluate to a Function (not to a boolean). If I try to call the function it throws an error "TypeError: Cannot read properties of undefined (reading 'isDate')".

Any help is appreciated.

const feel = require('js-feel/dist/feel');

describe( 'inbuild "not" function', () => {

  it( 'evaluates not(true)', async () => {
    const notTrue = 'not(true)'    
    const ast = await feel.parse( notTrue );
    const result = await ast.build({});
    expect( result ).toBe( false );   // -> Function
  });

  it( 'evaluates not(false)', async () => {
    const notFalse = 'not(false)'    
    const ast = await feel.parse( notFalse );
    const result = await ast.build({});
    expect( result ).toBe( true );   // -> Function
  });

  it( 'evaluates not(true) - with function', async () => {
    const notTrue = 'not(true)'    
    const ast = await feel.parse( notTrue);
    let result = await ast.build({});
    if( typeof result === 'function' ) result = result();
    expect( result ).toBe( false );   // -> "TypeError: Cannot read properties of undefined (reading 'isDate')"
  });

  it( 'evaluates true = true', async () => {
    const notTrue = 'true = true'    
    const ast = await feel.parse( notTrue);
    const result = await ast.build({});
    expect( result ).toBe( true );   // -> ok
  });

  it( 'evaluates true = false', async () => {
    const notTrue = 'true = false'    
    const ast = await feel.parse( notTrue);
    const result = await ast.build({});
    expect( result ).toBe( false );   // -> ok
  });

});

Webpack

Hi,

Does anyone have any experience of using this with webpack? I'm struggling with all manner of dependency issues from xlsx, cptable, dtrace-provider, source-map-support (which can mostly be circumvented with marking them as externals as I don't need the decision table bit, just the feel parser) and requires in external-function are expressions. I guess this just isn't designed to be used with webpack, which is fair enough - but just asking on the off chance someone has done any work on it?

<= ( 1 + 2 ) not working

hi, i was testing few examples and looks like this case is not working. is it valid?

res: peg$SyntaxError {message: "Expected "-", ".", [0-9], [?], [A-Z], [_], [a-z], …ꯥꯨ꯭ﬞ︀-️︠-︯], string, or whitespace but "(" found.", expected: Array(10), found: "(", location: Object, name: "SyntaxError"…}

"now" equivalent ?

Hi, is there a way use today's date / date time in FEEL ?

I guess the actual specification does not support this, is there any workaround that we can use?

Sample use case: we know date of birth in payload.
If age < ... then ...

There are two problems:
The date of birth is a dynamic date field, not a hardcoded string in FEEL
The "now" issue, FEEL expression does not support it

Names in a qualified name are separated by "->" instead of "."

The the grammar file, the names of a qualified name are separated by "->":

QualifiedName
    = head:Name tail: (__ "->" __ Name)*
        {
             return new ast.QualifiedNameNode(buildList(head,tail,3),location());
        }

According to the DMN specification (FEEL production rule 20), it must be "." instead:
qualified name = name , { "." , name } ;

Unable to apply filter expression to a list literal

If a list is part of the context, you may use a filter expression on it.
However, if the list is a list literal, attempting to extract data from it using a filter expression produces a parse error.
A corresponding problem exists if you try to access a property of a context literal using the dot operator.

I have verified that the failing expression parses and properly exedcutes against a Feel 1.3 implementation. I assume but am not sure that 1.1 was supposed to support this case.

SUCCESSFUL PARSE:

Parse tree for rule 'employees[3]' is:

{
  "type": "Program",
  "body": {
    "type": "FilterExpression",
    "expr": {
      "type": "Name",
      "nameChars": "employees",
      "loc": {"start": {"offset": 0,"line": 1,"column": 1},"end": {"offset": 9,"line": 1,"column": 10}},
      "text": "employees"
    },
    "filterExpr": {
      "type": "Literal",
      "value": 3,
      "loc": {"start": {"offset": 10,"line": 1,"column": 11},"end": {"offset": 11,"line": 1,"column": 12}},
      "text": "3"
    },
    "loc": {"start": {"offset": 0,"line": 1,"column": 1},"end": {"offset": 12,"line": 1,"column": 13}},
    "text": "employees[3]"
  },
  "loc": {"start": {"offset": 0,"line": 1,"column": 1},"end": {"offset": 12,"line": 1,"column": 13}
  },
  "text": "employees[3]"
}

UNSUCCESSFUL PARSE:

Parse tree for rule '["Sally", "Harry", "Dilbert", "Dogbert"] [3]' is:

peg$SyntaxError: Expected end of input or whitespace but "[" found.
    at peg$buildStructuredError (c:\Users\pchernoch\projects\feel\dist\feel.js:690:12)
    at Object.peg$parse [as parse] (c:\Users\pchernoch\projects\feel\dist\feel.js:8089:11)
    at test_parse (c:\Users\pchernoch\projects\feel-test\test-feel-expression.js:18:24)
    at main (c:\Users\pchernoch\projects\feel-test\test-feel-expression.js:182:21)
    at Object.<anonymous> (c:\Users\pchernoch\projects\feel-test\test-feel-expression.js:185:1)
    at Module._compile (internal/modules/cjs/loader.js:1063:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12) {
  expected: [ { type: 'other', description: 'whitespace' }, { type: 'end' } ],
  found: '[',
  location: {
    start: { offset: 41, line: 1, column: 42 },
    end: { offset: 42, line: 1, column: 43 }
  }
}

Realtime Condition/Action Update

When i tried to update the excel file actions column, i must restart the engine to get the result updated.

this is because the rootMap won't be created each time, if it's already create so the engine will not create it again and update the data , so this instruction should be deleted to update the rootMap after each checking time
if (rootMap[rootMapId] == null || rootMap[rootMapId] === 'undefined')

Screenshot 2021-11-07 at 14 43 16

Using results outside of the async

Hi everyone, sorry if I ask this question here, but tried a lot of things and wasn't able to solve this problem.

I am trying to use the results of the decision table outside the scope of the async function. like this:

let x;

const payload = {"Traffic":99,"Growth":9,"Transactions":9,"Weight":33};

let promise = new Promise((resolve, reject) => {
    decisionTable.execute_decision_table("Volumetrics", 
    decision_table,payload,  (err, results)  => {  
        resolve(results);   
    });
});

 x = promise.then(
    result =>{return (result) } 
);

console.log (x);

always got this: Promise { <pending> } rather than the json object
I guess is my ignorance about promises and async functions. Any help would be much appreciated. Thank you.

date("2018-07-31") - duration("P1M") fails

When evaluating the expression

date("2018-07-31") - duration("P1M") 

the following error occurs:

Error: Invalid date. Parsing error while attempting to create date from parts
      at date (utils\built-in-functions\date-time-functions\date.js:83:13)
      at operatorMap.-._.curry (utils\helper\fn-generator.js:272:28)
      at apply (node_modules\lodash\lodash.js:496:27)

This is because of the attempt to create the date "2018-06-31", which of course does not exist. It is not sufficient to just reduce the month value, since for the resulting month the day (in this case, the 31st) may not exist.

The same type of error exists for adding months instead of subtracting them.
Likely the same error exists if subtracting or adding months from a date and time instead of a date (I have not verified that).

Here is a test that reveals the error:

  it('should subtract months from last day of month correctly', (done) => {
    const text = 'date("2018-07-31") - duration("P1M") = date("2018-06-30")';
    const parsedGrammar = FEEL.parse(text);
    parsedGrammar.build().then(result => {
      expect(result).to.be.true;
      done();
    }).catch(err => done(err));
  });

Decision table execution always return null

I execute the code as in the exmaple also with table of exemple but always i ahve null en return

const { decisionTable } = require('js-feel')();
var path = require('path');
var root = path.dirname(require.main.filename)
//var absolutePath = path.join(root,req.files['dectabv.xls'].path)
console.log(root);
//console.log(absoluthPath);
root = root + "\dectabu.xls";
console.log(root);
//const csv = decisionTable.xls_to_csv('./dectabu.xls');
const csv = decisionTable.xls_to_csv('./EBB.xlsx');
console.log(csv[0]);
const decision_table = decisionTable.csv_to_decision_table(csv[0]);

console.log(decision_table);

//const payload = {a : 0};
var resu;
const payload = {'State' : 'Kerela', 'Bit' : 'b'};
console.log(payload);
decisionTable.execute_decision_table("EB", decision_table,payload, (resu)=> {
console.log("Rule result: " + resu)
});

EB&SP&SP&SP
RuleTable&SPCondition&SPCondition&SPAction
C+&SPState&SPBit&SPAmount
1&SP"""Karnataka"""&SP"""a"""&SP200
2&SP"""Kerela"""&SP"""b"""&SP300

{
inputExpressionList: [ 'State', 'Bit' ],
inputValuesList: [ '"Karnataka","Kerela"', '"a","b"' ],
outputs: [ 'Amount' ],
outputValues: [ [ '200', '300' ] ],
ruleList: [ [ '"Karnataka"', '"a"', '200' ], [ '"Kerela"', '"b"', '300' ] ],
hitPolicy: 'C+',
context: null
}
{ State: 'Kerela', Bit: 'b' }
Rule result: null

DMN Technology Compatibility Kit

Have you ever looked at running the DMN tck with your library?
For more info see https://github.com/dmn-tck/tck

We are looking for a rule engine are don't really like the java route and would much prefer a JavaScript solution. Your library seems like a great fit but we would like to get a feel for how mature or feature complete the library is. Having TCK results might give some insight.

I could spend some time to see if I can run the TCK with this library, but would like to get your gut feeling for the chance of success first.

Thanks

1 + 123 / > 3 parsed as valid

  1. title above is parsed as valid, confirming if this is valid.
  2. also as and addendum to this, while testing alternatives i realized that "1 + 123 > 3" and its ok, but wondering if there should be a way to specify expected result type, so in case this is expecting number/arithmetic, this first > is marked as invalid.
    2b) (thinking out loud here) having an expected result type may be could have a extra benefit of make parsing grammar simpler

thanks!

No support for string() function

The DMN specification includes a string() function to allow conversion from other data types (e.g. numbers)

When I try to evaluate string(1.1) as a FEEL expression I get

TypeError: Cannot read properties of undefined (reading 'fn') at processUserDefinedFunction (/home/david/x-rules/node_modules/js-feel/dist/feel-ast-parser.js:358:27) at processFnMeta (/home/david/x-rules/node_modules/js-feel/dist/feel-ast-parser.js:397:16)

Implying the function is not available as a built-in so it looks for it as a user-defined function.
Please can someone implement this?

Built-in list functions do not allow variable argument lists

The built-in list functions max, min, sum and mean currently only accept a single argument, a list of items to be aggregated.

The DMN 1.2 specification, section 10.3.4.4 permits a flattened list of arguments of arbitrary length to be supplied instead of a list.

For example both these should work:

  • max([1,2,3]) = 3
  • max(1,2,3) = 3

The following proposed change to utils\built-in-functions\list-functions\index.js would accomplish this.

Replace min, max, sum, and mean imlementations with this:

// Heuristic to determine if an object is a context or not.
// If so, it will have had the built-in functions added to it.
function isContext(obj) {
  return 'max' in obj && 'substring' in obj;
}

const aggregateHelper = (aggregatorFunc, itemsOrList) => {
  if (itemsOrList.length === 1) {
    // One item in array, so require it to be an array.
    if (!Array.isArray(itemsOrList[0])) {
      try {
        return aggregatorFunc([itemsOrList[0]]);
      } catch (err) {
        throw new Error('operation unsupported on element of this type');
      }
    } else {
      return aggregatorFunc(itemsOrList[0]);
    }
  } else if (itemsOrList.length === 2 && isContext(itemsOrList[1])) {
    // Two items in array, but the second one is a context, so only aggregate the first.
    try {
      if (!Array.isArray(itemsOrList[0])) {
        return aggregatorFunc([itemsOrList[0]]);
      }
      return aggregatorFunc(itemsOrList[0]);
    } catch (err) {
      throw new Error('operation unsupported on element of this type');
    }
  } else {
    try {
      if (isContext(itemsOrList[itemsOrList.length - 1])) {
        return aggregatorFunc(itemsOrList.slice(0, itemsOrList.length - 1));
      }
      return aggregatorFunc(itemsOrList);
    } catch (err) {
      throw new Error('operation unsupported on element of this type');
    }
  }
};

// Permits min(n1, n2, n3, ...) or min(list)
const min = (...itemsOrList) => aggregateHelper(arr => _.min(arr), itemsOrList);

// Permits max(n1, n2, n3, ...) or max(list)
const max = (...itemsOrList) => aggregateHelper(arr => _.max(arr), itemsOrList);

// Permits sum(n1, n2, n3, ...) or sum(list)
const sum = (...itemsOrList) => aggregateHelper(arr => _.sum(arr), itemsOrList);

const flatCount = (...itemsOrList) => aggregateHelper(arr => arr.length, itemsOrList);

// Permits mean(n1, n2, n3, ...) or mean(list)
const mean = (...itemsOrList) => {
  const itemSum = sum(...itemsOrList);
  const itemCount = flatCount(...itemsOrList);
  return itemSum / itemCount;
};

NOTE on aggregateHelper:

This function works around the implementation details. The context object is passed to all these methods as a hidden extra argument. By using the rest operator to get all arguments (since the arguments variable is not available in a lambda function) we are also slurping up that context, if present. This function checks for the context and removes it from the arguments to be passed on to lodash.

Little bug when we try to nest decimal function

Hi,

Currently I try to do the following thing :

const rule = 'decimal(decimal(0.22 * a, 0) * 223.65, 0)';
const context = {
    a: 10
};
 
const parsedGrammar = feel.parse(rule);

parsedGrammar.build(context).then(result => {
    console.log(result);
}).catch(err => console.error(err));

Expected behaviour

I expect to have 447 in the result

Current behaviour

I currently have Error: 'string * number : operation unsupported for one or more operands types'

The reason

After investigating why we have this error, I found that decimal function is
const decimal = (n, scale) => n.toFixed(scale)
toFixed is a formatting function, which has a sole purpose of converting a number to a string, formatting it using the specified number of decimals.

After checking the DMN Spec shared in the readme
decimal should return a number and not a string (at page 103, page 109 (10.3.2.3.1 number), page 113 (10.3.2.10 Mapping between FEEL and other domains), page 133 (Table 62: Semantics of numeric functions))

FEEL Expression Value
decimal(1, 2) 1.00

Proposed solution

By changing the decimal function to :

const decimal = (n, scale) => {
  const pow = Math.pow(10, scale);
  return Math.round(n*pow) / pow;
};

If you are agree with this solution, I could make a PR. Let me know thanks !

or list function results in parse error

This is the rule:

'or(likes)'

This is the context passed in:

  context = {
    "likes": [false, false, true]
  };

This is the exception thrown:

peg$SyntaxError: Expected "(", "-", ".", "<", "<=", ">", ">=", "[", "]", "date and time", "date", "days and time duration", "duration", "every", "for", "function", "if", "not", "some", "time zone", "time", "years and months duration", "{", [0-9], end of input, string, or whitespace but "o" found.
    at peg$buildStructuredError (c:\Users\pchernoch\projects\feel-test\node_modules\js-feel\dist\feel.js:690:12)
    at Object.peg$parse [as parse] (c:\Users\pchernoch\projects\feel-test\node_modules\js-feel\dist\feel.js:8089:11)
    at test_rule (c:\Users\pchernoch\projects\feel-test\test-feel-expression.js:10:24)
    at main (c:\Users\pchernoch\projects\feel-test\test-feel-expression.js:98:9) {
  expected: [
    { type: 'other', description: 'whitespace' },
    { type: 'literal', text: '[', ignoreCase: false },
    { type: 'literal', text: 'function', ignoreCase: false },
    { type: 'literal', text: '{', ignoreCase: false },
    { type: 'literal', text: 'for', ignoreCase: false },
    { type: 'literal', text: 'if', ignoreCase: false },
    { type: 'literal', text: 'some', ignoreCase: false },
    { type: 'literal', text: 'every', ignoreCase: false },
    { type: 'literal', text: '(', ignoreCase: false },
    { type: 'literal', text: 'time zone', ignoreCase: false },
    { type: 'literal', text: '-', ignoreCase: false },
    {
      type: 'class',
      parts: [Array],
      inverted: false,
      ignoreCase: false
    },
    { type: 'literal', text: '.', ignoreCase: false },
    { type: 'other', description: 'string' },
    { type: 'literal', text: 'date and time', ignoreCase: false },
    { type: 'literal', text: 'time', ignoreCase: false },
    { type: 'literal', text: 'date', ignoreCase: false },
    { type: 'literal', text: 'duration', ignoreCase: false },
    {
      type: 'literal',
      text: 'years and months duration',
      ignoreCase: false
    },
    {
      type: 'literal',
      text: 'days and time duration',
      ignoreCase: false
    },
    { type: 'literal', text: '<=', ignoreCase: false },
    { type: 'literal', text: '>=', ignoreCase: false },
    { type: 'literal', text: '<', ignoreCase: false },
    { type: 'literal', text: '>', ignoreCase: false },
    { type: 'literal', text: '(', ignoreCase: false },
    { type: 'literal', text: ']', ignoreCase: false },
    { type: 'literal', text: '[', ignoreCase: false },
    { type: 'literal', text: '-', ignoreCase: false },
    { type: 'literal', text: 'not', ignoreCase: false },
    { type: 'literal', text: '-', ignoreCase: false },
    { type: 'end' }
  ],
  found: 'o',
  location: {
    start: { offset: 0, line: 1, column: 1 },
    end: { offset: 1, line: 1, column: 2 }
  }
}

Interestingly, if I create this context with the function named OR (all uppercase) using the same function definition as in the index.js source code for list functions, it works:

  rule = 'OR(likes)';
  context = {
    "OR": (list) => {
      if (!Array.isArray(list)) {
        throw new Error('operation unsupported on element of this type');
      } else {
        return list.reduce((recur, next) => recur || next, false);
      }
    }, 
    "likes": [false, false, true]
  };

Subtracting durations from date and time gives wrong year

date and time("2018-03-01T00:00:00Z") - duration("P3M") 

is evaluated to

date and time("2019-12-01T00:00:00Z") 

instead of

date and time("2017-12-01T00:00:00Z")

This is likely due to a wrong sign in line 244 of file fn-generator.js

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));

I assume it should instead be:

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));

so that the "overflow" year is subtracted, not added.

Unrelated to this, subtracting a duration from a date (without a time) fails, but I do not know if this is by design? In the statement above, time(x) fails since for a date (instead of a date time) there is no time part.

Empty values in context

Rule:
'a+b'
context:
{a:"", b"123"}

throws error " + 123 : operation invalid for one or more operands types".

Error can be fixed by this change to fn-generator.js:
-const presence = (...args) => args.reduce((acc, arg) => acc && (arg || arg===0), true);
+const presence = (...args) => args.reduce((acc, arg) => acc && (arg!=undefined), true);

As far as I understand, the main purpose of this function is to determine the presence of the necessary parameters. But with such implementation, only numeric values can be empty. Comparison with undefined solves the problem for other types.

date("2012-12-23") >= date("2012-12-24") evaluates to true

The comparison of dates (and probably also times) seems to be wrong for inequalities (>, >=, <, <=).

This can be proved by adding the following test case to the file ./test/comparision-expression/feel-comparision-expression.build.spec.js

  it('Successfully compare dates with ">="', function(done) {
    var text = 'date("2012-12-23") >= date("2012-12-24")';
    // another error case: var text = 'date("2011-12-25") > date("2012-12-24")';
    var parsedGrammar = FEEL.parse(text);
    parsedGrammar.build().then(result => {
      expect(result).to.be.false;
      done();
    }).catch(err => done(err));
  });

The error is likely caused by the function "checkInequality" in file utils/helper/fn-generator.js, which applies the operator component-wise (with "component", I mean the date/time parts like year, month, day and so on), which works for equalities but not for inequalities. A possible solution would be to compare the components using two operators - by this we can decide for each component if the inequality holds, or if it does not hold, or if we cannot say and have to proceed to the next component.

function checkInequality(opTrue, opFalse) {
  const fnTrue = operatorMap[opTrue]; // the operator to decide if the inequality holds
  const fnFalse = operatorMap[opFalse]; // the reverse operator to decide if the inequality does not hold
  return function (x, y, props) {
    return props.reduce((recur, next) => {
      if (recur !== 0) { // we already know the result from a previous component
        return recur;
      }
      if (fnTrue(x[next], y[next])) {
        // now we know that the inequality holds
        return 1;
      }
      if (fnFalse(x[next], y[next])) {
        // now we know that the inequality does not hold
        return -1;
      }
      // we still do not know and have to proceed to the next component
      return 0;
    }, 0);
  };
}

Usage of the checkInequality function:

// for <
  const checkLt = checkInequality('<', '>'); // eslint-disable-line no-use-before-define
  return checkLt(x, y, dateTimeComponent.date) > 0;
// for <=
  const checkLt = checkInequality('<', '>'); // eslint-disable-line no-use-before-define
  return checkLt(x, y, dateTimeComponent.date) >= 0; // eslint-disable-line no-use-before-define
// for >
  const checkGt = checkInequality('>', '<'); // eslint-disable-line no-use-before-define
  return checkGt(x, y, dateTimeComponent.date) > 0;
// for >=
  const checkGt = checkInequality('>', '<'); // eslint-disable-line no-use-before-define
  return checkGt(x, y, dateTimeComponent.date) >= 0; // eslint-disable-line no-use-before-define

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.