Giter Club home page Giter Club logo

filtrex's Introduction

Filtrex

Build Status


⚠️ UPGRADING TO v3 ⚠️: If you're using Filtrex v2 and want to upgrade to the new version, check the changelog and this issue. If you need help with the migration, feel free to open an issue.


A simple, safe, JavaScript expression engine, allowing end-users to enter arbitrary expressions without p0wning you.

category == "meal" and (calories * weight > 2000.0 or subcategory in ("cake", "pie"))

Get it

Filtrex is available as an NPM package via yarn add filtrex or npm install filtrex:

import { compileExpression } from 'filtrex';
const f = compileExpression(`category == "meal"`)

You can also get the bundled versions from ./dist/.

Why?

There are many cases where you want a user to be able enter an arbitrary expression through a user interface. e.g.

  • Plot a chart (example)
  • Filter/searching across items using multiple fields (example)
  • Colorize items based on values (example)
  • Implement a browser based spreadsheet

Sure, you could do that with JavaScript and eval(), but I'm sure I don't have to tell you how stupid that would be.

Filtrex defines a really simple expression language that should be familiar to anyone who's ever used a spreadsheet, and compiles it into a JavaScript function at runtime.

Features

  • Simple! End user expression language looks like this transactions <= 5 and abs(profit) > 20.5
  • Fast! Expressions get compiled into JavaScript functions, offering the same performance as if it had been hand coded. e.g. function(item) { return item.transactions <=5 && Math.abs(item.profit) > 20.5; }
  • Safe! You as the developer have control of which data can be accessed and the functions that can be called. Expressions cannot escape the sandbox.
  • Pluggable! Add your own data and functions.
  • Predictable! Because users can't define loops or recursive functions, you know you won't be left hanging.

10 second tutorial

import { compileExpression } from 'filtrex';

// Input from user (e.g. search filter)
const expression = `transactions <= 5 and abs(profit) > 20.5`;

// Compile expression to executable function
const myfilter = compileExpression(expression);

// Execute function
myfilter({transactions: 3, profit:-40.5}); // → true
myfilter({transactions: 3, profit:-14.5}); // → false

→ Try it!


Under the hood, the above expression gets compiled to a clean and fast JavaScript function, looking something like this:

(item) => item.transactions <= 5 && Math.abs(item.profit) > 20.5;

Expressions

There are 5 types in Filtrex: numbers, strings, booleans and arrays & objects of these. Numbers may be floating point or integers. The properties of an object can be accessed using the of operator. Types don't get automatically converted: 1 + true isn't two, but an error.

Values Description
43, -1.234 Numbers
"hello" String
" \" \\ " Escaping of double-quotes and blackslash in string
foo, a.b.c, 'foo-bar' External data variable defined by application

BEWARE! Strings must be double-quoted! Single quotes are for external variables. Also, a.b.c doesn't mean data.a.b.c, it means data['a.b.c'].


Numeric arithmetic Description
x + y Add
x - y Subtract
x * y Multiply
x / y Divide
x ^ y Power
x mod y Modulo

BEWARE! Modulo always returns a positive number: -1 mod 3 == 2.


Comparisons Description
x == y Equals
x != y Does not equal
x < y Less than
x <= y Less than or equal to
x > y Greater than
x >= y Greater than or equal to
x == y <= z Chained relation, equivalent to (x == y and y <= z)
x ~= y Regular expression match
x in (a, b, c) Equivalent to (x == a or x == b or x == c)
x not in (a, b, c) Equivalent to (x != a and x != b and x != c)

Boolean logic Description
x or y Boolean or
x and y Boolean and
not x Boolean not
if x then y else z If boolean x is true, return value y, else return z
( x ) Explicity operator precedence

Objects and arrays Description
(a, b, c) Array
a in b Array a is a subset of array b
x of y Property x of object y

Built-in functions Description
abs(x) Absolute value
ceil(x) Round floating point up
empty(x) True if x is undefined, null, an empty array or an empty string
exists(x) True unless x is undefined or null
floor(x) Round floating point down
log(x) Natural logarithm
log2(x) Logarithm base two
log10(x) Logarithm base ten
max(a, b, c...) Max value (variable length of args)
min(a, b, c...) Min value (variable length of args)
round(x) Round floating point
sqrt(x) Square root

Errors

