Ceval

online demo;
零依赖,适合表达式运算;
No dependence, suitable for calculating expressions;
┌───────────────────────────────┐
│ │
│ Destination: lib/index.js │
│ Bundle Size: 21.92 KB │
│ Minified Size: 21.89 KB │
│ Gzipped Size: 6.76 KB │
│ │
└───────────────────────────────┘
usage
npm i ceval -S
introduce

Options
const Parser = require('ceval')
const analysis = new Parser({
endableOperators?: boolean = true;
endableBitNumber?: boolean = true;
allowMemberAccess?: boolean = true;
allowHandleNumberPrecision?: boolean = true;
allowOperatorsCovered?: boolean;
defaultReturnValues?: any = ''
})
API
Parser Instance API
| api | desc | type |
| --- | --- | --- | --- |
| operatorMap | Operators mapping table, which can be used in preset values overlay operation | Record<string, Function>|
| getSupportOperationMap | The name of the operator method supported by the query can be overridden | (ops: string) => null | Function;|
| parseString | Parsing strings, exposing methods to the outside world | (expression: string, values?: Record<string, any>) => any;|
| getCurrentValues | Get current datapool preset + external + internal declaration | () => Record<string, any> |
| updatePresetValues| Update PresetValues |(values: Record<string, any>) => void|
| updateOptions| Update Option | (Options: Partial) => void|
| getOptions| get Options | () => Readonly|
about Options example test case;
use test262 test case;
rule
There are two rules:
Semicolon at the end
e.g.
parse('0b01 + 0b01;')
Although it is not necessary in a simple expression operation, but it's a good habit.The parser can know exactly where the end is, Although it doesn't have too many restrictions.
e.g.
parse(`
function abs(a,b,c) {
let b = 1 /* ⚠️ error, must has semicolon */
c = 2;
return(a+b+c);
};
abs(3,4,8);
`)
statement
"var" statement does not affect "scope", it's inserted into values
"let" and "const" assigned to the current scope, warn if the current scope exists
var Parser = require('ceval');
var instance = new Parser({});
var parse = instance.parseString;
parse(`
var obj = { foo:'foo', bar: 'bar'};
function abs(a,b,c) {
var d = 'global';
return (a+b+c);
}
abs(1,2,3)
`)
console.log(instance.getCurrentValues().obj);
console.log(instance.getCurrentValues().d);
parse(`
let foo = 'foo';
const bar = 'bar';
function abs(a,b,c) {
let d = 'scope';
const e = 'scope';
return (a+b+c);
}
abs(1,2,3)
`)
console.log(instance.getCurrentValues().foo);
console.log(instance.getCurrentValues().bar);
console.log(instance.getCurrentValues().d);
console.log(instance.getCurrentValues().e);
basic
const { parse: parse } = analysis
Number
parse('0b01')
parse('0b11')
parse('0b010101')
parse('01')
parse('077')
parse('01111')
parse('.1')
parse('33')
parse('100.00')
parse('0x01')
parse('0xaf')
parse('0x9fac')
parse(`1e+308*2 === Infinity`)
parse(`
var x = NaN;
var y = NaN;
return (x !== y);
`)
parse(`
var x = NaN;
return(typeof(x) === 'number');
`)
parse(`
var x = NaN;
var x_geq_0=(x >= 0.0);
return(x_geq_0)
`)
parse(`
var x=+Infinity;
return(typeof(x) === 'number')
`)
More testcase here
calculation
const obj = `{ a: 1, b: 2, c: 3, d: { e: 4, f: 5}}`
parse(`1+1`);
parse(`-1-2-3`);
parse(`1*2*3`);
parse(`1/2/4`);
parse(`undefined || 2`);
parse(`~-1 || -2 || 3`);
parse(`-0 == +0`);
parse(`~1 > 1`);
parse(`false > false > 1`);
parse(`5 >= 0`);
parse(`1 in [1, 2, 3]`);
parse(`undefined in [1, 2, true]`);
parse(`'a' in ${obj}`);
parse(`\'\'a\'\' in ${obj}`);
parse(`1 === true`);
parse(`3%2`);
Function
parse(`
function abs(a,b,c) {
var a = 5; /* => inject to presetValues */
let b = 1; /* => inject to current scope */
c = 2;
const d = 4; /* If the current scope contains the variable D, It will trigger warning, but the operation will still be completed, is overlay */
return(a+b+c);
};
abs(3,4,8);
`)
Object & Array
parse(`[1*2, false, true, undefined, null]`);
parse(`var a = { b: { c: ['a','b','c','d']} };'e' in a.b.c`);
parse(`{ a: 1, b: 2, c: { d: undefined, e: { f: false, g: { h: null }}}}`);
parse(`var a = { b: 2 };a.b`)
parse(`var a = { b: 2 };a["b"]`)
parse(`var a = { b: 2, c:3 };var b='c';a[b]`)
parse(`
var a = { b: 2, c:[1,2,3]};
var b='c';
a[b][0] = '0';
return a[b];
`)
parse(`
var arr = [1,2,3];
arr[0] = 0;
return arr;
`)
Variable
parse(`
var a = { foo: 1 };
var b = { bar: 2 };
let a = { state: 1 } // ⚠️, Raise warning, current scope exists key
const b = { state: 1 } // ⚠️, Raise warning, current scope exists key
let c = { coo: 1} // success;
const d = { coo: 1} // success;
`)
parse(`
var a = { a: [false, true, undefined, null, ''] };
var b = { b: true, c: undefined, d:{ e: a, f: '1', g: {}}};
`)
this
Operator
Through instance.operatorMap Get all operators;
return
return interrupt this operation cycle; but it doesn't affect the outside world.
parse(`
return 1;
return 2;
`)
parse(`
var foo = 'foo'
function abs(a,b,c) {
return a;
return b;
}
var bar = abs(1,2,3)
return (bar + foo);
`)
Other
Please move to test case for more examples。
TODO: Test39 Some test cases,
speed of progress
2020-06-24 done: number, null, boolean
In more function extension, welcome to participate or propose feature.
development
develop
npm start
build
# webapck build umd module, No compression
npm run build:umd
# rollup build umd module, Compressed version
npm run build:rollup
# webpack build docs
npm run build:docs
publish
npm publish