@@ -4,14 +4,16 @@ Have you ever wanted to use some dynamic JS capabilities when using the ssr char
4
4
5
5
Now we have solved this problem for you. We have designed a simple and easy-to-understand template syntax to help you achieve dynamic rendering of charts.
6
6
7
- ## Features
8
7
9
- - 🔒 ** Secure by default** - No access to global objects or prototype chain, does not use ` eval ` or ` new Function `
10
- - 🚀 ** High performance** - Supports pre-compilation of expressions for improved performance with repeated evaluations
11
- - 🛠️ ** Extensible** - Register custom functions to easily extend functionality
12
- - 🪩 ** Lightweight** - Zero dependencies, small footprint, only ` 7.8KB `
8
+ ## ✨ Features
13
9
14
- ## Installation
10
+ - 🔒 ** Secure by default** - No access to global objects or prototype chain, does not use ` eval ` or ` new Function ` .
11
+ - 🚀 ** High performance** - Supports pre-compilation of expressions for improved performance with repeated evaluations.
12
+ - 🛠️ ** Extensible** - Register custom functions to easily extend functionality.
13
+ - 🪩 ** Lightweight** - Zero dependencies, small footprint, only ` 7.8 Kb ` before gzip.
14
+
15
+
16
+ ## 📥 Installation
15
17
16
18
``` bash
17
19
npm install @antv/expr
@@ -21,7 +23,8 @@ yarn add @antv/expr
21
23
pnpm add @antv/expr
22
24
```
23
25
24
- ## Basic Usage
26
+
27
+ ## 🔨 Usage
25
28
26
29
### Synchronous Expression Evaluation
27
30
@@ -51,45 +54,23 @@ const result1 = evaluator({ price: 10, quantity: 5 }); // returns 50
51
54
const result2 = evaluator ({ price: 20 , quantity: 3 }); // returns 60
52
55
```
53
56
54
- ### Using Asynchronous Patterns (Optional)
55
-
56
- While the library is synchronous, you can still use asynchronous patterns if needed:
57
-
58
- ``` typescript
59
- import { evaluate } from ' @antv/expr' ;
60
-
61
- // Wrap evaluation in an async function
62
- async function asyncEvaluate(expr , context ) {
63
- return new Promise ((resolve , reject ) => {
64
- try {
65
- resolve (evaluate (expr , context ));
66
- } catch (error ) {
67
- reject (error );
68
- }
69
- });
70
- }
71
-
72
- // Use with async/await
73
- const result = await asyncEvaluate (' x + y' , { x: 10 , y: 20 }); // returns 30
74
- ```
75
-
76
- ### Registering Custom Functions
57
+ ### Registering and Calling Functions
77
58
78
59
``` typescript
79
60
import { register , evaluate } from ' @antv/expr' ;
80
61
81
- // Register custom functions
82
- register (' sum' , (... args ) => args .reduce ((a , b ) => a + b , 0 ));
83
- register (' average' , (array ) => array .reduce ((a , b ) => a + b , 0 ) / array .length );
62
+ // Register functions
63
+ register (' formatCurrency' , (amount ) => ` $${amount .toFixed (2 )} ` );
84
64
85
- // Use custom functions in expressions
86
- const result = evaluate (' @sum(1, 2, 3, 4)' ); // returns 10
87
- const avg = evaluate (' @average(data.values)' , {
88
- data: { values: [10 , 20 , 30 , 40 ] }
89
- }); // returns 25
90
- ```
65
+ // Function call with arguments
66
+ const result = evaluate (' @max(a, b, c)' , { a: 5 , b: 9 , c: 2 }); // returns 9
91
67
92
- ## Supported Syntax
68
+ // Expression as function arguments
69
+ const result = evaluate (' @formatCurrency(price * quantity)' , {
70
+ price: 10.5 , quantity: 3
71
+ }); // returns '$31.50'
72
+ ```
73
+ Build-in Functions: ` abs ` , ` ceil ` , ` floor ` , ` round ` , ` sqrt ` , ` pow ` , ` max ` , ` min ` .
93
74
94
75
### Variable References
95
76
@@ -155,26 +136,32 @@ const result = evaluate('score >= 90 ? "A" : score >= 80 ? "B" : "C"', {
155
136
}); // returns 'B'
156
137
```
157
138
158
- ### Function Calls
139
+ ### Timeout Handling
140
+
141
+ You can implement timeout handling by wrapping your evaluation in a ` Promise.race ` with a timeout:
159
142
160
143
``` typescript
161
- import { register , evaluate } from ' @antv/expr' ;
144
+ import { evaluate } from " @antv/expr" ;
162
145
163
- // Register functions
164
- register (' max' , Math .max );
165
- register (' formatCurrency' , (amount ) => ` $${amount .toFixed (2 )} ` );
146
+ // Create a function that evaluates with a timeout
147
+ function evaluateWithTimeout(expr , context , timeoutMs ) {
148
+ const evaluationPromise = new Promise ((resolve ) => {
149
+ resolve (evaluate (expr , context ));
150
+ });
166
151
167
- // Function call with arguments
168
- const result = evaluate (' @max(a, b, c)' , { a: 5 , b: 9 , c: 2 }); // returns 9
152
+ const timeoutPromise = new Promise ((_ , reject ) => {
153
+ setTimeout (
154
+ () => reject (new Error (` Evaluation timed out after ${timeoutMs }ms ` )),
155
+ timeoutMs ,
156
+ );
157
+ });
169
158
170
- // Expression as function arguments
171
- const result = evaluate (' @formatCurrency(price * quantity)' , {
172
- price: 10.5 , quantity: 3
173
- }); // returns '$31.50'
159
+ return Promise .race ([evaluationPromise , timeoutPromise ]);
160
+ }
174
161
```
175
- ** Default Global Functions:** ` ['abs', 'ceil', 'floor', 'round', 'sqrt', 'pow', 'max', 'min'] `
176
162
177
- ## Benchmarks
163
+
164
+ ## 🚀Benchmarks
178
165
179
166
Performance comparison of different evaluation methods: (baseline: new Function)
180
167
@@ -191,64 +178,23 @@ gantt
191
178
axisFormat %s
192
179
193
180
section Simple
194
- evaluate after compile :done, 0, 159
195
- evaluate without compile :done, 0, 636
181
+ expr evaluate after compile :done, 0, 159
182
+ expr evaluate without compile :done, 0, 636
196
183
expr-eval Parser :done, 0, 2394
197
184
198
185
section Medium
199
- evaluate after compile :done, 0, 216
200
- evaluate without compile :done, 0, 981
186
+ expr evaluate after compile :done, 0, 216
187
+ expr evaluate without compile :done, 0, 981
201
188
expr-eval Parser :done, 0, 3781
202
189
203
190
section Complex
204
- evaluate after compile :done, 0, 159
205
- evaluate without compile :done, 0, 489
191
+ expr evaluate after compile :done, 0, 159
192
+ expr evaluate without compile :done, 0, 489
206
193
expr-eval Parser :done, 0, 3274
207
194
```
208
195
209
- ## Advanced Usage
210
-
211
- ### Timeout Handling
212
-
213
- You can implement timeout handling by wrapping your evaluation in a Promise.race with a timeout:
214
-
215
- ``` typescript
216
- import { evaluate } from " @antv/expr" ;
217
-
218
- // Create a function that evaluates with a timeout
219
- function evaluateWithTimeout(expr , context , timeoutMs ) {
220
- const evaluationPromise = new Promise ((resolve , reject ) => {
221
- try {
222
- const result = evaluate (expr , context );
223
- resolve (result );
224
- } catch (error ) {
225
- reject (error );
226
- }
227
- });
228
-
229
- const timeoutPromise = new Promise ((_ , reject ) => {
230
- setTimeout (
231
- () => reject (new Error (` Evaluation timed out after ${timeoutMs }ms ` )),
232
- timeoutMs ,
233
- );
234
- });
235
-
236
- return Promise .race ([evaluationPromise , timeoutPromise ]);
237
- }
238
- ```
239
- ## Security Features
240
-
241
- This library is designed with security in mind:
242
-
243
- - ✅ No access to global objects (` window ` , ` global ` , etc.)
244
- - ✅ No access to prototype chain
245
- - ✅ No use of ` eval ` or ` Function ` constructor
246
- - ✅ Expression execution has timeout protection
247
- - ✅ Configurable keyword blacklist
248
196
249
- ## API Reference
250
-
251
- ### Core Functions
197
+ ## 📮API Reference
252
198
253
199
#### ` evaluate(expression: string, context?: object): any `
254
200
@@ -265,23 +211,16 @@ Synchronously compiles an expression, returning a function that can be used mult
265
211
- ` expression ` : The expression string to compile
266
212
- Returns: A function that accepts a context object and returns the evaluation result
267
213
268
- ### Registration
269
-
270
214
#### ` register(name: string, fn: Function): void `
271
215
272
216
Registers a custom function that can be used in expressions.
273
217
274
218
- ` name ` : Function name (used with @ prefix in expressions)
275
219
- ` fn ` : Function implementation
276
220
277
- ### Error Handling
278
-
279
221
All evaluation errors throw an ` ExpressionError ` type exception with detailed error information.
280
222
281
- ## Contributing
282
-
283
- Contributions are welcome! Please feel free to submit issues or pull requests.
284
223
285
224
## License
286
225
287
- MIT
226
+ MIT
0 commit comments