fig-tree-evaluator 2.3.1 → 2.3.3
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 +26 -17
- package/build/cache.js +0 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,9 +4,11 @@
|
|
|
4
4
|
|
|
5
5
|
**FigTree Evaluator** is a module to evaluate JSON-structured expression trees.
|
|
6
6
|
|
|
7
|
-
A typical use case would be for evaluating **configuration** files, where you need to store dynamic values or arbitrary logic without allowing users to inject executable code (perhaps in a .json file, say).
|
|
7
|
+
A typical use case would be for evaluating **configuration** files, where you need to store dynamic values or arbitrary logic without allowing users to inject executable code (perhaps in a .json file, say). Use cases could include:
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
- a [form-builder app](https://github.com/openmsupply/conforma-web-app) might need to allow complex conditional logic for form element visibility based on previous responses, or for validation beyond what is available in standard validation libraries.
|
|
10
|
+
- configure a [decision tree](https://en.wikipedia.org/wiki/Decision_tree) to implement branching logic. (See examples in `20_match.test.ts`)
|
|
11
|
+
- extend [JSON Forms](https://jsonforms.io) with more complex logic and dynamic lookups: https://github.com/CarlosNZ/jsonforms-with-figtree-demo
|
|
10
12
|
|
|
11
13
|
A range of built-in operators are available, from simple logic, arithmetic and string manipulation, to data fetching from local sources or remote APIs.
|
|
12
14
|
|
|
@@ -165,7 +167,7 @@ import { evaluateExpression } from 'fig-tree-evaluator'
|
|
|
165
167
|
|
|
166
168
|
evaluateExpression(expression, [options]).then((result) => {
|
|
167
169
|
// Do something with result
|
|
168
|
-
}
|
|
170
|
+
})
|
|
169
171
|
```
|
|
170
172
|
|
|
171
173
|
## Operator nodes
|
|
@@ -202,13 +204,13 @@ For example, the following two representations are equivalent `conditional` oper
|
|
|
202
204
|
}
|
|
203
205
|
```
|
|
204
206
|
|
|
205
|
-
Most of the time named properties
|
|
207
|
+
Most of the time named properties would be preferable; however there are occasional cases where the "children" array might be easier to deal with, or to build up from child nodes.
|
|
206
208
|
|
|
207
209
|
### Other common properties:
|
|
208
210
|
|
|
209
|
-
In each operator node, as well as the operator-specific properties, the following
|
|
211
|
+
In each operator node, as well as the operator-specific properties, the following three optional properties can be provided:
|
|
210
212
|
|
|
211
|
-
- `fallback`: if the operation throws an error, the `fallback` value will be returned instead. The `fallback` property can be provided at any level of the expression tree and bubbled up from where errors are caught to parent nodes.
|
|
213
|
+
- `fallback`: if the operation throws an error, the `fallback` value will be returned instead. The `fallback` property can be provided at any level of the expression tree and bubbled up from where errors are caught to parent nodes. *Fallbacks are strongly recommended if there is any chance of an error (e.g. a network "GET" request that doesn't yet have its parameters defined).*
|
|
212
214
|
- `outputType` (or `type`): will convert the result of the current node to the specified `outputType`. Valid values are `string`, `number`, `boolean` (or `bool`), and `array`. You can experiment in the [demo app](https://carlosnz.github.io/fig-tree-evaluator/) to see the outcome of applying different `outputType` values to various results.
|
|
213
215
|
- `useCache`: Overrides the global `useCache` value (from [options](#available-options)) for this node only. See [Caching/Memoization](#caching-memoization) below for more info.
|
|
214
216
|
|
|
@@ -431,7 +433,7 @@ e.g.
|
|
|
431
433
|
----
|
|
432
434
|
### MULTIPLY
|
|
433
435
|
|
|
434
|
-
*
|
|
436
|
+
*Multiplication*
|
|
435
437
|
|
|
436
438
|
Aliases: `*`, `x`, `multiply`, `times`
|
|
437
439
|
|
|
@@ -634,6 +636,8 @@ e.g.
|
|
|
634
636
|
|
|
635
637
|
`children` array: `[condition, valueIfTrue, valueIfFalse]`
|
|
636
638
|
|
|
639
|
+
**Note**: *For more complex branching logic, the ["match" operator](#match) can be used (it matches more than just a boolean condition)*
|
|
640
|
+
|
|
637
641
|
----
|
|
638
642
|
### REGEX
|
|
639
643
|
|
|
@@ -719,8 +723,10 @@ Here is the result of various values of `expression:`
|
|
|
719
723
|
Notice the last example pulls multiple values out of an array of objects, in this case the "name". This is essentially a shorthand for:
|
|
720
724
|
|
|
721
725
|
```js
|
|
722
|
-
|
|
723
|
-
|
|
726
|
+
exp.evaluate(
|
|
727
|
+
{ operator: 'getProperty', path: 'user.enemies' },
|
|
728
|
+
{ data: { user } }
|
|
729
|
+
).map((e) => e.name)
|
|
724
730
|
```
|
|
725
731
|
|
|
726
732
|
The "objectProperties" operator uses [`object-property-extractor`](https://www.npmjs.com/package/object-property-extractor) internally, so please see the documentation of that package for more information.
|
|
@@ -840,7 +846,7 @@ Aliases: `split`, `arraySplit`
|
|
|
840
846
|
- `excludeTrailing` (or `removeTrailing`, `excludeTrailingDelimiter`): (boolean, default `true`) -- if `false`, if the input string ends with the delimiter, the last member of the output array will be an empty string.
|
|
841
847
|
i.e. `this, that, another,` (delimiter `","`) => `["this", "that", "another", ""]`
|
|
842
848
|
|
|
843
|
-
The last two parameters (`timeWhiteSpace` and `excludeTrailing`) should rarely be needed.
|
|
849
|
+
The last two parameters (`timeWhiteSpace` and `excludeTrailing`) should *rarely* be needed to be changed from their default values.
|
|
844
850
|
|
|
845
851
|
e.g.
|
|
846
852
|
```js
|
|
@@ -978,7 +984,7 @@ The required connection object is:
|
|
|
978
984
|
}
|
|
979
985
|
```
|
|
980
986
|
|
|
981
|
-
The following example expression uses the GraphQL connection: `{endpoint: 'https://countries.trevorblades.com/'}`
|
|
987
|
+
The following example expression uses the GraphQL connection (specified in constructor options): `{endpoint: 'https://countries.trevorblades.com/'}`
|
|
982
988
|
```js
|
|
983
989
|
{
|
|
984
990
|
operator: 'graphQL',
|
|
@@ -1121,7 +1127,7 @@ e.g.
|
|
|
1121
1127
|
|
|
1122
1128
|
`children` array: `[key1, value1, key2, value2, ...]`
|
|
1123
1129
|
|
|
1124
|
-
This is one of the few
|
|
1130
|
+
This is one of the few cases where the `children` array might actually be simpler to define than the `properties` property, depending on how deep the array elements are themselves operator nodes.
|
|
1125
1131
|
|
|
1126
1132
|
e.g.
|
|
1127
1133
|
```js
|
|
@@ -1221,7 +1227,6 @@ This expression could also be written as (with branch/case keys at the root leve
|
|
|
1221
1227
|
|
|
1222
1228
|
The pairs of `key`/`value`s are constructed into the `branches` object, the same way the objects are built using `children` in the ["buildObject"](#build_object) operator.
|
|
1223
1229
|
|
|
1224
|
-
|
|
1225
1230
|
For an example of a complex decision tree implementation, which includes [aliases](#alias-nodes), [fallbacks](#other-common-properties) and a range of operators, see the "match" test case file (`20_match.test.ts`).
|
|
1226
1231
|
|
|
1227
1232
|
----
|
|
@@ -1298,7 +1303,7 @@ Here is the result of various expressions:
|
|
|
1298
1303
|
},
|
|
1299
1304
|
],
|
|
1300
1305
|
}
|
|
1301
|
-
// => "THE CURRENT YEAR IS:
|
|
1306
|
+
// => "THE CURRENT YEAR IS: 2023"
|
|
1302
1307
|
```
|
|
1303
1308
|
|
|
1304
1309
|
`children` array: `[functionPath, ...args]`
|
|
@@ -1314,7 +1319,7 @@ e.g.
|
|
|
1314
1319
|
|
|
1315
1320
|
## Alias Nodes
|
|
1316
1321
|
|
|
1317
|
-
If you have a node that is used more than once in a complex expression, it's possible to just evaluate the repeated node once, and refer to it throughout using an "alias" reference. This allows for a simpler expression (reduces duplication) as well as a performance improvement, since the aliased node is only evaluated once, providing a simple [memoization](https://en.wikipedia.org/wiki/Memoization) mechanism.
|
|
1322
|
+
If you have a node that is used more than once in a complex expression, it's possible to just evaluate the repeated node once, and refer to it throughout using an "alias" reference. This allows for a simpler expression (reduces code duplication) as well as a performance improvement, since the aliased node is only evaluated once, providing a simple [memoization](https://en.wikipedia.org/wiki/Memoization) mechanism. (See also [Caching/Memoization](#caching-memoization))
|
|
1318
1323
|
|
|
1319
1324
|
For example, if you have the expression:
|
|
1320
1325
|
```js
|
|
@@ -1385,7 +1390,7 @@ Like all expression nodes, alias nodes can themselves contain complex expression
|
|
|
1385
1390
|
|
|
1386
1391
|
## Caching (Memoization)
|
|
1387
1392
|
|
|
1388
|
-
FigTree Evaluator has basic memoization functionality for certain nodes to speed up re-evaluation
|
|
1393
|
+
FigTree Evaluator has basic [memoization](https://en.wikipedia.org/wiki/Memoization) functionality for certain nodes to speed up re-evaluation when the input parameters haven't changed. There is a single cache store per FigTree instance which persists for the lifetime of the instance. By default, it remembers the last 50 results, but this can be modified using the `maxCacheSize` option.
|
|
1389
1394
|
|
|
1390
1395
|
Currently, caching is only implemented for the following operators, since they perform requests to external resources, which are inherently slow:
|
|
1391
1396
|
|
|
@@ -1395,6 +1400,10 @@ Currently, caching is only implemented for the following operators, since they p
|
|
|
1395
1400
|
- GRAPH_QL (`useCache` default: `true`)
|
|
1396
1401
|
- CUSTOM_FUNCTIONS (`useCache` default: `false`)
|
|
1397
1402
|
|
|
1403
|
+
This is different to the memoization provided by [Alias Nodes](#alias-nodes):
|
|
1404
|
+
- Alias nodes are still evaluated once for every evaluation -- they're more for re-use *within* a complex expression.
|
|
1405
|
+
- Cached nodes will persist *between* different evaluations as long as the input values are the same as a previously evaluated node.
|
|
1406
|
+
|
|
1398
1407
|
## More examples
|
|
1399
1408
|
|
|
1400
1409
|
More examples, included large, complex expressions can be found within the test suites in the [repository](https://github.com/CarlosNZ/fig-tree-evaluator).
|
|
@@ -1427,7 +1436,7 @@ Please open an issue: https://github.com/CarlosNZ/fig-tree-evaluator/issues
|
|
|
1427
1436
|
|
|
1428
1437
|
## Changelog
|
|
1429
1438
|
|
|
1430
|
-
- **v2.3.
|
|
1439
|
+
- **v2.3.2**: Bug fix: alias nodes not working with `evaluateFullObject` (#72)
|
|
1431
1440
|
- **v2.3.0**: Implement [caching/memoization](#caching-memoization) (#68)
|
|
1432
1441
|
- **v2.2.3**: Change option `objects` name to `data` (but keep backward compatibility) (#66)
|
|
1433
1442
|
- **v2.2.2**: Option to evaluate whole object if operator nodes are deep within it (#64)
|
package/build/cache.js
CHANGED
|
@@ -59,7 +59,6 @@ var FigTreeCache = (function () {
|
|
|
59
59
|
if (key in this.store) {
|
|
60
60
|
this.queue = this.queue.filter(function (val) { return val !== key; });
|
|
61
61
|
this.queue.unshift(key);
|
|
62
|
-
console.log('Using cached result:', this.store[key]);
|
|
63
62
|
return [2, this.store[key]];
|
|
64
63
|
}
|
|
65
64
|
return [4, action.apply(void 0, args)];
|