Skip to content

Commit 2abb65d

Browse files
committed
Remove async
1 parent 1e3d439 commit 2abb65d

16 files changed

Lines changed: 378 additions & 629 deletions

CHANGELOG.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,28 @@ This project adheres to [Semantic Versioning](http://semver.org/).
66

77
Nothing yet!
88

9+
## [v3.0.0]
10+
11+
### BREAKING CHANGES
12+
13+
- **Removed async evaluation support**: Jexl now only supports synchronous evaluation
14+
- **Renamed methods**: `evalSync()` has been renamed to `eval()`. The async `eval()` method has been removed.
15+
- **Removed PromiseSync class**: Internal implementation detail removed
16+
- **Synchronous transforms/functions only**: Custom transforms and functions must now be synchronous. They should return values directly rather than Promises.
17+
18+
### Changed
19+
20+
- Simplified codebase by removing Promise/PromiseSync abstraction layer
21+
- All evaluation is now synchronous, improving performance and simplifying error handling
22+
- Errors are now thrown directly rather than being rejected Promises
23+
24+
### Migration Guide
25+
26+
- Replace `await jexl.eval(expr)` with `jexl.eval(expr)` (remove await)
27+
- Replace `jexl.evalSync(expr)` with `jexl.eval(expr)` (remove Sync suffix)
28+
- Update custom transforms/functions to be synchronous
29+
- Replace `.catch()` error handling with `try/catch` blocks
30+
931
## [v2.3.0]
1032

1133
### Added

README.md

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,30 +16,30 @@ const context = {
1616
}
1717

1818
// Template strings with interpolation
19-
jexl.evalSync('`Hello ${name.first} ${name.last}`', context)
19+
jexl.eval('`Hello ${name.first} ${name.last}`', context)
2020
// "Hello Sterling Archer"
2121

22-
jexl.evalSync('`Age in 5 years: ${age + 5}`', context)
22+
jexl.eval('`Age in 5 years: ${age + 5}`', context)
2323
// "Age in 5 years: 41"
2424

2525
// Filter arrays
26-
jexl.evalSync('assoc[.first == "Lana"].last', context)
26+
jexl.eval('assoc[.first == "Lana"].last', context)
2727
// "Kane"
2828

2929
// Math operations
30-
jexl.evalSync('age * (3 - 1)', context)
30+
jexl.eval('age * (3 - 1)', context)
3131
// 72
3232

3333
// String concatenation
34-
jexl.evalSync('name.first + " " + name.last', context)
34+
jexl.eval('name.first + " " + name.last', context)
3535
// "Sterling Archer"
3636

3737
// Conditional logic
38-
jexl.evalSync('age > 62 ? "retired" : "working"', context)
38+
jexl.eval('age > 62 ? "retired" : "working"', context)
3939
// "working"
4040

4141
// Array indexes
42-
jexl.evalSync('assoc[1].first', context)
42+
jexl.eval('assoc[1].first', context)
4343
// "Cyril"
4444
```
4545

@@ -63,17 +63,17 @@ Template strings use backticks and support expression interpolation with `${}`:
6363
```javascript
6464
const context = { name: 'World', price: 10, qty: 3 }
6565

66-
jexl.evalSync('`Hello ${name}!`', context)
66+
jexl.eval('`Hello ${name}!`', context)
6767
// "Hello World!"
6868

69-
jexl.evalSync('`Total: $${price * qty}`', context)
69+
jexl.eval('`Total: $${price * qty}`', context)
7070
// "Total: $30"
7171

7272
// Escape backticks and dollar signs with backslash
73-
jexl.evalSync('`Code: \\`example\\``')
73+
jexl.eval('`Code: \\`example\\``')
7474
// "Code: `example`"
7575

76-
jexl.evalSync('`Price: \\$100`')
76+
jexl.eval('`Price: \\$100`')
7777
// "Price: $100"
7878
```
7979

@@ -103,10 +103,10 @@ const context = {
103103
lastEx: 2
104104
}
105105

106-
jexl.evalSync('name.first', context) // "Malory"
107-
jexl.evalSync('name["last"]', context) // "Archer"
108-
jexl.evalSync('exes[2]', context) // "Burt"
109-
jexl.evalSync('exes[lastEx - 1]', context) // "Len"
106+
jexl.eval('name.first', context) // "Malory"
107+
jexl.eval('name["last"]', context) // "Archer"
108+
jexl.eval('exes[2]', context) // "Burt"
109+
jexl.eval('exes[lastEx - 1]', context) // "Len"
110110
```
111111

112112
### Filtering Collections
@@ -123,13 +123,13 @@ const context = {
123123
]
124124
}
125125

