build-function
v0.1.0
Published
The way to describe and build simple functions using JSON
Downloads
33
Readme
build-function
The way to describe and build simple functions using JSON
Motivation
I need to allow the end user to create some simple function using a JSON file (mostly math based functions), but without allowing them to access the global scope. This module allow them to declare and run functions, but in an enclosed environment provided by the developer.
Performance Notice
Functions built with this module are very slow, despite the fact that we pre-compile and cache every expression and statement. Use it only when performance is not an issue.
In This Guide
CDN
jsDelivr
<script src="https://cdn.jsdelivr.net/npm/build-function@latest/dist/build.umd.js"></script>
for production...
<script src="https://cdn.jsdelivr.net/npm/build-function@latest/dist/build.umd.min.js"></script>
UNPKG
<script src="https://unpkg.com/build-function@latest/dist/build.umd.js"></script>
for production...
<script src="https://unpkg.com/build-function@latest/dist/build.umd.min.js"></script>
API
build
Creates a function from options
using env
as outer environment
.
function build(
options: BuildFunctionOptions,
env?: Environment,
): Function;
interface BuildFunctionOptions {
name?: string;
params?: string | ParamDescriptor | Array<string | ParamDescriptor>;
body?: Step | Step[];
}
arguments
options
Function options.
name
(optional
)A
name
for thefunction
, if provided it will be registered to theenvironment
so you can call the function recursively.params
(optional
)see Function Expression for more information.
body
(optional
)see Function Expression for more information.
env
(optional
)Outer
environment
for the function. see environment section for more information.
compileExp
Compiles an expression
or array of expressions
into a function
or array of functions
.
function compileExp(
expression: Expression,
cache: object,
safeGet?: boolean,
): (env: Environment) => any;
function compileExp(
expression: Array<Expression>,
cache: object,
safeGet?: boolean,
): Array<(env: Environment) => any>;
arguments
expression
Expression
orarray of Expressions
to be compiled.cache
Cache object.
safeGet
(optional
)Whether or not to return
undefined
ifid
not found on aget
expression. IfsafeGet
is falsyget
expression will throw ifid
not present in theenvironment
.
compileStep
Compiles a step
or array of steps
into a function
.
function compileStep(
step: Step | Step[],
cache: object,
allowBreak?: boolean,
): (env: Environment) => StepResult;
arguments
step
Step
orarray of steps
to be compiled.cache
Cache object.
allowBreak
(optional
)Whether or not to allow
break
statements.
createEnv
Creates a new environment
with parent
as parent environment.
function createEnv(
parent: Environment | null,
lib?: EnvironmentLib | null,
): Environment;
arguments
parent
Parent
environment
.lib
Variables to be added to the newly created
environment
.
findInEnv
Searches for an id
in an environment
.
function findInEnv(
env: Environment,
id: string,
topOnly?: boolean,
): EnvFound | void;
interface EnvFound {
env: Environment;
id: string;
}
arguments
env
The
environment
.id
Variable
id
to search for.topOnly
(optional
)Whether or not to search the top level
environment
only. Otherwise it will keep searching every parentenvironment
.
setInEnv
Sets a value into an environment
.
function setInEnv(
env: Environment,
id: string,
value: any,
): void;
arguments
env
The
environment
to set the variable.id
The variable
id
.value
The variable value.
Expressions
Literal Expression
It resolves to a literal expression.
syntax
interface LiteralExpression {
type: "literal";
value: any;
}
type
Always
"literal"
, it's what identifies aliteral
expression from other expressions and statements.value
Value to be used as literal when expression is evaluated. This value will be serialized using
JSON.stringify
and then reparsed usingJSON.parse
when expression is evaluated, it allows to resolve to a fresh object or array when expresion is evaluated.
example
{
"type": "literal",
"value": [1, 2]
}
... is equivalent to...
[1, 2]
Get Expression
Gets a value of the variable identified by the id
from the current virtual environment. If the variable if not found, it will throw, unless it is inside a typeof
trnsform operation.
syntax
interface GetExpression {
type: "get";
id: string;
}
type
Always
"get"
, it's what identifies aget
expression from other expressions and statements.id
String representing the
id
to be used when expression is resolved.If the
id
is not present in the current virtual environment, it will throw.
example
{
"type": "get",
"id": "current"
}
... is equivalent to...
current
Set Expression
It sets a value to the variable identified by the id
in the current virtual environment. If the variable has not been declared prevoiusly, it will throw. The expression will resolve to the value being set.
syntax
interface SetExpression {
type: "set";
id: string;
value: Expression;
}
type
Always
"set"
, it's what identifies aset
expression from other expressions and statements.id
String representing the
id
to be used when expression is resolved.value
Expression resolving to a value to be assigned to the corresponding
id
in the current virtual environment.
example
{
"type": "set",
"id": "a",
"value": {
"type": "set",
"id": "b",
"value": {
"type": "literal",
"value": true
}
}
}
... is equivalent to...
a = b = true
Note that set
expressions resolve to the value being set so they can be chained together.
Ternary Expression
It resolves to a ternary operation expression.
syntax
interface TernaryExpression {
type: "ternary";
condition: Expression;
then: Expression;
otherwise: Expression;
}
type
Always
"ternary"
, it's what identifies aternary
expression from other expressions and statements.condition
Expression which result will be used as condition for the
ternary
expression.then
Expression which result will be used as resul for the
ternary
expression ifcondition
is truthy.otherwise
Expression which result will be used as resul for the
ternary
expression ifcondition
is falsy.
example
{
"type": "ternary",
"condition": {
"type": "get",
"id": "value",
"then": {
"type": "literal",
"value": "yes"
},
"otherwise": {
"type": "literal",
"value": "no"
}
}
}
... is equivalent to...
value ? "yes" : "no"
Operation Expression
It performs an operation between 2 or more operands, see operations for supported operators and information.
syntax
interface OperationExpression {
type: "oper";
oper: MultiTermOperator;
exp: Expression[];
}
type
Always
"oper"
, it's what identifies anoperation
expression from other expressions and statements.oper
The operator to be used in the operation, see operations for more information.
exp
Array of expressions to be used in the operation, if less than 2 operators provided, it will throw at compile time.
example
{
"type": "oper",
"oper": "*",
"exp": [
{
"type": "literal",
"value": "15"
},
{
"type": "oper",
"oper": "+",
"exp": [
{
"type": "get",
"id": "value"
},
{
"type": "literal",
"value": 2
},
{
"type": "literal",
"value": 5
}
]
}
]
}
... is equivalent to...
15 * (value + 2 + 5)
Every operation expression acts like its operands has been grouped inside parentheses, so the order of operations doesn't apply.
Transform Expression
It performs a transform operation to another expression, see transformations for supported operators and information.
syntax
interface TransformExpression {
type: "trans";
oper: TransformOperator;
exp: Expression;
}
type
Always
"trans"
, it's what identifies atrnsform
expression from other expressions and statements.oper
The operator to be used in the operation, see transformations for more information.
exp
Expression which result will be transformed.
example
{
"type": "trans",
"oper": "typeof",
"exp": {
"type": "get",
"id": "value"
}
}
... is equivalent to...
typeof value
Function Expression
It represents a function expression.
syntax
interface FunctionExpression {
type: "func";
params?: string | ParamDescriptor | Array<string | ParamDescriptor>;
body?: Step | Step[];
}
interface ParamDescriptor {
id: string;
type: "param" | "rest";
}
type
Always
"func"
, it's what identifies afunction
expression from other expressions and statements.params
(optional
)String representing the the param
id
,object
representing paramid
andtype
, or anarray of them
representing multiple parameters.body
(optional
)A
step
orarray of steps
to be executed when the function is called. See function steps for more information.
example
{
"type": "func",
"params": "obj",
"body": {
"type": "return",
"value": {
"type": "trans",
"oper": "!",
"exp": {
"type": "get",
"id": "obj"
}
}
}
}
... is equivalent to...
function (obj) {
return !obj;
}
Function Call Expression
It represents a function call result expression.
syntax
interface FunctionCallExpression {
type: "call";
func: Expression;
args?: Expression | SpreadExpression | Array<Expression | SpreadExpression>;
}
type
Always
"call"
, it's what identifies afunction call
expression from other expressions and statements.func
Expression which resolves to a function to be called.
args
(optional
)Expression
,spread expression
orarray of them
to be used asarguments
to call the function.
example
{
"type": "call",
"func": {
"type": "get",
"id": "concat"
},
"args": [
{
"type": "literal",
"value": "Hello "
},
{
"type": "get",
"id": "name"
}
]
}
... is equivalent to...
concat("Hello ", name)
Spread Expression
It spreads the values of an array for a function call. Spread expressions only work on function call expressions, it will throw if used somewhere else.
syntax
interface SpreadExpression {
type: "spread";
exp: Expression;
}
type
Always
"spread"
, it's what identifies aspread
expression from other expressions and statements.exp
Expression which resolves to an array to be spread.
example
{
"type": "call",
"func": {
"type": "get",
"id": "func"
},
"args": [
{
"type": "literal",
"value": 100
},
{
"type": "spread",
"exp": {
"type": "get",
"id": "others"
}
}
]
}
... is equivalent to...
func(100, ...others)
Statements
let
Statement
Declares variables into the current virtual environment.
syntax
interface LetStatement {
type: "let";
declare: string | DeclareWithValue | Array<string | DeclareWithValue>;
}
interface DeclareWithValue {
id: string;
value?: Expression;
}
type
Always
"let"
, it's what identifies alet
statement from other statements and expressions.declare
An
id
,id-value-pair
orarray of them
to be declared into the current virtual environment.
example
{
"type": "let",
"declare": [
"a",
{
"id": "b"
},
{
"id": "c",
"value": 10
}
]
}
... is equivalent to...
let a, b, c = 10;
if
Statement
Declares an if
statement.
syntax
interface IfStatement {
type: "if";
condition: Expression;
then?: Step | Step[];
otherwise?: Step | Step[];
}
type
Always
"if"
, it's what identifies anif
statement from other statements and expressions.condition
Expression which result will be used as condition for the
if
statement.then
(optional
)A
step
orarray of steps
to be executed ifcondition
resolves to a truthy value. See function steps for more information.otherwise
(optional
)A
step
orarray of steps
to be executed ifcondition
resolves to a falsy value. See function steps for more information.
example
{
"type": "if",
"condition": {
"type": "get",
"id": "test"
},
"then": {
"type": "call",
"func": {
"type": "get",
"id": "func1"
}
},
"otherwise": {
"type": "call",
"func": {
"type": "get",
"id": "func2"
}
}
}
... is equivalent to...
if (test) {
func1();
} else {
func2();
}
for
Statement
Declares a for
loop.
syntax
interface ForStatement {
type: "for";
target: Expression;
index?: string;
value?: string;
body?: Step | Step[];
}
type
Always
"for"
, it's what identifies afor
statement from other statements and expressions.target
Expression resolving to an
array-like
object, whichlength
property will be used for the loop.index
(optional
)The
id
to be registered inside the loop body virtual environment containing the current iteration index, if not specified it won't be registered, the loop will still run.value
(optional
)The
id
to be registered inside the loop body virtual environment containing the current iteration value, if not specified it won't be registered, the loop will still run.body
(optional
)A
step
orarray of steps
to be executed for every iteration. See function steps for more information.
example
{
"type": "for",
"target": {
"type": "get",
"id": "array"
},
"index": "index",
"value": "item",
"body": {
"type": "call",
"func": {
"type": "get",
"id": "func"
},
"args": [
{
"type": "get",
"id": "index"
},
{
"type": "get",
"id": "item"
}
]
}
}
... is equivalent to...
for (let i = 0; i < array.length; i++) {
func(i, array[i]);
}
break
Statement
Declares a break
statement, it will throw at build time if used outside a loop.
syntax
interface BreakStatement {
type: "break";
}
type
Always
"break"
, it's what identifies abreak
statement from other statements and expressions.
return
Statement
It represents a return
statement.
syntax
interface ReturnStatement {
type: "return";
value: Expression;
}
type
Always
"return"
, it's what identifies areturn
statement from other statements and expressions.value
Expression which result will be used as
return
value.
example
{
"type": "return",
"value": {
"type": "get",
"id": "result"
}
}
... is equivalent to...
return result;
try
Statement
It represents a try
statement.
syntax
interface TryStatement {
type: "try";
body?: Step | Step[];
error?: string;
catch?: Step | Step[];
}
type
Always
"try"
, it's what identifies atry
statement from other statements and expressions.body
(optional
)A
step
orarray of steps
to be executed insidetry
block.error
(optional
)The
id
to be registered inside thecatch
block virtual environment containing the error message, if not specified it won't be registered.catch
(optional
)A
step
orarray of steps
to be executed insidecatch
block.If
error
option provided you can access the error message using aget
expression.
example
{
"type": "try",
"body": {
"type": "call",
"func": {
"type": "get",
"id": "test"
},
"args": [
{
"type": "get",
"id": "a"
},
{
"type": "get",
"id": "b"
}
]
},
"error": "err",
"catch": {
"type": "call",
"func": {
"type": "get",
"id": "log"
},
"args": {
"type": "get",
"id": "err"
}
}
}
... is equivalent to...
try {
test(a, b);
} catch (err) {
log(err);
}
throw
Statement
It represents a throw
statement.
syntax
interface ThrowStatement {
type: "throw";
msg: string | Expression;
}
type
Always
"throw"
, it's what identifies athrow
statement from other statements and expressions.msg
A
string
orExpression
resolving to astring
to be used as error message.
example
{
"type": "throw",
"msg": "Unknown Error"
}
... is equivalent to...
throw new Error("Unknown Error");
Steps
Any statement or expression is considered a step.
Operations
Multiterm operations are defined using the Operation Expression.
Supported Operators
+
Addition Operator
-
Subtraction Operator
*
Multiplication Operator
/
Division Operator
%
Modulus Operator
**
Exponentiation Operator
&&
Logic AND Operator
||
Logic OR Operator
==
Equal Operator
===
Strict equal Operator
!=
Unequal Operator
!==
Strict unequal Operator
<
Less than Operator
<=
Less than or equal Operator
>
Greater than Operator
>=
Greater than or equal Operator
&
Bitwise AND Operator
|
Bitwise OR Operator
^
Bitwise XOR Operator
<<
Shift Left Operator
>>
Shift Right Operator
>>>
Unsigned Shift Right Operator
Transformations
Transformations are defined using the Transform Expression.
Supported Transform Operators
typeof
Type Operator
!
NOT Operator
!!
To Boolean Operator
~
Bitwise NOT Operator