Filtrex may throw during the compilation of an expression (for example if it's malformed, or when you supply invalid options). However, it will never throw during the execution of an expression – instead it will return the corresponding error. It is intentional: this way you don't have to be too cautious when executing user-defined filters even in critical code.

Error type Meaning
UnknownOptionError You specified an option which was not recognized by Filtrex. Double-check your spelling and the version of Filtrex you are using.
UnexpectedTypeError The user passed a different type than the one accepted by the function or operator.
UnknownFunctionError The user attempted to call a function which is not a predefined function, nor specified in options.extraFunctions.
UnknownPropertyError The user attempted to access a property which is not present in the data object, nor in the constants. If the property is meant to be empty, use undefined or null as its value. If you need to use optional properties in your data, define a customProp function.
Error A general error, typically thrown by Jison when parsing a malformed expression.

To achieve a good UX, it is recommended to continually validate the user's expression and let them know whether it's well-formed. To achieve this, you can try to build their expression and evaluate it on sample data every few milliseconds – if it either throws or returns an error, display that error to them.

Many errors have a unique I18N_STRING to help you translate the message to the user's preferred language. Check errors.mjs for more info.

Custom functions and constants

When integrating Filtrex into your application, you can add your own custom functions.

// Custom function: Return string length.
function strlen(s) {
  return s.length;
}

let options = {
  extraFunctions: { strlen }
};

// Compile expression to executable function
let myfilter = compileExpression('strlen(firstname) > 5', options);

myfilter({firstname:'Joe'});    // → false
myfilter({firstname:'Joseph'}); // → true

→ Try it!

You can also add custom constants. This is useful when you want to let the user use a constant value without modifying all the data. If you specify a constant whose name also exists in your data, the constant will have precedence. However, constants cannot be accessed using single-quoted symbols.

const options = {
  constants: { pi: Math.PI }
}
const fn = compileExpression(`2 * pi * radius`, options)

fn({ radius: 1/2 })
// → Math.PI

→ Try it!

const options = { constants: { a: "a_const " } }
const data = { a: "a_data ", b: "b_data " }

// single-quotes give access to data
const expr = `'a' + a + 'b' + b`

compileExpression(expr, options)(data)
// → "a_data a_const b_data b_data"

→ Try it!

Custom operator implementations

Filtrex has many built-in operators: +, -, *, /, ^, mod, ==, !=, <, <=, >=, >, ~= and each of them has a well-defined behavior. However, if you want to change anything about them, you are free to. You can override one or more operators using the options.operators setting.

import { compileExpression } from "filtrex";
import { add, subtract, unaryMinus, matrix }  from "mathjs";

const options = {
  operators: {
    '+': add,
    '-': (a, b) => b == undefined ? unaryMinus(a) : subtract(a, b),
  }
};

const data = { a: matrix([1, 2, 3]), b: matrix([-1, 0, 1]) };

compileExpression(`-a + b`, options)(data)
// → matrix([-2, -2, -2])

→ Try it!

Custom property function

If you want to do even more magic with Filtrex, you can supply a custom function that will resolve the identifiers used in expressions and assign them a value yourself. This is called a property function and has the following signature:

function propFunction(
  propertyName: string, // name of the property being accessed
  get: (name: string) => obj[name], // safe getter that retrieves the property from obj
  obj: any, // the object passed to compiled expression
  type: 'unescaped' | 'single-quoted' // whether the symbol was unquoted or enclosed in single quotes
)

For example, this can be useful when you're filtering based on whether a string contains some words or not:

function containsWord(string, word) {
  // your optimized code
}

let options = {
  customProp: (word, _, string) => containsWord(string, word)
};

let myfilter = compileExpression('Bob and Alice or Cecil', options);

myfilter("Bob is boring"); // → false
myfilter("Bob met Alice"); // → true
myfilter("Cecil is cool"); // → true

→ Try it!

Safety note: The get function returns undefined for properties that are defined on the object's prototype, not on the object itself. This is important, because otherwise the user could access things like toString.constructor and maybe do some nasty things with it. Bear this in mind if you decide not to use get and access the properties yourself.

FAQ

Why the name?

Because you can use it to make filtering expressions – expressions that filter data.

What's Jison?

Jison is bundled with Filtrex – it's a JavaScript parser generator that does the underlying hard work of understanding the expression. It's based on Flex and Bison.

License?

MIT

Unit tests?

Here: Source

What happens if the expression is malformed?

Calling compileExpression() with a malformed expression will throw an exception. You can catch that and display feedback to the user. A good UI pattern is to attempt to compile on each change (properly debounced, of course) and continuously indicate whether the expression is valid. On the other hand, once the expression is successfully compiled, it will never throw – this is to prevent the user from making your program fail when you expect it the least – a compiled expression that fails at runtime will return an error.

Strings don't work! I can't access a property!

Strings in Filtrex are always double-quoted, like this: "hello", never single-quoted. Symbols (ie. data accessors, or variables) can be unquoted or single-quoted, for example: foo, 'foo-bar', foo.bar. However, the dot there doesn't mean a property accessor – it's just a symbol named literally "foo.bar".

Can I use dots as property accessors?

Yes, you can – using a custom prop function! Since this request is a common one, we even ship the required function with Filtrex – it's called useDotAccessOperator. It is enough to do the following:

import {
  compileExpression,
  useDotAccessOperator
} from 'filtrex'

const expr = "foo.bar"
const fn = compileExpression(expr, {
  customProp: useDotAccessOperator
});

fn({ foo: { bar: 42 } }) // → 42

Can I get rid of the UnknownPropertyError?

If you want to return undefined instead of an error when the user accesses an undefined field, you can use the useOptionalChaining property function. And if you want to combine it with dots as access operators, use the useDotAccessOperatorAndOptionalChaining prop function.

Contributors

  • @joewalnes Joe Walnes – the original author of this repository
  • @m93a Michal Grňo – maintainer of the NPM package and the current main developer
  • @msantos Michael Santos – quoted symbols, regex matches and numerous fixes
  • @bradparks Brad Parks – extensible prop function
  • @arendjr Arend van Beelen jr. – quote escaping in string literals
  • @alexgorbatchev Alex Gorbatchev – the original maintainer of the NPM package

filtrex's People

Contributors

albehrens avatar arendjr avatar dependabot[bot] avatar georgest-citrix avatar joewalnes avatar m93a avatar mrbradparks avatar msantos 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

Watchers

 avatar  avatar  avatar  avatar

filtrex's Issues

Change modulo from `%` to `mod`

For a non-programmer, % is immediately recognizable as a per cent sign, not as modulo. The mathematical symbol for a modulo is the “mod” keyword. Filtrex v3 will introduce a mod keyword and deprecate the % operator.

In a future version, % could be potentially reintroduced as percentage.

Remove `random` from standard functions to promote reliability

The ideal filtrex expression should be reliable and return the same result every time it is evaluated. Letting the user call Math.random() by default goes against this principle and might lead to pathological applications states – imagine filtering a paginated list based on a random criterion.

Therefore, the random() function will be removed in v3. Anyone who needs it can pass it as a custom function.

Fail early and reliably

Right now, unknown symbols return undefined, rather than returning a descriptive error:

compileExpression('a', {b: 4})
// undefined
compileExpression('foo of bar')({ bar: 4 })
// undefined

This way, expressions are prone to bugs:

compileExpression('widht > 500', {width: 600})
// false (0)

There should be an API for errors. Errors should be machine-readable and easily localisable by the developer. Errors should be thrown returned much more often.

Catch errors

Don't let the user throw an error. Instead, catch it and return it.

Translatable parser errors

Most errors are now i18n-friendly (see #35), however errors produced by Jison are not. Investigate the possibility to modify Jison, so that it produces better errors.

Support in async functions

Hey,

I would be more than happy if its possible to add an async extra functions support.
I've done it in my fork.
simply alter the following files:
at filtrex.mjs file.

    return async function (data) {
        try {
            return await func(createCall(functions), operators, std, prop, data)
        } catch (e) {
            return e
        }
    };

The use-case that we're having is filtering data utilizing some db queries and it requires async functions :#

Additionally, I've added a test file to test it out:

const options = {
    extraFunctions: {
        asyncFunc: async (a, b) => {
            return new Promise((resolve, reject) => {
                resolve(a + b);
            })
        }
    }
}
const eval = (str, obj) => compileExpression(str, options)(obj);

describe('Arithmetics', () => {
    it('can do simple numeric expressions', async () => {
        expect( eval('1 + 2 * 3') ).equals(7);
    });

    it('can do simple async expressions', async () => {
        expect( await eval('asyncFunc(1,2)') ).equals(3);
    });

});

Add options as an argument

Right now, the compileExpression function has the following signature:

function compileExpression(expr: string, customFunctions?: { [k: any]: Function }, customProp?: Function);

It should be changed to:

function compileExpression(expr: string, options: object)

This would allow us to introduce new API more easily and without breaking changes.

Todo list

  • Change the code
  • Update README
  • Add to changelog

Make a changelog for v3

Version 3 brings a lot of changes, including breaking ones. Either a readme or a wiki page should include a complete changelog. Furthermore, make sure that each new feature is properly documented in the readme.

BREAKING DESIGN CHANGES:

  • #22 (Returning runtime errors instead of undefined.)
  • #27 (Not converting booleans to numbers anymore.)
  • #36 (Modulo can no more return a negative result.)
  • #47

BREAKING BUG FIXES:

  • #41
  • #42 (Changed not in to have the same precedence as in.)
  • #43 (Changed exponentiation to be right-associative.)

DEPRECATIONS:

  • #34 (Ternary ? : operator deprecated in favor of if then else.)
  • #48 (% deprecated in favor of mod.)

NEW FEATURES:

  • #30
  • #35
  • #37
  • #38
  • #44 (Optional chaining and dot accessor syntax.)
  • customProp now has additional argument type: 'unescaped' | 'single-quoted'

Add implicit multiplication

Make this:

 a^2 + 2 a b + b^2

parse as this:

  a**2 + 2*a*b + b**2

The implicit multiplication operator can be overloaded (see #30) using options.operators.juxtapos. If you want to disable multiplication by juxtaposition, redefine the operator to throw an error.

Get a list of used variables

Hi!
Is there a way to get a list of used variables in the expression after compiling it.
E.g.
Expr: transactions <= 5 and abs(profit) > 20.5
Variables: ["transactions","profit"]

Thanks!

Object key with dash symbol

Hi,

my JSON object contains the dash symbol (-) within the, e.g. { 'seller-sku': 'AB-CDEF-GH' } and my filter expression var expression = 'seller-sku == "AB-CDEF-GH"'; does not work with that.

So I would need to pre-parse the object and change every object key to camelCase or PascalCase.

Would it be possible to include all possible JSON keys within the expression?

"non-existent variable" and "!=" expression should return false

For example:

<script src="filtrex.2.2.0.min.js"></script>
<pre>
<script>
var fn1 = filtrex.compileExpression("x==1");
document.write('{x:1}:',fn1({x:1}),"\n"); //1
document.write('{x:2}:',fn1({x:2}),"\n"); //0
document.write('{y:1}:',fn1({y:1}),"\n"); //0

var fn2 = filtrex.compileExpression("x!=1");
document.write('{x:1}:',fn2({x:1}),"\n"); //0
document.write('{x:2}:',fn2({x:2}),"\n"); //1
document.write('{y:1}:',fn2({y:1}),"\n"); //1 (this should be 0)

var fn3 = filtrex.compileExpression("x!=1 and x!=null");
document.write('{x:1}:',fn3({x:1}),"\n"); //0
document.write('{x:2}:',fn3({x:2}),"\n"); //1
document.write('{y:1}:',fn3({y:1}),"\n"); //0 (this is ok)
</script>
</pre>

I can resolve this by using x!=1 and x!=null, but a little troublesome.

Could you provide a way to make that default false? Maybe add an option or something.

Add constants

Sometimes, it is necessary to provide various constants to the user. Right now, the only way to achieve this is to modify the data, which is rather unfortunate – it would be much better to specify the constants only once at compile time. Example usage:

const options = {
  constants: { pi: Math.PI }
}
const fn = compileExpression(`2 * pi * radius`, options)

fn({ radius: 1/2 })
// → Math.PI

It should be possible to access data fields shadowed by constants using single-quoted symbols:

const options = { constants: { a: "a_const " } }
const data = { a: "a_data ", b: "b_data " }

// single-quotes give access to data
const expr = `'a' + a + 'b' + b`

compileExpression(expr, options)(data)
// → "a_data a_const b_data b_data"

In order to keep the API simple, constants will bypass a customProp function – if a developer wants total control over the identifiers, they shouldn't define any constants.

`not in` has weird precedence

As rightly pointed out by @​rici in this SO post, the expression 4 + 3 not in (7, 8) groups as 4 + (3 not in (7,8)), which produces a nonsense answer 4 + true == 5. This will be fixed in v3.

Investigate type detection

In theory, it should be possible to detect the return type of expressions. Investigate whether it would be viable and useful.

Add operator “overloading”

The options object should allow for methods like customAdd and customGreaterThan that would override the default action of these operators.

Make errors i18n-friendly

All errors, both thrown and compile time and returned at runtime, should have an identifier which would make translation possible. It is not acceptable to show English errors in a non-English application.

Add number suffixes (support for units)

If a NUMBER is followed by a SYMBOL, we should treat it as a suffixed number and transformed to something like options.suffixedNumber( num, sfx ). If there is no suffixedNumber method, we should throw an error that makes sense to the user as well as the developer.

This would allow us to write expressions like:

width of screen < 800px

Comparing a user supplied string to a string on the data object

I'm trying to implement a way to filter out objects based on the user supplied string. I wanted to string match using a fuzzy match algorithm, but when defining a custom function:

fuzzy(inputString, matchString) {
   // return boolean
}

and setting the filter expression to this (example data object: { name: 'John K', age: 18 }):
fuzzy(name, 'John')

doesn't pass 'John' to the custom function. Is there a way to do this?

Jison NPM package has Node dependencies

It looks that the Makefile refers to some "src/jison.js" file which is not in the repository
so when you call const Jison = require("jison").Jison; it will reach the jison package in node_modules which depends on some nodejs stuff like the 'fs' module:

https://github.com/zaach/jison/blob/master/package.json#L37 (enbf-parser)
-> https://github.com/zaach/ebnf-parser/blob/master/ebnf-parser.js#L2 (ebnf-transform)
-> https://github.com/zaach/ebnf-parser/blob/master/ebnf-transform.js#L2 (transform-parser)
-> https://github.com/zaach/ebnf-parser/blob/master/transform-parser.js#L623 (fs)

that's why import * as filtrex from "filtrex" fails in browser runtime:

This dependency was not found:
⠀
* fs in ./node_modules/ebnf-parser/parser.js, ./node_modules/ebnf-parser/transform-parser.js and 2 others

To install it, you can run: npm install --save fs

is there any way to use the npm package in the browser ?

Properties cannot contain single quotes

This issue is similar to #11, but applies to properties escaped using single quotes instead. Because there is no support for escaping single quotes, it is not possible to refer to any properties in the input that have single quotes in them.

Cannot create array of 1 element -> return value is element alone and not an array of a single element

When creating an array of 1 value i.e. (42) the return value is just 42 instead of an array of a single element 42

This test passes

it('array support', () => {
        const arr = eval('(42, "fifty", pi)', {pi: Math.PI});

        expect(arr).is.array();
        expect(arr).to.be.equalTo([42, "fifty", Math.PI]);
    });

This test fails

it('array single element', () => {
        const arr = eval('(42)');

        expect(arr).is.array();
        expect(arr).to.be.equalTo([42]);
    });

Allow `in` operator for runtime arrays

The current implementation only allows identifier in arrayLiteral syntax. Variants arrayLiteral in identifier and identifier in identifier should also be allowed for completeness.

Access nested object properties

Dear,

Thanks for sharing this very useful library!

I'm a bit confused about nested object properties.
I pass an object like this:

image

Which we try to validate using following expression:

msg.payload.open == true

From the readme page I understood this should be possible:

image

But I might have misinterpreted this??
And indeed while debugging, I see that this library checks whether the object has its own property "msg.payload.open" which is of course not the case:

image

Which means the nested property cannot be found :-(

However when I change the code to this:

    function prop(name, obj) {
        return name.split('.').reduce((obj, prop) => {
            return obj && obj[prop] ? obj[prop] : undefined;
        }, obj)
    }

    function safeGetter(obj) {
        return function get(name) {
            return name.split('.').reduce((obj, prop) => {
                return obj && obj[prop] ? obj[prop] : undefined;
            }, obj)
        }
    }

Then the nested property can be found without problems:
image

Thanks !!!
Bart

Add option to use dot attribute access

Hi! I just want to say that I love this package and it's super useful for things like offloading dashboard search and filtering logic to config files so thank you!

My only hangup is that you have to do y of x of config instead of config.x.y which to me feels a bit confusing and counter-intuitive. And it makes it harder to teach others about how to use the expressions because it goes against how you access data in most other languages.

I wonder if it'd be possible to add a filter compile option that allows you to enable dot attribute access? That way we could keep the default functionality, but allow for a more familiar config.x.y to access attributes (instead of key literals) if a user prefers.

A headstart on a solution?

I'm not very familiar with language grammar definitions so I'm sure this isn't all right, but I'm hoping it's in the right direction.

Add ['\\.', 'return ".";'], after this line?

['of[^\\w]', 'return "of";'],

Replace this regex with: '[a-zA-Z$_][a-zA-Z0-9$_]*'

['[a-zA-Z$_][\\.a-zA-Z0-9$_]*',

Add ['left', '.'], after

['left', 'of'],

Add ['e . SYMBOL', code(['prop(', 1, ',', 3, ')'])], (I think?)

['SYMBOL of e', code(['prop(', 1, ',', 3, ')'])],

Boolean values are handled as property names

Dear,

I wanted to test whether an object property is true.
Don't see booleans values mentioned on the readme page, but found an Add booleans pull request.
So I assume this is supported...

However I get the impression that it only works for a boolean as string ("true" or "false")...

Because when I use this expression:

msg.payload.open == true

Then it tries to get a property with the name "true" from my object:

image

I was wondering if you could do something like this in your code: when the property name is "true" or "false", then it is no property but a boolean. So you simply leave it untouched in the expression, without wrapping it with prop(...)?

P.S. I don't think that "true" or "false" are allowed as property names in JavaScript, when looking at this Stackoverflow discussion. When you click on the Mozilla link in that this discussion you find this:

Additionally, the literals null, true, and false cannot be used as identifiers in ECMAScript.

A JavaScript identifier is a sequence of characters in the code, that identifies a variable, function, or property...

Thanks!!!
Bart

Investigate rewriting in PEG

The Jison parser generator makes it hard to write advanced language features (like implicit multiplication, see #39). Maybe, migrating to a modern PEG parser would be worth it. Peggy looks quite good.

Add booleans

While using ones and zeros is fun, returning an actual boolean would make things more robust. It would, for example, allow the developer to detect more potential mistakes on the user's side and warn them.

Strings cannot contain double quotes

Strings (surrounding with double quotes) in filtrex expressions cannot contain any double quote characters themselves.

I'll open a PR to address this.

TypeError: cannot assign to read only property 'name' function

Hi,

I have recently upgraded the version of the filtrex package to 2.0.0 but our previously working code is now giving a TypeError as soon as the app loads.

The error seems to be come from the jison.js file in line 2143:

"push shift unshift forEach some every join sort".split(' ').forEach(function (e,i) {
    setMixin[e] = function () { return Array.prototype[e].apply(this._items, arguments); };
    setMixin[e].name = e;
});

The error stack is as follows:

Uncaught TypeError: Cannot assign to read only property ‘name’ of function ‘function () { return Array.prototype[e].apply(this._items, arguments); }’
   at index-0e1ff3fc.js:5286
   at Array.forEach (<anonymous>)
   at Object.factory [as jison/util/set] (index-0e1ff3fc.js:5284)
   at r (index-0e1ff3fc.js:3150)
   at Object.factory [as jison] (index-0e1ff3fc.js:3166)
   at r (index-0e1ff3fc.js:3150)
   at Module.../../../build/@shared/stencil/esm/index-0e1ff3fc.js (index-0e1ff3fc.js:6477)
   at __webpack_require__ (bootstrap:84)
   at Module.../../../build/@shared/stencil/esm/index-563ba7d7.js (index-563ba7d7.js:1)
   at __webpack_require__ (bootstrap:84)

Any help with this would be appreciated. If you need any further info, feel free to contact me and I will help with what I can.

Expressions to customise return value

Is there scope in this project to allow expressions that calculate a return value?

var returnExpression = 'text in response'';
let myReturn = compileReturnExpression(returnExpression);
return myReturn({response: {code: 200, text: 'hi'}}); // returns hi

Add better support for sorting

The core engine should be able to compare numbers, alphabetical strings (with natural sorting) and arrays (element by element, lexicographically, useful for multisort), so that filtrex can be used for custom user-defined sorting.

Single item arrays

Using '(' ')' to represent arrays of length 1 does not work and returns the item inside the array instead.

Example usecase:
equals(account_numbers, ("1"))
the function receives 1.
When adding another value to the list, for example ("1", "2")
The function receives [1, 2] as expected.

(equals is a custom function)

Change the ternary operator to `if..then..else`

Many languages, including Python and CoffeeScript, use keywords if and else instead of the ternary operator ?:. This approach is better aligned with the goals of filtrex. In particular, the CoffeeScript version (if a then b else c) is very close to natural language which makes it layman-friendly.

This change is scheduled as a breaking change in v3.0.0. Any discussion is welcome.

Exponentiation is left-associative

As pointed out here, filtrex has left-associative exponentiation x^y^z == (x^y)^z, while everyone else uses right-associative exponentiation x^y^z == x^(y^z). The current behavior is undocumented and there is no reason to do it the non-standard way. This will be fixed in v3.

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.