126-
jexl.evalSync('employees[.first == "Sterling"]', context)
126+
jexl.eval('employees[.first == "Sterling"]', context)
127127
// [{ first: 'Sterling', last: 'Archer', age: 36 }]
128128

129-
jexl.evalSync('employees[.age >= 30 && .age < 40]', context)
129+
jexl.eval('employees[.age >= 30 && .age < 40]', context)
130130
// [{ first: 'Sterling', ... }, { first: 'Lana', ... }]
131131

132-
jexl.evalSync('employees[.last == "Kane"].first', context)
132+
jexl.eval('employees[.last == "Kane"].first', context)
133133
// "Lana"
134134
```
135135

@@ -141,10 +141,10 @@ Apply transforms to values using the pipe operator:
141141
jexl.addTransform('upper', (val) => val.toUpperCase())
142142
jexl.addTransform('split', (val, char) => val.split(char))
143143

144-
jexl.evalSync('"hello"|upper')
144+
jexl.eval('"hello"|upper')
145145
// "HELLO"
146146

147-
jexl.evalSync('"firstName lastName"|split(" ")[0]')
147+
jexl.eval('"firstName lastName"|split(" ")[0]')
148148
// "firstName"
149149
```
150150

@@ -156,10 +156,10 @@ Call functions in expressions:
156156
jexl.addFunction('min', Math.min)
157157
jexl.addFunction('max', Math.max)
158158

159-
jexl.evalSync('min(5, 2, 9)')
159+
jexl.eval('min(5, 2, 9)')
160160
// 2
161161

162-
jexl.evalSync('max(temperature, threshold)')
162+
jexl.eval('max(temperature, threshold)')
163163
// evaluates with context
164164
```
165165

@@ -168,10 +168,10 @@ jexl.evalSync('max(temperature, threshold)')
168168
Separate multiple expressions with semicolons. The result is the value of the last expression:
169169

170170
```javascript
171-
jexl.evalSync('5; 10; 15')
171+
jexl.eval('5; 10; 15')
172172
// 15
173173

174-
jexl.evalSync('1 + 1; 2 + 2; 3 + 3')
174+
jexl.eval('1 + 1; 2 + 2; 3 + 3')
175175
// 6
176176
```
177177

@@ -180,17 +180,17 @@ jexl.evalSync('1 + 1; 2 + 2; 3 + 3')
180180
Assign values to variables using `=` (no `let`, `var`, or `const` needed). Assignments mutate the context and return the assigned value:
181181

182182
```javascript
183-
jexl.evalSync('x = 5')
183+
jexl.eval('x = 5')
184184
// 5
185185

186-
jexl.evalSync('x = 5; x * 2')
186+
jexl.eval('x = 5; x * 2')
187187
// 10
188188

189-
jexl.evalSync('x = 5; y = 10; x + y')
189+
jexl.eval('x = 5; y = 10; x + y')
190190
// 15
191191

192192
const context = {}
193-
jexl.evalSync('x = 5; y = x * 2; y', context)
193+
jexl.eval('x = 5; y = x * 2; y', context)
194194
// 10
195195
// context is now { x: 5, y: 10 }
196196
```
@@ -200,15 +200,12 @@ jexl.evalSync('x = 5; y = x * 2; y', context)
200200
```javascript
201201
import jexl from '@jbrowse/jexl'
202202

203-
// Synchronous evaluation
204-
const result = jexl.evalSync('expression', context)
205-
206-
// Asynchronous evaluation (supports async transforms/functions)
207-
const result = await jexl.eval('expression', context)
203+
// Evaluate an expression
204+
const result = jexl.eval('expression', context)
208205

