@jbrowse/jexl 2.3.1
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/CHANGELOG.md +222 -0
- package/LICENSE.txt +19 -0
- package/README.md +216 -0
- package/dist/Expression.d.ts +38 -0
- package/dist/Expression.js +75 -0
- package/dist/Expression.js.map +1 -0
- package/dist/Jexl.d.ts +148 -0
- package/dist/Jexl.js +208 -0
- package/dist/Jexl.js.map +1 -0
- package/dist/Lexer.d.ts +130 -0
- package/dist/Lexer.js +321 -0
- package/dist/Lexer.js.map +1 -0
- package/dist/PromiseSync.d.ts +13 -0
- package/dist/PromiseSync.js +80 -0
- package/dist/PromiseSync.js.map +1 -0
- package/dist/evaluator/Evaluator.d.ts +92 -0
- package/dist/evaluator/Evaluator.js +153 -0
- package/dist/evaluator/Evaluator.js.map +1 -0
- package/dist/evaluator/handlers.d.ts +111 -0
- package/dist/evaluator/handlers.js +216 -0
- package/dist/evaluator/handlers.js.map +1 -0
- package/dist/grammar.d.ts +25 -0
- package/dist/grammar.js +179 -0
- package/dist/grammar.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/package.json +1 -0
- package/dist/parser/Parser.d.ts +112 -0
- package/dist/parser/Parser.js +233 -0
- package/dist/parser/Parser.js.map +1 -0
- package/dist/parser/handlers.d.ts +112 -0
- package/dist/parser/handlers.js +302 -0
- package/dist/parser/handlers.js.map +1 -0
- package/dist/parser/states.d.ts +47 -0
- package/dist/parser/states.js +195 -0
- package/dist/parser/states.js.map +1 -0
- package/dist/types.d.ts +77 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/esm/Expression.d.ts +38 -0
- package/esm/Expression.js +70 -0
- package/esm/Expression.js.map +1 -0
- package/esm/Jexl.d.ts +148 -0
- package/esm/Jexl.js +202 -0
- package/esm/Jexl.js.map +1 -0
- package/esm/Lexer.d.ts +130 -0
- package/esm/Lexer.js +319 -0
- package/esm/Lexer.js.map +1 -0
- package/esm/PromiseSync.d.ts +13 -0
- package/esm/PromiseSync.js +78 -0
- package/esm/PromiseSync.js.map +1 -0
- package/esm/evaluator/Evaluator.d.ts +92 -0
- package/esm/evaluator/Evaluator.js +118 -0
- package/esm/evaluator/Evaluator.js.map +1 -0
- package/esm/evaluator/handlers.d.ts +111 -0
- package/esm/evaluator/handlers.js +202 -0
- package/esm/evaluator/handlers.js.map +1 -0
- package/esm/grammar.d.ts +25 -0
- package/esm/grammar.js +175 -0
- package/esm/grammar.js.map +1 -0
- package/esm/index.d.ts +5 -0
- package/esm/index.js +9 -0
- package/esm/index.js.map +1 -0
- package/esm/parser/Parser.d.ts +112 -0
- package/esm/parser/Parser.js +198 -0
- package/esm/parser/Parser.js.map +1 -0
- package/esm/parser/handlers.d.ts +112 -0
- package/esm/parser/handlers.js +280 -0
- package/esm/parser/handlers.js.map +1 -0
- package/esm/parser/states.d.ts +47 -0
- package/esm/parser/states.js +159 -0
- package/esm/parser/states.js.map +1 -0
- package/esm/types.d.ts +77 -0
- package/esm/types.js +6 -0
- package/esm/types.js.map +1 -0
- package/package.json +67 -0
- package/src/Expression.ts +95 -0
- package/src/Jexl.ts +232 -0
- package/src/Lexer.ts +344 -0
- package/src/PromiseSync.ts +86 -0
- package/src/evaluator/Evaluator.ts +153 -0
- package/src/evaluator/handlers.ts +226 -0
- package/src/grammar.ts +200 -0
- package/src/index.ts +10 -0
- package/src/parser/Parser.ts +235 -0
- package/src/parser/handlers.ts +309 -0
- package/src/parser/states.ts +177 -0
- package/src/types.ts +107 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# Jexl Change Log
|
|
2
|
+
|
|
3
|
+
This project adheres to [Semantic Versioning](http://semver.org/).
|
|
4
|
+
|
|
5
|
+
## [development]
|
|
6
|
+
|
|
7
|
+
Nothing yet!
|
|
8
|
+
|
|
9
|
+
## [v2.3.0]
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Top-level expression functions, along with `jexl.addFunction` and
|
|
14
|
+
`jexl.addFunctions`. (#25)
|
|
15
|
+
- Binary operators can now be set to evaluate their operands manually, allowing
|
|
16
|
+
them to decide if and when to resolve the value of the left or right sides.
|
|
17
|
+
See the new `manualEval` option in `jexl.addBinaryOp`.
|
|
18
|
+
- Support for Latin 1 Suppliment characters in identifiers (#68) (@heharkon)
|
|
19
|
+
- Support for Russian chatacters in identifiers (#90) (@a-gorbunov)
|
|
20
|
+
- ES5 build for browser support (#87) (@czosel)
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- The binary operators `&&` and `||` now evaluate the right operand
|
|
25
|
+
conditionally, depending on the value of the left.
|
|
26
|
+
|
|
27
|
+
## [v2.2.2]
|
|
28
|
+
|
|
29
|
+
### Changes
|
|
30
|
+
|
|
31
|
+
- Jexl now officially supports Node v12. It's been working, but now CI tests it!
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
|
|
35
|
+
- Accessing children of null should resolve to undefined rather than throwing
|
|
36
|
+
(#64)
|
|
37
|
+
|
|
38
|
+
## [v2.2.1]
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- Relative collection filters didn't function appropriately when evalSync was
|
|
43
|
+
used, as it would sometimes revert to using an actual Promise object.
|
|
44
|
+
(#61)
|
|
45
|
+
|
|
46
|
+
## [v2.2.0]
|
|
47
|
+
|
|
48
|
+
### Added
|
|
49
|
+
|
|
50
|
+
- Introducing the `Expression` object, which allows expressions to be compiled
|
|
51
|
+
only once and evaluated many times
|
|
52
|
+
- Get an Expression by calling `jexl.createExpression('2 + 2')`
|
|
53
|
+
- Get a pre-compiled expression by calling `jexl.compile('2 + 2')`
|
|
54
|
+
- Evaluate Expressions asyncronoushly or synchronously by calling
|
|
55
|
+
`myExpression.eval(context)` or `myExpression.evalSync(context)`
|
|
56
|
+
- Create expressions using a convenient tagged template: `` jexl.expr`2 + 2` ``
|
|
57
|
+
|
|
58
|
+
### Fixed
|
|
59
|
+
|
|
60
|
+
- Transform errors did not always get thrown when using `evalSync` (#55, #56)
|
|
61
|
+
(@bitghostm)
|
|
62
|
+
- Arbitrary whitespace is now re-supported (#54) (@czosel)
|
|
63
|
+
- Strings were not tokenized correctly when ending with an escaped quote (#51)
|
|
64
|
+
(@rehandalal)
|
|
65
|
+
- Identifier names can now start with `$` (#36) (@glromeo)
|
|
66
|
+
|
|
67
|
+
## [v2.1.1]
|
|
68
|
+
|
|
69
|
+
### Fixed
|
|
70
|
+
|
|
71
|
+
- Applying a filter to an undefined identifier now returns an empty array
|
|
72
|
+
instead of an array with one undefined element.
|
|
73
|
+
|
|
74
|
+
## [v2.1.0]
|
|
75
|
+
|
|
76
|
+
### Added
|
|
77
|
+
|
|
78
|
+
- Jexl now has synchronous evaluation! Just call `evalSync`.
|
|
79
|
+
|
|
80
|
+
## [v2.0.2]
|
|
81
|
+
|
|
82
|
+
### Fixed
|
|
83
|
+
|
|
84
|
+
- Issue #47: Revert unintentional change to strict === and !== comparisons
|
|
85
|
+
|
|
86
|
+
## [v2.0.1]
|
|
87
|
+
|
|
88
|
+
### Fixed
|
|
89
|
+
|
|
90
|
+
- Issue where Jexl might mistake an identifier as being relative to a parent
|
|
91
|
+
when it should refer to the top level of the context in one specific case
|
|
92
|
+
|
|
93
|
+
## [v2.0.0]
|
|
94
|
+
|
|
95
|
+
### Changed
|
|
96
|
+
|
|
97
|
+
- The pre-minified Jexl has been removed; in modern times, frontend
|
|
98
|
+
webapps have their own build stack, and Jexl should't make assumptions
|
|
99
|
+
about the module format a frontend app wants to use.
|
|
100
|
+
- Support for Node 4 and earlier has been dropped.
|
|
101
|
+
- The codebase has been modernized to the subset of ES6 supported in
|
|
102
|
+
Node 6 LTS and beyond. Tests require Node 8 or later.
|
|
103
|
+
- The codebase has been shifted to Standard JS style.
|
|
104
|
+
- jexl.eval no longer accepts a callback function. Jexl is now promises-only.
|
|
105
|
+
- Tests have been converted to Jest to eliminate sneaky error swallowing
|
|
106
|
+
|
|
107
|
+
## [v1.1.4]
|
|
108
|
+
|
|
109
|
+
### Fixed
|
|
110
|
+
|
|
111
|
+
- Falsey identifiers are no longer treated as undefined
|
|
112
|
+
|
|
113
|
+
## [v1.1.3]
|
|
114
|
+
|
|
115
|
+
### Fixed
|
|
116
|
+
|
|
117
|
+
- Binary operators after nested identifiers were not balanced properly,
|
|
118
|
+
resulting in a broken expression/AST
|
|
119
|
+
- Gulp (or one of its plugins) had a breaking change in a minor release,
|
|
120
|
+
preventing the frontend build from running. This build method will be
|
|
121
|
+
removed from the next major version of Jexl. For now, Jexl is now version-
|
|
122
|
+
locked to the original gulp+plugins that worked.
|
|
123
|
+
|
|
124
|
+
## [v1.1.2]
|
|
125
|
+
|
|
126
|
+
### Changed
|
|
127
|
+
|
|
128
|
+
- Code coverage thresholds are now enforced through `gulp coverage-test`
|
|
129
|
+
|
|
130
|
+
### Fixed
|
|
131
|
+
|
|
132
|
+
- Operators found in identifier names (such as 'in' in 'incident') were being
|
|
133
|
+
tokenized separately from the rest of the identifier
|
|
134
|
+
|
|
135
|
+
## [v1.1.1]
|
|
136
|
+
|
|
137
|
+
### Fixed
|
|
138
|
+
|
|
139
|
+
- Minus did not denote a negative number at the start of a ternary's consequent
|
|
140
|
+
section
|
|
141
|
+
|
|
142
|
+
## [v1.1.0]
|
|
143
|
+
|
|
144
|
+
### Added
|
|
145
|
+
|
|
146
|
+
- The ability to define new binary and unary operators, or override existing
|
|
147
|
+
ones.
|
|
148
|
+
- The ability to delete existing binary and unary operators.
|
|
149
|
+
|
|
150
|
+
## [v1.0.2]
|
|
151
|
+
|
|
152
|
+
### Fixed
|
|
153
|
+
|
|
154
|
+
- Bad Gulpfile resulted in frontend dist falling out of sync. Fixed and
|
|
155
|
+
re-synced.
|
|
156
|
+
|
|
157
|
+
## [v1.0.1]
|
|
158
|
+
|
|
159
|
+
### Changed
|
|
160
|
+
|
|
161
|
+
- Refactored Parser and Evaluator. Both operations are now marginally faster.
|
|
162
|
+
- Removed balance tracking in favor of passing maps of token types at which
|
|
163
|
+
the sub-parser should stop.
|
|
164
|
+
|
|
165
|
+
### Fixed
|
|
166
|
+
|
|
167
|
+
- Object literals could not be defined in the consequent section of a ternary
|
|
168
|
+
expression.
|
|
169
|
+
|
|
170
|
+
## [v1.0.0]
|
|
171
|
+
|
|
172
|
+
### Added
|
|
173
|
+
|
|
174
|
+
- Object literals. Objects can now be defined inline with
|
|
175
|
+
`{standard: 'syntax'}`.
|
|
176
|
+
- Array literals. Arrays can also be defined with `["standard", 'syntax']`.
|
|
177
|
+
- The 'in' operator, for checking to see if a string appears inside a larger
|
|
178
|
+
string, or if an element exists in an array.
|
|
179
|
+
- Ternary expressions with `this ? "standard" : "syntax"`
|
|
180
|
+
- Ternary expressions with `alternate ?: "syntax"`
|
|
181
|
+
|
|
182
|
+
### Changed
|
|
183
|
+
|
|
184
|
+
- Simplified Grammar, reduced RAM footprint
|
|
185
|
+
- Dot notation can now be used to access properties of literals, such as
|
|
186
|
+
`"someString".length` or `{foo: 'bar'}.foo`.
|
|
187
|
+
- Transform syntax has changed. Arguments are now passed in parentheses, and
|
|
188
|
+
multiple arguments can be defined. Arguments are no longer limited to object
|
|
189
|
+
literals.
|
|
190
|
+
|
|
191
|
+
## [v0.2.0]
|
|
192
|
+
|
|
193
|
+
### Added
|
|
194
|
+
|
|
195
|
+
- "Divide and floor" operator: //
|
|
196
|
+
- Documentation outlining running expressions against XML.
|
|
197
|
+
|
|
198
|
+
## v0.1.0
|
|
199
|
+
|
|
200
|
+
### Added
|
|
201
|
+
|
|
202
|
+
- Initial release
|
|
203
|
+
|
|
204
|
+
[development]: https://github.com/TomFrost/Jexl/compare/v2.3.0...HEAD
|
|
205
|
+
[v2.3.0]: https://github.com/TomFrost/Jexl/compare/v2.2.2...v2.3.0
|
|
206
|
+
[v2.2.2]: https://github.com/TomFrost/Jexl/compare/v2.2.1...v2.2.2
|
|
207
|
+
[v2.2.1]: https://github.com/TomFrost/Jexl/compare/v2.2.0...v2.2.1
|
|
208
|
+
[v2.2.0]: https://github.com/TomFrost/Jexl/compare/v2.1.1...v2.2.0
|
|
209
|
+
[v2.1.1]: https://github.com/TomFrost/Jexl/compare/v2.1.0...v2.1.1
|
|
210
|
+
[v2.1.0]: https://github.com/TomFrost/Jexl/compare/v2.0.2...v2.1.0
|
|
211
|
+
[v2.0.2]: https://github.com/TomFrost/Jexl/compare/v2.0.1...v2.0.2
|
|
212
|
+
[v2.0.1]: https://github.com/TomFrost/Jexl/compare/v2.0.0...v2.0.1
|
|
213
|
+
[v2.0.0]: https://github.com/TomFrost/Jexl/compare/1.1.4...v2.0.0
|
|
214
|
+
[v1.1.4]: https://github.com/TomFrost/Jexl/compare/1.1.3...1.1.4
|
|
215
|
+
[v1.1.3]: https://github.com/TomFrost/Jexl/compare/1.1.2...1.1.3
|
|
216
|
+
[v1.1.2]: https://github.com/TomFrost/Jexl/compare/1.1.1...1.1.2
|
|
217
|
+
[v1.1.1]: https://github.com/TomFrost/Jexl/compare/1.1.0...1.1.1
|
|
218
|
+
[v1.1.0]: https://github.com/TomFrost/Jexl/compare/1.0.2...1.1.0
|
|
219
|
+
[v1.0.2]: https://github.com/TomFrost/Jexl/compare/1.0.1...1.0.2
|
|
220
|
+
[v1.0.1]: https://github.com/TomFrost/Jexl/compare/1.0.0...1.0.1
|
|
221
|
+
[v1.0.0]: https://github.com/TomFrost/Jexl/compare/0.2.0...1.0.0
|
|
222
|
+
[v0.2.0]: https://github.com/TomFrost/Jexl/compare/0.1.0...0.2.0
|
package/LICENSE.txt
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2020 Tom Shawver
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
|
11
|
+
all copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# @jbrowse/jexl
|
|
2
|
+
|
|
3
|
+
A fork of the jexl lang for jbrowse
|
|
4
|
+
|
|
5
|
+
## Quick Examples
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
const context = {
|
|
9
|
+
name: { first: 'Sterling', last: 'Archer' },
|
|
10
|
+
assoc: [
|
|
11
|
+
{ first: 'Lana', last: 'Kane' },
|
|
12
|
+
{ first: 'Cyril', last: 'Figgis' },
|
|
13
|
+
{ first: 'Pam', last: 'Poovey' }
|
|
14
|
+
],
|
|
15
|
+
age: 36
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Template strings with interpolation
|
|
19
|
+
jexl.evalSync('`Hello ${name.first} ${name.last}`', context)
|
|
20
|
+
// "Hello Sterling Archer"
|
|
21
|
+
|
|
22
|
+
jexl.evalSync('`Age in 5 years: ${age + 5}`', context)
|
|
23
|
+
// "Age in 5 years: 41"
|
|
24
|
+
|
|
25
|
+
// Filter arrays
|
|
26
|
+
jexl.evalSync('assoc[.first == "Lana"].last', context)
|
|
27
|
+
// "Kane"
|
|
28
|
+
|
|
29
|
+
// Math operations
|
|
30
|
+
jexl.evalSync('age * (3 - 1)', context)
|
|
31
|
+
// 72
|
|
32
|
+
|
|
33
|
+
// String concatenation
|
|
34
|
+
jexl.evalSync('name.first + " " + name.last', context)
|
|
35
|
+
// "Sterling Archer"
|
|
36
|
+
|
|
37
|
+
// Conditional logic
|
|
38
|
+
jexl.evalSync('age > 62 ? "retired" : "working"', context)
|
|
39
|
+
// "working"
|
|
40
|
+
|
|
41
|
+
// Array indexes
|
|
42
|
+
jexl.evalSync('assoc[1].first', context)
|
|
43
|
+
// "Cyril"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Language Reference
|
|
47
|
+
|
|
48
|
+
### Native Types
|
|
49
|
+
|
|
50
|
+
| Type | Examples |
|
|
51
|
+
| ---------------- | ---------------------------------------------------- |
|
|
52
|
+
| Booleans | `true`, `false` |
|
|
53
|
+
| Strings | `"Hello \"user\""`, `'Hey there!'` |
|
|
54
|
+
| Template Strings | `` `Hello ${name}` ``, `` `Total: ${price * qty}` `` |
|
|
55
|
+
| Numerics | `6`, `-7.2`, `5`, `-3.14159` |
|
|
56
|
+
| Objects | `{hello: "world!"}` |
|
|
57
|
+
| Arrays | `['hello', 'world!']` |
|
|
58
|
+
|
|
59
|
+
### Template Strings
|
|
60
|
+
|
|
61
|
+
Template strings use backticks and support expression interpolation with `${}`:
|
|
62
|
+
|
|
63
|
+
```javascript
|
|
64
|
+
const context = { name: 'World', price: 10, qty: 3 }
|
|
65
|
+
|
|
66
|
+
jexl.evalSync('`Hello ${name}!`', context)
|
|
67
|
+
// "Hello World!"
|
|
68
|
+
|
|
69
|
+
jexl.evalSync('`Total: $${price * qty}`', context)
|
|
70
|
+
// "Total: $30"
|
|
71
|
+
|
|
72
|
+
// Escape backticks and dollar signs with backslash
|
|
73
|
+
jexl.evalSync('`Code: \\`example\\``')
|
|
74
|
+
// "Code: `example`"
|
|
75
|
+
|
|
76
|
+
jexl.evalSync('`Price: \\$100`')
|
|
77
|
+
// "Price: $100"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Operators
|
|
81
|
+
|
|
82
|
+
**Unary:** `!` (negate)
|
|
83
|
+
|
|
84
|
+
**Binary:**
|
|
85
|
+
|
|
86
|
+
- Arithmetic: `+`, `-`, `*`, `/`, `//` (floor division), `%`, `^` (power)
|
|
87
|
+
- Comparison: `==`, `!=`, `>`, `>=`, `<`, `<=`, `in`
|
|
88
|
+
- Logical: `&&`, `||`
|
|
89
|
+
- Assignment: `=` (assigns value to variable)
|
|
90
|
+
|
|
91
|
+
**Ternary:** `condition ? consequent : alternate`
|
|
92
|
+
|
|
93
|
+
**Sequence:** `;` (separates multiple expressions)
|
|
94
|
+
|
|
95
|
+
### Identifiers
|
|
96
|
+
|
|
97
|
+
Access context variables by name. Use dot notation or brackets for nested properties:
|
|
98
|
+
|
|
99
|
+
```javascript
|
|
100
|
+
const context = {
|
|
101
|
+
name: { first: 'Malory', last: 'Archer' },
|
|
102
|
+
exes: ['Nikolai', 'Len', 'Burt'],
|
|
103
|
+
lastEx: 2
|
|
104
|
+
}
|
|
105
|
+
|
|
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"
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Filtering Collections
|
|
113
|
+
|
|
114
|
+
Filter arrays using expressions in brackets. Reference properties with a leading dot:
|
|
115
|
+
|
|
116
|
+
```javascript
|
|
117
|
+
const context = {
|
|
118
|
+
employees: [
|
|
119
|
+
{ first: 'Sterling', last: 'Archer', age: 36 },
|
|
120
|
+
{ first: 'Malory', last: 'Archer', age: 75 },
|
|
121
|
+
{ first: 'Lana', last: 'Kane', age: 33 },
|
|
122
|
+
{ first: 'Cyril', last: 'Figgis', age: 45 }
|
|
123
|
+
]
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
jexl.evalSync('employees[.first == "Sterling"]', context)
|
|
127
|
+
// [{ first: 'Sterling', last: 'Archer', age: 36 }]
|
|
128
|
+
|
|
129
|
+
jexl.evalSync('employees[.age >= 30 && .age < 40]', context)
|
|
130
|
+
// [{ first: 'Sterling', ... }, { first: 'Lana', ... }]
|
|
131
|
+
|
|
132
|
+
jexl.evalSync('employees[.last == "Kane"].first', context)
|
|
133
|
+
// "Lana"
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Transforms
|
|
137
|
+
|
|
138
|
+
Apply transforms to values using the pipe operator:
|
|
139
|
+
|
|
140
|
+
```javascript
|
|
141
|
+
jexl.addTransform('upper', (val) => val.toUpperCase())
|
|
142
|
+
jexl.addTransform('split', (val, char) => val.split(char))
|
|
143
|
+
|
|
144
|
+
jexl.evalSync('"hello"|upper')
|
|
145
|
+
// "HELLO"
|
|
146
|
+
|
|
147
|
+
jexl.evalSync('"firstName lastName"|split(" ")[0]')
|
|
148
|
+
// "firstName"
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Functions
|
|
152
|
+
|
|
153
|
+
Call functions in expressions:
|
|
154
|
+
|
|
155
|
+
```javascript
|
|
156
|
+
jexl.addFunction('min', Math.min)
|
|
157
|
+
jexl.addFunction('max', Math.max)
|
|
158
|
+
|
|
159
|
+
jexl.evalSync('min(5, 2, 9)')
|
|
160
|
+
// 2
|
|
161
|
+
|
|
162
|
+
jexl.evalSync('max(temperature, threshold)')
|
|
163
|
+
// evaluates with context
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Multiple Expressions
|
|
167
|
+
|
|
168
|
+
Separate multiple expressions with semicolons. The result is the value of the last expression:
|
|
169
|
+
|
|
170
|
+
```javascript
|
|
171
|
+
jexl.evalSync('5; 10; 15')
|
|
172
|
+
// 15
|
|
173
|
+
|
|
174
|
+
jexl.evalSync('1 + 1; 2 + 2; 3 + 3')
|
|
175
|
+
// 6
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Variable Assignment
|
|
179
|
+
|
|
180
|
+
Assign values to variables using `=` (no `let`, `var`, or `const` needed). Assignments mutate the context and return the assigned value:
|
|
181
|
+
|
|
182
|
+
```javascript
|
|
183
|
+
jexl.evalSync('x = 5')
|
|
184
|
+
// 5
|
|
185
|
+
|
|
186
|
+
jexl.evalSync('x = 5; x * 2')
|
|
187
|
+
// 10
|
|
188
|
+
|
|
189
|
+
jexl.evalSync('x = 5; y = 10; x + y')
|
|
190
|
+
// 15
|
|
191
|
+
|
|
192
|
+
const context = {}
|
|
193
|
+
jexl.evalSync('x = 5; y = x * 2; y', context)
|
|
194
|
+
// 10
|
|
195
|
+
// context is now { x: 5, y: 10 }
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Usage
|
|
199
|
+
|
|
200
|
+
```javascript
|
|
201
|
+
import jexl from 'jexl'
|
|
202
|
+
|
|
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)
|
|
208
|
+
|
|
209
|
+
// Compile once, evaluate many times
|
|
210
|
+
const expr = jexl.compile('name.first + " " + name.last')
|
|
211
|
+
expr.evalSync({ name: { first: 'John', last: 'Doe' } })
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## License
|
|
215
|
+
|
|
216
|
+
MIT License - see LICENSE.txt for details
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import PromiseSync from './PromiseSync.ts';
|
|
2
|
+
import type { AstNode } from './types.ts';
|
|
3
|
+
interface Grammar {
|
|
4
|
+
elements: Record<string, any>;
|
|
5
|
+
[key: string]: any;
|
|
6
|
+
}
|
|
7
|
+
type PromiseConstructor = typeof Promise | typeof PromiseSync;
|
|
8
|
+
declare class Expression {
|
|
9
|
+
_grammar: Grammar;
|
|
10
|
+
_exprStr: string;
|
|
11
|
+
_ast: AstNode | null;
|
|
12
|
+
constructor(grammar: Grammar, exprStr: string);
|
|
13
|
+
/**
|
|
14
|
+
* Forces a compilation of the expression string that this Expression object
|
|
15
|
+
* was constructed with. This function can be called multiple times; useful
|
|
16
|
+
* if the language elements of the associated Jexl instance change.
|
|
17
|
+
* @returns {Expression} this Expression instance, for convenience
|
|
18
|
+
*/
|
|
19
|
+
compile(): this;
|
|
20
|
+
/**
|
|
21
|
+
* Asynchronously evaluates the expression within an optional context.
|
|
22
|
+
* @param {Object} [context] A mapping of variables to values, which will be
|
|
23
|
+
* made accessible to the Jexl expression when evaluating it
|
|
24
|
+
* @returns {Promise<*>} resolves with the result of the evaluation.
|
|
25
|
+
*/
|
|
26
|
+
eval(context?: {}): Promise<any> | PromiseSync<any>;
|
|
27
|
+
/**
|
|
28
|
+
* Synchronously evaluates the expression within an optional context.
|
|
29
|
+
* @param {Object} [context] A mapping of variables to values, which will be
|
|
30
|
+
* made accessible to the Jexl expression when evaluating it
|
|
31
|
+
* @returns {*} the result of the evaluation.
|
|
32
|
+
* @throws {*} on error
|
|
33
|
+
*/
|
|
34
|
+
evalSync(context?: {}): unknown;
|
|
35
|
+
_eval(context: any, promise: PromiseConstructor): Promise<any> | PromiseSync<any>;
|
|
36
|
+
_getAst(): AstNode | null;
|
|
37
|
+
}
|
|
38
|
+
export default Expression;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Jexl
|
|
4
|
+
* Copyright 2020 Tom Shawver
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
const Lexer_ts_1 = __importDefault(require("./Lexer.js"));
|
|
11
|
+
const PromiseSync_ts_1 = __importDefault(require("./PromiseSync.js"));
|
|
12
|
+
const Evaluator_ts_1 = __importDefault(require("./evaluator/Evaluator.js"));
|
|
13
|
+
const Parser_ts_1 = __importDefault(require("./parser/Parser.js"));
|
|
14
|
+
class Expression {
|
|
15
|
+
constructor(grammar, exprStr) {
|
|
16
|
+
this._grammar = grammar;
|
|
17
|
+
this._exprStr = exprStr;
|
|
18
|
+
this._ast = null;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Forces a compilation of the expression string that this Expression object
|
|
22
|
+
* was constructed with. This function can be called multiple times; useful
|
|
23
|
+
* if the language elements of the associated Jexl instance change.
|
|
24
|
+
* @returns {Expression} this Expression instance, for convenience
|
|
25
|
+
*/
|
|
26
|
+
compile() {
|
|
27
|
+
const lexer = new Lexer_ts_1.default(this._grammar);
|
|
28
|
+
const parser = new Parser_ts_1.default(this._grammar, lexer);
|
|
29
|
+
const tokens = lexer.tokenize(this._exprStr);
|
|
30
|
+
parser.addTokens(tokens);
|
|
31
|
+
this._ast = parser.complete();
|
|
32
|
+
return this;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Asynchronously evaluates the expression within an optional context.
|
|
36
|
+
* @param {Object} [context] A mapping of variables to values, which will be
|
|
37
|
+
* made accessible to the Jexl expression when evaluating it
|
|
38
|
+
* @returns {Promise<*>} resolves with the result of the evaluation.
|
|
39
|
+
*/
|
|
40
|
+
eval(context = {}) {
|
|
41
|
+
return this._eval(context, Promise);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Synchronously evaluates the expression within an optional context.
|
|
45
|
+
* @param {Object} [context] A mapping of variables to values, which will be
|
|
46
|
+
* made accessible to the Jexl expression when evaluating it
|
|
47
|
+
* @returns {*} the result of the evaluation.
|
|
48
|
+
* @throws {*} on error
|
|
49
|
+
*/
|
|
50
|
+
evalSync(context = {}) {
|
|
51
|
+
const res = this._eval(context, PromiseSync_ts_1.default);
|
|
52
|
+
if (res.error) {
|
|
53
|
+
if (res.error instanceof Error) {
|
|
54
|
+
throw res.error;
|
|
55
|
+
}
|
|
56
|
+
throw new Error(typeof res.error === 'string' ? res.error : JSON.stringify(res.error));
|
|
57
|
+
}
|
|
58
|
+
return res.value;
|
|
59
|
+
}
|
|
60
|
+
_eval(context, promise) {
|
|
61
|
+
return promise.resolve().then(() => {
|
|
62
|
+
const ast = this._getAst();
|
|
63
|
+
const evaluator = new Evaluator_ts_1.default(this._grammar, context, undefined, promise);
|
|
64
|
+
return evaluator.eval(ast);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
_getAst() {
|
|
68
|
+
if (!this._ast) {
|
|
69
|
+
this.compile();
|
|
70
|
+
}
|
|
71
|
+
return this._ast;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
exports.default = Expression;
|
|
75
|
+
//# sourceMappingURL=Expression.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Expression.js","sourceRoot":"","sources":["../src/Expression.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;AAEH,0DAA8B;AAC9B,sEAA0C;AAC1C,4EAAgD;AAChD,mEAAuC;AAWvC,MAAM,UAAU;IAKd,YAAY,OAAgB,EAAE,OAAe;QAC3C,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAA;QACvB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAA;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;IAClB,CAAC;IAED;;;;;OAKG;IACH,OAAO;QACL,MAAM,KAAK,GAAG,IAAI,kBAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACtC,MAAM,MAAM,GAAG,IAAI,mBAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;QAC/C,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAC5C,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;QACxB,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAA;QAC7B,OAAO,IAAI,CAAA;IACb,CAAC;IAED;;;;;OAKG;IACH,IAAI,CAAC,OAAO,GAAG,EAAE;QACf,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IACrC,CAAC;IAED;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,GAAG,EAAE;QACnB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,wBAAkB,CAAgB,CAAA;QAClE,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;YACd,IAAI,GAAG,CAAC,KAAK,YAAY,KAAK,EAAE,CAAC;gBAC/B,MAAM,GAAG,CAAC,KAAK,CAAA;YACjB,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAA;QACxF,CAAC;QACD,OAAO,GAAG,CAAC,KAAK,CAAA;IAClB,CAAC;IAED,KAAK,CAAC,OAAY,EAAE,OAA2B;QAC7C,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;YACjC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,CAAA;YAC1B,MAAM,SAAS,GAAG,IAAI,sBAAS,CAC7B,IAAI,CAAC,QAAQ,EACb,OAAO,EACP,SAAS,EACT,OAAO,CACR,CAAA;YACD,OAAO,SAAS,CAAC,IAAI,CAAC,GAAI,CAAC,CAAA;QAC7B,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,OAAO;QACL,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YACf,IAAI,CAAC,OAAO,EAAE,CAAA;QAChB,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAA;IAClB,CAAC;CACF;AAED,kBAAe,UAAU,CAAA"}
|