expression-runner
v1.0.4
Published
Compile and run JavaScript expressions safely
Downloads
27
Maintainers
Readme
Expression Runner
Simple JavaScript expression compiler: given a JavaScript expression as a string, generates a function that evaluates the expression.
Install: npm install expression-runner
Syntax
The following JavaScript syntax is allowed within compiled expressions:
- literal tokens (strings, numbers, etc. but not regular expressions)
- array and object literals (e.g.
[1, 2]
,{ a: 1 }
,{ a, b }
) - function literals (e.g.
(a) => a + 1
, but only using a single expression) - variables and property access
- function and method calls
- calculations with one or more operands, brackets, etc.
- null-coalescing expressions using
??
and?.
operators - tertiary expressions (e.g.
a ? b : c
) - assignments (top-level only, e.g.
a = 1
,b += 2
), but not++
and--
Function calls may include calls to default functions (see list below), as well as 'safe' methods on strings, numbers, arrays, dates, and the RegExp test
method; these do not modify anything other than the original value.
Multiple expressions
Multiple expressions are allowed, separated by semicolons OR newlines.
Only the result of the last expression is returned by the compiled function, however each intermediate result is available as $_
.
This allows for running a block of expressions, although branching and looping is not available (since statements are not compiled).
[3, 2, 1]
sort($_)
$_.map(i => "(" + i + ")")
$_.join(",")
The code above results in the string "(1),(2),(3)"
Usage: as single function
The easiest way to use this library is with the compile()
method:
let myVars = { a: 1 };
const f1 = compile("a + 1");
let result = f1(myVars);
console.log(result) // => 2
Expressions can also be assignments, but those cannot appear in the middle of another expression (e.g. not a = (b = 2)
but b = 2
itself is allowed).
To allow assignments, pass true
as the second argument to the compile
function.
let myVars = {};
const f2 = compile("a = 42", true);
f2(myVars);
console.log(myVars.a) // => 42
The final argument to the compile
function can be used to pass additional functions that will be available within the compiled expression.
let check = 0;
const setCheck = (i) => { check = i };
const f3 = compile("set(42)", false, { set: setCheck });
f3();
console.log(setCheck) // => 42
Precompilation
For manual compilation, especially if you do not want to make the default functions available or if you want to run the same expression multiple times within the same scope (variables), use the following exported classes:
- class
Compiler
- Instantiate a compiler object with a given expression:
new Compiler(expr)
- Compile the expression to an intermediate form:
ic = compiler.compile()
; optionally, pass intrue
to allow assignments at the top level.
- Instantiate a compiler object with a given expression:
- class
Runtime
- Use the static
scopeFactory
method to create aRuntime
constructor that encapsulates the intermediate code:R = Runtime.scopeFactory(ic)
- Instantiate this constructor, passing in (optional) variables and functions as an object:
new R(vars, fns)
. This represents the 'scope' that the expression code will run in - Default functions are available as
Runtime.functions
- The
Runtime
object'srun()
method evaluates the expression, and returns its result:result = r.run()
- Use the static
Default functions
Other than 'safe' methods on strings, numbers, arrays, dates, and regular expressions (created using the regexp
function, since regular expression literals are not allowed), the following 'global' functions are available within expressions.
- Math functions:
abs
,floor
,ceil
,round
,min
,max
,pow
,sqrt
,random
typeof(value)
— result oftypeof value
in JavaScriptstr(value)
— convert to stringchr(value)
— get string from character code (unicode)parseFloat(value)
— same as JavaScriptparseFloat
parseInt(value)
— same as JavaScriptparseInt
isDefined(value)
— returns true if value is not undefined or nullisArray(value)
— same as JavaScriptArray.isArray(...)
isObject(value)
— returns true if value is a plain objectkeys(object)
— same as JavaScriptObject.keys(...)
merge(...objects)
— returns a new object with all properties from given objectsconcat(...arrays)
— returns a new array with all elements from given arrayssort(array, [compareFn])
— returns a copy of the array that is sorted; the comparison function is optional, a default is provided that works well for both strings and numberssortBy(arrayOfObjects, propertyName)
- returns a copy of the array that is sorted by the property with given namereverse(array)
— returns a copy of the array in reverse orderrange(start, length)
— returns an array of numbers starting withstart
, of given lengthtoJSON(value)
— same as JavaScriptJSON.stringify(...)
parseJSON(string)
— same as JavaScriptJSON.parse(...)
regexp(patternString, [flags])
— same as JavaScriptnew RegExp(...)
match(string, patternString, [flags])
— same as JavaScriptstring.match(...)
date(...values)
— same as JavaScriptnew Date(...)
dateUTC(y, m, ...d)
— same as JavaScriptnew Date(Date.UTC(y, m, ...))
now()
— same as JavaScriptDate.now()
(i.e. returns a number)encodeURI(string)
— same as JavaScriptencodeURI(...)
encodeURIComponent(string)
— same as JavaScriptencodeURIComponent(...)