209206
// Compile once, evaluate many times
210207
const expr = jexl.compile('name.first + " " + name.last')
211-
expr.evalSync({ name: { first: 'John', last: 'Doe' } })
208+
const result = expr.eval({ name: { first: 'John', last: 'Doe' } })
212209
```
213210

214211
## License

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@jbrowse/jexl",
3-
"version": "2.3.1",
3+
"version": "3.0.0",
44
"description": "A fork of the jexl lang for jbrowse",
55
"type": "module",
66
"types": "./dist/index.d.ts",

src/Expression.ts

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
*/
55

66
import Lexer from './Lexer.ts'
7-
import PromiseSync from './PromiseSync.ts'
87
import Evaluator from './evaluator/Evaluator.ts'
98
import Parser from './parser/Parser.ts'
109

@@ -15,8 +14,6 @@ interface Grammar {
1514
[key: string]: any
1615
}
1716

18-
type PromiseConstructor = typeof Promise | typeof PromiseSync
19-
2017
class Expression {
2118
_grammar: Grammar
2219
_exprStr: string
@@ -44,44 +41,16 @@ class Expression {
4441
}
4542

4643
/**
47-
* Asynchronously evaluates the expression within an optional context.
48-
* @param {Object} [context] A mapping of variables to values, which will be
49-
* made accessible to the Jexl expression when evaluating it
50-
* @returns {Promise<*>} resolves with the result of the evaluation.
51-
*/
52-
eval(context = {}) {
53-
return this._eval(context, Promise)
54-
}
55-
56-
/**
57-
* Synchronously evaluates the expression within an optional context.
44+
* Evaluates the expression within an optional context.
5845
* @param {Object} [context] A mapping of variables to values, which will be
5946
* made accessible to the Jexl expression when evaluating it
6047
* @returns {*} the result of the evaluation.
6148
* @throws {*} on error
6249
*/
63-
evalSync(context = {}) {
64-
const res = this._eval(context, PromiseSync as any) as PromiseSync
65-
if (res.error) {
66-
if (res.error instanceof Error) {
67-
throw res.error
68-
}
69-
throw new Error(typeof res.error === 'string' ? res.error : JSON.stringify(res.error))
70-
}
71-
return res.value
72-
}
73-
74-
_eval(context: any, promise: PromiseConstructor) {
75-
return promise.resolve().then(() => {
76-
const ast = this._getAst()
77-
const evaluator = new Evaluator(
78-
this._grammar,
79-
context,
80-
undefined,
81-
promise
82-
)
83-
return evaluator.eval(ast!)
84-
})
50+
eval(context = {}) {
51+
const ast = this._getAst()
52+
const evaluator = new Evaluator(this._grammar, context)
53+
return evaluator.eval(ast!)
8554
}
8655

8756
_getAst() {

src/Jexl.ts

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,11 @@ class Jexl {
3939
* @param {number} precedence The operator's precedence
4040
* @param {function} fn A function to run to calculate the result. The function
4141
* will be called with two arguments: left and right, denoting the values
42-
* on either side of the operator. It should return either the resulting
43-
* value, or a Promise that resolves with the resulting value.
42+
* on either side of the operator. It should return the resulting value.
4443
* @param {boolean} [manualEval] If true, the `left` and `right` arguments
4544
* will be wrapped in objects with an `eval` function. Calling
46-
* left.eval() or right.eval() will return a promise that resolves to
47-
* that operand's actual value. This is useful to conditionally evaluate
48-
* operands.
45+
* left.eval() or right.eval() will return that operand's actual value.
46+
* This is useful to conditionally evaluate operands.
4947
*/
5048
addBinaryOp(
5149
operator: string,
@@ -88,8 +86,7 @@ class Jexl {
8886
* @param {string} operator The operator string to be added
8987
* @param {function} fn A function to run to calculate the result. The function
9088
* will be called with one argument: the literal value to the right of the
91-
* operator. It should return either the resulting value, or a Promise
92-
* that resolves with the resulting value.
89+
* operator. It should return the resulting value.
9390
*/
9491
addUnaryOp(operator: string, fn: (right: any) => any) {
9592
this._addGrammarElement(operator, {
@@ -163,28 +160,16 @@ class Jexl {
163160
}
164161

165162
/**
166-
* Asynchronously evaluates a Jexl string within an optional context.
167-
* @param {string} expression The Jexl expression to be evaluated
168-
* @param {Object} [context] A mapping of variables to values, which will be
169-
* made accessible to the Jexl expression when evaluating it
170-
* @returns {Promise<*>} resolves with the result of the evaluation.
171-
*/
172-
eval(expression: string, context = {}) {
173-
const exprObj = this.createExpression(expression)
174-
return exprObj.eval(context)
175-
}
176-
177-
/**
178-
* Synchronously evaluates a Jexl string within an optional context.
163+
* Evaluates a Jexl string within an optional context.
179164
* @param {string} expression The Jexl expression to be evaluated
180165
* @param {Object} [context] A mapping of variables to values, which will be
181166
* made accessible to the Jexl expression when evaluating it
182167
* @returns {*} the result of the evaluation.
183168
* @throws {*} on error
184169
*/
185-
evalSync(expression: string, context = {}) {
170+
eval(expression: string, context = {}) {
186171
const exprObj = this.createExpression(expression)
187-
return exprObj.evalSync(context)
172+
return exprObj.eval(context)
188173
}
189174

190175
/**

0 commit comments

Comments
 (0)