ecma-evaluator 2.0.8 → 2.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -494
- package/README.zh-CN.md +10 -493
- package/dist/cjs/Evaluator.d.cts +15 -2
- package/dist/cjs/TemplateParser.d.cts +12 -0
- package/dist/cjs/index.cjs +349 -27
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/esm/Evaluator.d.mts +15 -2
- package/dist/esm/TemplateParser.d.mts +12 -0
- package/dist/esm/index.mjs +349 -27
- package/dist/esm/index.mjs.map +1 -1
- package/package.json +74 -67
package/README.md
CHANGED
|
@@ -11,13 +11,9 @@ English | [简体中文](./README.zh-CN.md)
|
|
|
11
11
|
|
|
12
12
|
## Features
|
|
13
13
|
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
- 🎯 **Rich feature set** - Most JS expressions/functions
|
|
18
|
-
- 🔒 **No eval()** - Does not use `eval()` or `Function()` constructor
|
|
19
|
-
- 💪 **TypeScript support** - Includes TypeScript type definitions
|
|
20
|
-
- 📝 **Template strings** - Evaluate expressions within template strings using `{{ }}` syntax
|
|
14
|
+
- Sandboxed evaluation without `eval()` or `Function()`
|
|
15
|
+
- Supports JavaScript expressions and `{{ }}` templates
|
|
16
|
+
- TypeScript definitions included
|
|
21
17
|
|
|
22
18
|
## Installation
|
|
23
19
|
|
|
@@ -30,494 +26,14 @@ npm install ecma-evaluator
|
|
|
30
26
|
```js
|
|
31
27
|
import { evalExpression, evalTemplate } from "ecma-evaluator";
|
|
32
28
|
|
|
33
|
-
//
|
|
34
|
-
|
|
35
|
-
console.log(result); // Output: 7
|
|
36
|
-
|
|
37
|
-
// Evaluate template
|
|
38
|
-
const text = evalTemplate("Hello {{ name }}!", { name: "World" });
|
|
39
|
-
console.log(text); // Output: "Hello World!"
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## API Reference
|
|
43
|
-
|
|
44
|
-
### `evalExpression(expression, context?)`
|
|
45
|
-
|
|
46
|
-
Evaluates a JavaScript expression with an optional context.
|
|
47
|
-
|
|
48
|
-
**Parameters:**
|
|
49
|
-
|
|
50
|
-
- `expression` (string): The JavaScript expression to evaluate
|
|
51
|
-
- `context` (object, optional): An object containing variables to use in the expression
|
|
52
|
-
|
|
53
|
-
**Returns:** The result of evaluating the expression
|
|
54
|
-
|
|
55
|
-
**Example:**
|
|
56
|
-
|
|
57
|
-
```js
|
|
58
|
-
import { evalExpression } from "ecma-evaluator";
|
|
59
|
-
|
|
60
|
-
// Basic arithmetic
|
|
61
|
-
evalExpression("2 + 3 * 4"); // 14
|
|
62
|
-
|
|
63
|
-
// With variables
|
|
64
|
-
evalExpression("x + y", { x: 10, y: 20 }); // 30
|
|
65
|
-
|
|
66
|
-
// Using built-in functions
|
|
67
|
-
evalExpression("Math.max(a, b, c)", { a: 5, b: 15, c: 10 }); // 15
|
|
68
|
-
|
|
69
|
-
// String operations
|
|
70
|
-
evalExpression("greeting + ', ' + name", {
|
|
71
|
-
greeting: "Hello",
|
|
72
|
-
name: "Alice",
|
|
73
|
-
}); // "Hello, Alice"
|
|
74
|
-
|
|
75
|
-
// Array methods
|
|
76
|
-
evalExpression("[1, 2, 3].map(x => x * 2)"); // [2, 4, 6]
|
|
77
|
-
|
|
78
|
-
// Conditional expressions
|
|
79
|
-
evalExpression("score >= 60 ? 'Pass' : 'Fail'", { score: 75 }); // "Pass"
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
### `evalTemplate(template, context?, templateParserOptions?)`
|
|
83
|
-
|
|
84
|
-
Evaluates a template string by replacing `{{ expression }}` patterns with their evaluated values.
|
|
85
|
-
|
|
86
|
-
**Parameters:**
|
|
87
|
-
|
|
88
|
-
- `template` (string): The template string to evaluate
|
|
89
|
-
- `context` (object, optional): An object containing variables to use in the template
|
|
90
|
-
- `templateParserOptions` (object, optional): Options for the template parser
|
|
91
|
-
|
|
92
|
-
**Returns:** The evaluated template string
|
|
93
|
-
|
|
94
|
-
**Example:**
|
|
95
|
-
|
|
96
|
-
```js
|
|
97
|
-
import { evalTemplate } from "ecma-evaluator";
|
|
98
|
-
|
|
99
|
-
// Basic variable replacement
|
|
100
|
-
evalTemplate("Hello, {{ name }}!", { name: "World" });
|
|
101
|
-
// Output: "Hello, World!"
|
|
102
|
-
|
|
103
|
-
// Multiple expressions
|
|
104
|
-
evalTemplate("{{ a }} + {{ b }} = {{ a + b }}", { a: 10, b: 20 });
|
|
105
|
-
// Output: "10 + 20 = 30"
|
|
106
|
-
|
|
107
|
-
// Complex expressions
|
|
108
|
-
evalTemplate("The sum is {{ [1, 2, 3].reduce((a, b) => a + b, 0) }}");
|
|
109
|
-
// Output: "The sum is 6"
|
|
110
|
-
|
|
111
|
-
// Template literals within expressions
|
|
112
|
-
evalTemplate("{{ `Hello ${name}, welcome!` }}", { name: "Alice" });
|
|
113
|
-
// Output: "Hello Alice, welcome!"
|
|
114
|
-
|
|
115
|
-
// Date formatting
|
|
116
|
-
evalTemplate("Today is {{ new Date().toLocaleDateString() }}");
|
|
117
|
-
// Output: "Today is 11/18/2025" (varies by locale)
|
|
118
|
-
|
|
119
|
-
// Conditional rendering
|
|
120
|
-
evalTemplate("Status: {{ isActive ? 'Active' : 'Inactive' }}", { isActive: true });
|
|
121
|
-
// Output: "Status: Active"
|
|
122
|
-
|
|
123
|
-
// Optional chaining
|
|
124
|
-
evalTemplate("Value: {{ obj?.prop?.value ?? 'N/A' }}", { obj: null });
|
|
125
|
-
// Output: "Value: N/A"
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
### Error Handling
|
|
129
|
-
|
|
130
|
-
When an undefined variable is referenced in a template, it's replaced with `"undefined"` instead of throwing an error:
|
|
131
|
-
|
|
132
|
-
```js
|
|
133
|
-
evalTemplate("Hello {{ name }}!", {}); // "Hello undefined!"
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
For other errors (syntax errors, type errors, etc.), an exception will be thrown:
|
|
137
|
-
|
|
138
|
-
```js
|
|
139
|
-
evalTemplate("{{ 1 + }}", {}); // Throws SyntaxError
|
|
140
|
-
evalTemplate("{{ obj.prop }}", { obj: null }); // Throws TypeError
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
## Supported JavaScript Features
|
|
144
|
-
|
|
145
|
-
### Operators
|
|
146
|
-
|
|
147
|
-
#### Arithmetic Operators
|
|
148
|
-
|
|
149
|
-
```js
|
|
150
|
-
evalExpression("10 + 5"); // 15 (addition)
|
|
151
|
-
evalExpression("10 - 5"); // 5 (subtraction)
|
|
152
|
-
evalExpression("10 * 5"); // 50 (multiplication)
|
|
153
|
-
evalExpression("10 / 5"); // 2 (division)
|
|
154
|
-
evalExpression("10 % 3"); // 1 (modulo)
|
|
155
|
-
evalExpression("2 ** 3"); // 8 (exponentiation)
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
#### Comparison Operators
|
|
159
|
-
|
|
160
|
-
```js
|
|
161
|
-
evalExpression("5 > 3"); // true
|
|
162
|
-
evalExpression("5 >= 5"); // true
|
|
163
|
-
evalExpression("5 < 3"); // false
|
|
164
|
-
evalExpression("5 <= 5"); // true
|
|
165
|
-
evalExpression("5 == '5'"); // true (loose equality)
|
|
166
|
-
evalExpression("5 === '5'"); // false (strict equality)
|
|
167
|
-
evalExpression("5 != '5'"); // false (loose inequality)
|
|
168
|
-
evalExpression("5 !== '5'"); // true (strict inequality)
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
#### Logical Operators
|
|
172
|
-
|
|
173
|
-
```js
|
|
174
|
-
evalExpression("true && false"); // false (AND)
|
|
175
|
-
evalExpression("true || false"); // true (OR)
|
|
176
|
-
evalExpression("null ?? 'default'"); // "default" (nullish coalescing)
|
|
177
|
-
evalExpression("!true"); // false (NOT)
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
#### Bitwise Operators
|
|
181
|
-
|
|
182
|
-
```js
|
|
183
|
-
evalExpression("5 & 3"); // 1 (AND)
|
|
184
|
-
evalExpression("5 | 3"); // 7 (OR)
|
|
185
|
-
evalExpression("5 ^ 3"); // 6 (XOR)
|
|
186
|
-
evalExpression("~5"); // -6 (NOT)
|
|
187
|
-
evalExpression("5 << 1"); // 10 (left shift)
|
|
188
|
-
evalExpression("5 >> 1"); // 2 (right shift)
|
|
189
|
-
evalExpression("5 >>> 1"); // 2 (unsigned right shift)
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
#### Unary Operators
|
|
193
|
-
|
|
194
|
-
```js
|
|
195
|
-
evalExpression("-5"); // -5 (negation)
|
|
196
|
-
evalExpression("+5"); // 5 (unary plus)
|
|
197
|
-
evalExpression("typeof 5"); // "number"
|
|
198
|
-
evalExpression("void 0"); // undefined
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
### Data Types
|
|
202
|
-
|
|
203
|
-
#### Literals
|
|
204
|
-
|
|
205
|
-
```js
|
|
206
|
-
evalExpression("42"); // Number
|
|
207
|
-
evalExpression("'hello'"); // String
|
|
208
|
-
evalExpression("true"); // Boolean
|
|
209
|
-
evalExpression("null"); // null
|
|
210
|
-
evalExpression("undefined"); // undefined
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
#### Arrays
|
|
214
|
-
|
|
215
|
-
```js
|
|
216
|
-
evalExpression("[1, 2, 3]"); // [1, 2, 3]
|
|
217
|
-
evalExpression("[1, 2, 3][1]"); // 2
|
|
218
|
-
evalExpression("[1, 2, 3].length"); // 3
|
|
219
|
-
evalExpression("[1, 2, 3].map(x => x * 2)"); // [2, 4, 6]
|
|
220
|
-
evalExpression("[1, 2, 3].filter(x => x > 1)"); // [2, 3]
|
|
221
|
-
evalExpression("[1, 2, 3].reduce((a, b) => a + b, 0)"); // 6
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
#### Objects
|
|
225
|
-
|
|
226
|
-
```js
|
|
227
|
-
evalExpression("{ a: 1, b: 2 }"); // { a: 1, b: 2 }
|
|
228
|
-
evalExpression("({ a: 1, b: 2 }).a"); // 1
|
|
229
|
-
evalExpression("({ a: 1, b: 2 })['b']"); // 2
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
#### Template Literals
|
|
233
|
-
|
|
234
|
-
```js
|
|
235
|
-
evalExpression("`Hello ${'World'}`"); // "Hello World"
|
|
236
|
-
evalExpression("`2 + 2 = ${2 + 2}`", {}); // "2 + 2 = 4"
|
|
237
|
-
evalExpression("`Hello ${name}`", { name: "Bob" }); // "Hello Bob"
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
### Functions
|
|
241
|
-
|
|
242
|
-
#### Arrow Functions
|
|
243
|
-
|
|
244
|
-
```js
|
|
245
|
-
evalExpression("((x) => x * 2)(5)"); // 10
|
|
246
|
-
evalExpression("[1, 2, 3].map(x => x * 2)"); // [2, 4, 6]
|
|
247
|
-
evalExpression("((a, b) => a + b)(3, 4)"); // 7
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
#### Built-in Objects and Functions
|
|
251
|
-
|
|
252
|
-
```js
|
|
253
|
-
// Math
|
|
254
|
-
evalExpression("Math.max(1, 2, 3)"); // 3
|
|
255
|
-
evalExpression("Math.min(1, 2, 3)"); // 1
|
|
256
|
-
evalExpression("Math.round(4.7)"); // 5
|
|
257
|
-
evalExpression("Math.floor(4.7)"); // 4
|
|
258
|
-
evalExpression("Math.ceil(4.3)"); // 5
|
|
259
|
-
evalExpression("Math.abs(-5)"); // 5
|
|
260
|
-
evalExpression("Math.sqrt(16)"); // 4
|
|
261
|
-
|
|
262
|
-
// String methods
|
|
263
|
-
evalExpression("'hello'.toUpperCase()"); // "HELLO"
|
|
264
|
-
evalExpression("'HELLO'.toLowerCase()"); // "hello"
|
|
265
|
-
evalExpression("'hello world'.split(' ')"); // ["hello", "world"]
|
|
266
|
-
|
|
267
|
-
// Array methods (non-mutating only)
|
|
268
|
-
evalExpression("[1,2,3].join(', ')"); // "1, 2, 3"
|
|
269
|
-
evalExpression("[1,2,3].slice(1)"); // [2, 3]
|
|
270
|
-
evalExpression("[1,2,3].concat([4,5])"); // [1, 2, 3, 4, 5]
|
|
271
|
-
|
|
272
|
-
// JSON
|
|
273
|
-
evalExpression("JSON.stringify({ a: 1 })"); // '{"a":1}'
|
|
274
|
-
evalExpression("JSON.parse('{\"a\":1}')"); // { a: 1 }
|
|
275
|
-
|
|
276
|
-
// Date
|
|
277
|
-
evalExpression("new Date(0).getTime()"); // 0
|
|
278
|
-
evalExpression("new Date().getFullYear()"); // current year
|
|
279
|
-
|
|
280
|
-
// Object methods
|
|
281
|
-
evalExpression("Object.keys({ a: 1, b: 2 })"); // ["a", "b"]
|
|
282
|
-
evalExpression("Object.values({ a: 1, b: 2 })"); // [1, 2]
|
|
283
|
-
|
|
284
|
-
// Number methods
|
|
285
|
-
evalExpression("Number.parseInt('42')"); // 42
|
|
286
|
-
evalExpression("Number.parseFloat('3.14')"); // 3.14
|
|
287
|
-
evalExpression("Number.isNaN(NaN)"); // true
|
|
288
|
-
evalExpression("Number.isFinite(42)"); // true
|
|
289
|
-
|
|
290
|
-
// Global functions
|
|
291
|
-
evalExpression("isNaN(NaN)"); // true
|
|
292
|
-
evalExpression("isFinite(Infinity)"); // false
|
|
293
|
-
evalExpression("parseInt('42')"); // 42
|
|
294
|
-
evalExpression("parseFloat('3.14')"); // 3.14
|
|
295
|
-
evalExpression("encodeURIComponent('hello world')"); // "hello%20world"
|
|
296
|
-
evalExpression("decodeURIComponent('hello%20world')"); // "hello world"
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
### Advanced Features
|
|
300
|
-
|
|
301
|
-
#### Conditional (Ternary) Operator
|
|
302
|
-
|
|
303
|
-
```js
|
|
304
|
-
evalExpression("5 > 3 ? 'yes' : 'no'"); // "yes"
|
|
305
|
-
evalExpression("age >= 18 ? 'adult' : 'minor'", { age: 20 }); // "adult"
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
#### Optional Chaining
|
|
309
|
-
|
|
310
|
-
```js
|
|
311
|
-
evalExpression("obj?.prop", { obj: null }); // undefined
|
|
312
|
-
evalExpression("obj?.prop?.value", { obj: {} }); // undefined
|
|
313
|
-
evalExpression("arr?.[0]", { arr: null }); // undefined
|
|
314
|
-
evalExpression("func?.()", { func: null }); // undefined
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
#### Member Access
|
|
318
|
-
|
|
319
|
-
```js
|
|
320
|
-
evalExpression("obj.prop", { obj: { prop: 42 } }); // 42
|
|
321
|
-
evalExpression("obj['prop']", { obj: { prop: 42 } }); // 42
|
|
322
|
-
evalExpression("arr[0]", { arr: [1, 2, 3] }); // 1
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
#### Constructor Expressions
|
|
326
|
-
|
|
327
|
-
```js
|
|
328
|
-
evalExpression("new Date(2024, 0, 1)"); // Date object
|
|
329
|
-
evalExpression("new Array(1, 2, 3)"); // [1, 2, 3]
|
|
330
|
-
evalExpression("new Set([1, 2, 2, 3])"); // Set {1, 2, 3}
|
|
331
|
-
evalExpression("new Map([['a', 1], ['b', 2]])"); // Map {"a" => 1, "b" => 2}
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
## Security Features
|
|
335
|
-
|
|
336
|
-
### Sandboxed Environment
|
|
337
|
-
|
|
338
|
-
`ecma-evaluator` runs expressions in a sandboxed environment with several security features:
|
|
339
|
-
|
|
340
|
-
1. **No access to `eval()` or `Function()` constructor** - Prevents dynamic code execution
|
|
341
|
-
2. **Blocked mutable methods** - Methods that mutate objects are blocked to prevent side effects:
|
|
342
|
-
|
|
343
|
-
- Array: `push`, `pop`, `shift`, `unshift`, `splice`, `reverse`, `sort`, `fill`, `copyWithin`
|
|
344
|
-
- Object: `freeze`, `defineProperty`, `defineProperties`, `preventExtensions`, `setPrototypeOf`, `assign`
|
|
345
|
-
- Set/Map: `add`, `set`, `delete`, `clear`
|
|
346
|
-
- Date: All setter methods (`setDate`, `setFullYear`, etc.)
|
|
347
|
-
- TypedArray: `set`, `fill`, `copyWithin`, `reverse`, `sort`
|
|
348
|
-
|
|
349
|
-
3. **No `delete` operator** - The `delete` operator is blocked as it's a mutating operation
|
|
350
|
-
4. **Limited global scope** - Only safe built-in objects are available (Math, JSON, Array, Object, etc.)
|
|
351
|
-
5. **No file system or network access** - Cannot access Node.js APIs or perform I/O operations
|
|
352
|
-
6. **No access to process or global variables** - Cannot access `process`, `global`, `require`, etc.
|
|
353
|
-
7. **Prevention of prototype pollution** - Accessing prototype properties (e.g., `__proto__`) is blocked
|
|
354
|
-
|
|
355
|
-
### Safe Built-in Objects
|
|
356
|
-
|
|
357
|
-
The following built-in objects are available in the sandboxed environment:
|
|
358
|
-
|
|
359
|
-
- **Numbers & Math**: `Number`, `Math`, `Infinity`, `NaN`, `isNaN`, `isFinite`, `parseInt`, `parseFloat`
|
|
360
|
-
- **Strings**: `String`, `encodeURI`, `encodeURIComponent`, `decodeURI`, `decodeURIComponent`
|
|
361
|
-
- **Data Structures**: `Array`, `Object`, `Set`, `WeakSet`, `Map`, `WeakMap`
|
|
362
|
-
- **Date & Time**: `Date`
|
|
363
|
-
- **JSON**: `JSON`
|
|
364
|
-
- **Types**: `Boolean`, `Symbol`, `BigInt`, `RegExp`
|
|
365
|
-
- **TypedArrays**: `Int8Array`, `Uint8Array`, `Int16Array`, `Uint16Array`, `Int32Array`, `Uint32Array`, `Float32Array`, `Float64Array`, `BigInt64Array`, `BigUint64Array`
|
|
366
|
-
- **Errors**: `Error`, `EvalError`, `RangeError`, `ReferenceError`, `SyntaxError`, `TypeError`, `URIError`
|
|
367
|
-
- **Promises**: `Promise`
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
### Error Prevention
|
|
371
|
-
|
|
372
|
-
```js
|
|
373
|
-
// ❌ These will throw errors:
|
|
374
|
-
evalExpression("arr.push(1)", { arr: [1, 2, 3] });
|
|
375
|
-
// Error: Array.prototype.push is not allow
|
|
376
|
-
|
|
377
|
-
evalExpression("new Function('return 1')");
|
|
378
|
-
// Error: Cannot use new with Function constructor
|
|
379
|
-
|
|
380
|
-
evalExpression("delete obj.prop", { obj: { prop: 1 } });
|
|
381
|
-
// Error: Delete operator is not allow
|
|
382
|
-
```
|
|
383
|
-
|
|
384
|
-
## Use Cases
|
|
385
|
-
|
|
386
|
-
### Configuration & Rules Engine
|
|
387
|
-
|
|
388
|
-
```js
|
|
389
|
-
// Evaluate business rules
|
|
390
|
-
const rule = "age >= 18 && country === 'US'";
|
|
391
|
-
const isEligible = evalExpression(rule, { age: 25, country: "US" }); // true
|
|
392
|
-
|
|
393
|
-
// Dynamic pricing
|
|
394
|
-
const priceFormula = "basePrice * (1 - discount / 100)";
|
|
395
|
-
const finalPrice = evalExpression(priceFormula, {
|
|
396
|
-
basePrice: 100,
|
|
397
|
-
discount: 20,
|
|
398
|
-
}); // 80
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
### Template Rendering
|
|
402
|
-
|
|
403
|
-
```js
|
|
404
|
-
// Email templates
|
|
405
|
-
const emailTemplate = `
|
|
406
|
-
Hello {{ user.name }},
|
|
407
|
-
|
|
408
|
-
Your order #{{ order.id }} has been {{ order.status }}.
|
|
409
|
-
Total: {{ order.total.toFixed(2) }}
|
|
410
|
-
|
|
411
|
-
Thank you for shopping with us!
|
|
412
|
-
`;
|
|
413
|
-
|
|
414
|
-
const email = evalTemplate(emailTemplate, {
|
|
415
|
-
user: { name: "John Doe" },
|
|
416
|
-
order: { id: 12345, status: "shipped", total: 99.99 },
|
|
417
|
-
});
|
|
418
|
-
|
|
419
|
-
// Dynamic content
|
|
420
|
-
const greeting = evalTemplate("Good {{ hour < 12 ? 'morning' : hour < 18 ? 'afternoon' : 'evening' }}, {{ name }}!", {
|
|
421
|
-
hour: new Date().getHours(),
|
|
422
|
-
name: "Alice",
|
|
423
|
-
});
|
|
424
|
-
```
|
|
425
|
-
|
|
426
|
-
### Data Transformation
|
|
427
|
-
|
|
428
|
-
```js
|
|
429
|
-
// Transform API responses
|
|
430
|
-
const transform = "data.items.filter(x => x.active).map(x => x.name)";
|
|
431
|
-
const result = evalExpression(transform, {
|
|
432
|
-
data: {
|
|
433
|
-
items: [
|
|
434
|
-
{ name: "Item 1", active: true },
|
|
435
|
-
{ name: "Item 2", active: false },
|
|
436
|
-
{ name: "Item 3", active: true },
|
|
437
|
-
],
|
|
438
|
-
},
|
|
439
|
-
}); // ["Item 1", "Item 3"]
|
|
440
|
-
```
|
|
441
|
-
|
|
442
|
-
### Form Validation
|
|
443
|
-
|
|
444
|
-
```js
|
|
445
|
-
// Conditional validation
|
|
446
|
-
const validationRule = "email.includes('@') && password.length >= 8";
|
|
447
|
-
const isValid = evalExpression(validationRule, {
|
|
448
|
-
email: "user@example.com",
|
|
449
|
-
password: "secretpassword",
|
|
450
|
-
}); // true
|
|
451
|
-
```
|
|
452
|
-
|
|
453
|
-
## Limitations
|
|
454
|
-
|
|
455
|
-
1. **No statements** - Only expressions are supported, not statements (no `if`, `for`, `while`, etc.)
|
|
456
|
-
2. **No variable assignment** - Cannot use assignment operators (`=`, `+=`, etc.)
|
|
457
|
-
3. **No mutable operations** - Mutable array/object methods are blocked
|
|
458
|
-
4. **No async operations** - Promises work but cannot use `await`
|
|
459
|
-
5. **No function declarations** - Only arrow functions in expressions are supported
|
|
460
|
-
6. **Limited error recovery** - Syntax errors will throw immediately
|
|
461
|
-
7. **No imports/requires** - Cannot import external modules
|
|
462
|
-
8. **Cloneable context only** - Context objects must be cloneable (no functions, DOM nodes, etc.)
|
|
463
|
-
|
|
464
|
-
## Advanced Usage
|
|
465
|
-
|
|
466
|
-
### Custom Evaluator Instance
|
|
467
|
-
|
|
468
|
-
```js
|
|
469
|
-
import { Evaluator } from "ecma-evaluator";
|
|
470
|
-
|
|
471
|
-
// Create a reusable evaluator with fixed context
|
|
472
|
-
const evaluator = new Evaluator({ x: 10, y: 20 });
|
|
473
|
-
|
|
474
|
-
// Evaluate multiple expressions with the same context
|
|
475
|
-
console.log(evaluator.evaluate("x + y")); // 30
|
|
476
|
-
console.log(evaluator.evaluate("x * y")); // 200
|
|
477
|
-
console.log(evaluator.evaluate("Math.max(x, y)")); // 20
|
|
478
|
-
```
|
|
479
|
-
|
|
480
|
-
### Custom Template Parser
|
|
481
|
-
|
|
482
|
-
```js
|
|
483
|
-
import { evalTemplate } from "ecma-evaluator";
|
|
484
|
-
|
|
485
|
-
evalTemplate(
|
|
486
|
-
"Hello ${ name }!",
|
|
487
|
-
{ name: "World" },
|
|
488
|
-
{
|
|
489
|
-
expressionStart: "${",
|
|
490
|
-
expressionEnd: "}",
|
|
491
|
-
preserveWhitespace: false,
|
|
492
|
-
}
|
|
493
|
-
);
|
|
494
|
-
// Output: "Hello World!"
|
|
29
|
+
evalExpression("a + b * c", { a: 1, b: 2, c: 3 }); // 7
|
|
30
|
+
evalTemplate("Hello {{ name }}!", { name: "World" }); // "Hello World!"
|
|
495
31
|
```
|
|
496
32
|
|
|
497
|
-
##
|
|
498
|
-
|
|
499
|
-
1. **Reuse evaluator instances** when evaluating multiple expressions with the same context
|
|
500
|
-
2. **Avoid complex nested expressions** - Break them into smaller parts if possible
|
|
501
|
-
3. **Cache parsed templates** if you're rendering the same template multiple times
|
|
502
|
-
4. **Use simple variable access** instead of complex property chains when possible
|
|
503
|
-
|
|
504
|
-
## TypeScript Support
|
|
505
|
-
|
|
506
|
-
The package includes TypeScript type definitions:
|
|
507
|
-
|
|
508
|
-
## Compatibility
|
|
509
|
-
|
|
510
|
-
Compatible with Nodejs and major browsers. For older environments, use Babel for transpilation and polyfills.
|
|
511
|
-
|
|
512
|
-
```js
|
|
513
|
-
import 'core-js/actual/structured-clone.js';
|
|
514
|
-
import 'core-js/actual/object/has-own.js';
|
|
515
|
-
```
|
|
516
|
-
|
|
517
|
-
## Contributing
|
|
518
|
-
|
|
519
|
-
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
33
|
+
## Documentation
|
|
520
34
|
|
|
521
|
-
|
|
35
|
+
- [Getting started](/guide/getting-started)
|
|
36
|
+
- [API, supported features, security, and usage reference](/guide/reference)
|
|
37
|
+
- [Online playground](/#playground)
|
|
522
38
|
|
|
523
|
-
|
|
39
|
+
See the [documentation site](https://axetroy.github.io/ecma-evaluator/).
|