fig-tree-evaluator 2.3.2 → 2.4.0
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 +87 -16
- package/build/evaluate.js +79 -64
- package/build/helpers.d.ts +1 -0
- package/build/helpers.js +7 -1
- package/build/index.js +1 -12
- package/build/types.d.ts +11 -1
- package/package.json +2 -2
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
|
|
|
@@ -47,6 +49,7 @@ A range of built-in operators are available, from simple logic, arithmetic and s
|
|
|
47
49
|
- [PASSTHRU](#passthru)
|
|
48
50
|
- [CUSTOM\_FUNCTIONS](#custom_functions)
|
|
49
51
|
- [Alias Nodes](#alias-nodes)
|
|
52
|
+
- [Fragments](#fragments)
|
|
50
53
|
- [Caching (Memoization)](#caching-memoization)
|
|
51
54
|
- [More examples](#more-examples)
|
|
52
55
|
- [Development environment](#development-environment)
|
|
@@ -138,6 +141,7 @@ The `options` parameter is an object with the following available properties (al
|
|
|
138
141
|
|
|
139
142
|
- `data` -- a single object containing any *objects* in your application that may wish to be inspected using the [objectProperties](#object_properties) operator. (See [playground](LINK) for examples). If these objects are regularly changing, you'll probably want to pass them into each separate evaluation rather than with the initial constructor.
|
|
140
143
|
- `functions` -- a single object containing any *custom functions* available for use by the [customFunctions](#custom_functions) operator.
|
|
144
|
+
- `fragments` -- commonly-used expressions (with optional parameters) that can be re-used in any other expression. See [Fragments](#fragments)
|
|
141
145
|
- `pgConnection` -- if you wish to make calls to a Postgres database using the [`pgSQL` operator](#pg_sql), pass a [node-postres](https://node-postgres.com/) connection object here.
|
|
142
146
|
- `graphQLConnection` -- a GraphQL connection object, if using the [`graphQL` operator](#graphql). See operator details below.
|
|
143
147
|
- `baseEndpoint` -- A general http headers object that will be passed to *all* http-based operators (`GET`, `POST`, `GraphQL`). Useful if all http queries are to a common server -- then each individual node will only require a relative url. See specific operator for more details.
|
|
@@ -165,7 +169,7 @@ import { evaluateExpression } from 'fig-tree-evaluator'
|
|
|
165
169
|
|
|
166
170
|
evaluateExpression(expression, [options]).then((result) => {
|
|
167
171
|
// Do something with result
|
|
168
|
-
}
|
|
172
|
+
})
|
|
169
173
|
```
|
|
170
174
|
|
|
171
175
|
## Operator nodes
|
|
@@ -202,13 +206,13 @@ For example, the following two representations are equivalent `conditional` oper
|
|
|
202
206
|
}
|
|
203
207
|
```
|
|
204
208
|
|
|
205
|
-
Most of the time named properties
|
|
209
|
+
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
210
|
|
|
207
211
|
### Other common properties:
|
|
208
212
|
|
|
209
|
-
In each operator node, as well as the operator-specific properties, the following
|
|
213
|
+
In each operator node, as well as the operator-specific properties, the following three optional properties can be provided:
|
|
210
214
|
|
|
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.
|
|
215
|
+
- `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
216
|
- `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
217
|
- `useCache`: Overrides the global `useCache` value (from [options](#available-options)) for this node only. See [Caching/Memoization](#caching-memoization) below for more info.
|
|
214
218
|
|
|
@@ -431,7 +435,7 @@ e.g.
|
|
|
431
435
|
----
|
|
432
436
|
### MULTIPLY
|
|
433
437
|
|
|
434
|
-
*
|
|
438
|
+
*Multiplication*
|
|
435
439
|
|
|
436
440
|
Aliases: `*`, `x`, `multiply`, `times`
|
|
437
441
|
|
|
@@ -634,6 +638,8 @@ e.g.
|
|
|
634
638
|
|
|
635
639
|
`children` array: `[condition, valueIfTrue, valueIfFalse]`
|
|
636
640
|
|
|
641
|
+
**Note**: *For more complex branching logic, the ["match" operator](#match) can be used (it matches more than just a boolean condition)*
|
|
642
|
+
|
|
637
643
|
----
|
|
638
644
|
### REGEX
|
|
639
645
|
|
|
@@ -719,8 +725,10 @@ Here is the result of various values of `expression:`
|
|
|
719
725
|
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
726
|
|
|
721
727
|
```js
|
|
722
|
-
|
|
723
|
-
|
|
728
|
+
exp.evaluate(
|
|
729
|
+
{ operator: 'getProperty', path: 'user.enemies' },
|
|
730
|
+
{ data: { user } }
|
|
731
|
+
).map((e) => e.name)
|
|
724
732
|
```
|
|
725
733
|
|
|
726
734
|
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 +848,7 @@ Aliases: `split`, `arraySplit`
|
|
|
840
848
|
- `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
849
|
i.e. `this, that, another,` (delimiter `","`) => `["this", "that", "another", ""]`
|
|
842
850
|
|
|
843
|
-
The last two parameters (`timeWhiteSpace` and `excludeTrailing`) should rarely be needed.
|
|
851
|
+
The last two parameters (`timeWhiteSpace` and `excludeTrailing`) should *rarely* be needed to be changed from their default values.
|
|
844
852
|
|
|
845
853
|
e.g.
|
|
846
854
|
```js
|
|
@@ -978,7 +986,7 @@ The required connection object is:
|
|
|
978
986
|
}
|
|
979
987
|
```
|
|
980
988
|
|
|
981
|
-
The following example expression uses the GraphQL connection: `{endpoint: 'https://countries.trevorblades.com/'}`
|
|
989
|
+
The following example expression uses the GraphQL connection (specified in constructor options): `{endpoint: 'https://countries.trevorblades.com/'}`
|
|
982
990
|
```js
|
|
983
991
|
{
|
|
984
992
|
operator: 'graphQL',
|
|
@@ -1121,7 +1129,7 @@ e.g.
|
|
|
1121
1129
|
|
|
1122
1130
|
`children` array: `[key1, value1, key2, value2, ...]`
|
|
1123
1131
|
|
|
1124
|
-
This is one of the few
|
|
1132
|
+
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
1133
|
|
|
1126
1134
|
e.g.
|
|
1127
1135
|
```js
|
|
@@ -1221,7 +1229,6 @@ This expression could also be written as (with branch/case keys at the root leve
|
|
|
1221
1229
|
|
|
1222
1230
|
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
1231
|
|
|
1224
|
-
|
|
1225
1232
|
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
1233
|
|
|
1227
1234
|
----
|
|
@@ -1298,7 +1305,7 @@ Here is the result of various expressions:
|
|
|
1298
1305
|
},
|
|
1299
1306
|
],
|
|
1300
1307
|
}
|
|
1301
|
-
// => "THE CURRENT YEAR IS:
|
|
1308
|
+
// => "THE CURRENT YEAR IS: 2023"
|
|
1302
1309
|
```
|
|
1303
1310
|
|
|
1304
1311
|
`children` array: `[functionPath, ...args]`
|
|
@@ -1383,9 +1390,71 @@ Like all expression nodes, alias nodes can themselves contain complex expression
|
|
|
1383
1390
|
|
|
1384
1391
|
(If an alias reference does not having a matching definition, the reference value will just be returned as a literal string, e.g. `"$getCountry"`)
|
|
1385
1392
|
|
|
1393
|
+
## Fragments
|
|
1394
|
+
|
|
1395
|
+
You may find that the expressions you are building for your configuration files often use very similar sub-expressions (but perhaps with only some input values that differ). For example, your expressions might be regularly looking up a "countries" database and fetching the capital city, such as:
|
|
1396
|
+
```js
|
|
1397
|
+
{
|
|
1398
|
+
operator: 'GET',
|
|
1399
|
+
url: {
|
|
1400
|
+
operator: 'stringSubstitution',
|
|
1401
|
+
string: 'https://restcountries.com/v3.1/name/%1',
|
|
1402
|
+
replacements: ['New Zealand'],
|
|
1403
|
+
},
|
|
1404
|
+
returnProperty: '[0].capital',
|
|
1405
|
+
outputType: 'string',
|
|
1406
|
+
}
|
|
1407
|
+
// => "Wellington"
|
|
1408
|
+
```
|
|
1409
|
+
|
|
1410
|
+
In this case, you can pre-define the main part of the expression as part of an expression "**fragment**" in the evaluator [options](#available-options).
|
|
1411
|
+
|
|
1412
|
+
The idea is that you can "hard-code" some common expressions into your app, so that external configuration expressions can be simpler when using these common elements.
|
|
1413
|
+
|
|
1414
|
+
The syntax is similar to [Alias Nodes](#alias-nodes), in that any string values prefixed with `$` will be treated as "parameters" that will be replaced during evaluation. In the above example, you would define the fragment when instantiating the evaluator like so:
|
|
1415
|
+
|
|
1416
|
+
```js
|
|
1417
|
+
const exp = new FigTreeEvaluator({
|
|
1418
|
+
fragments: {
|
|
1419
|
+
getCapital: {
|
|
1420
|
+
operator: 'GET',
|
|
1421
|
+
url: {
|
|
1422
|
+
operator: 'stringSubstitution',
|
|
1423
|
+
string: 'https://restcountries.com/v3.1/name/%1',
|
|
1424
|
+
replacements: [ "$country" ],
|
|
1425
|
+
},
|
|
1426
|
+
returnProperty: '[0].capital',
|
|
1427
|
+
outputType: 'string',
|
|
1428
|
+
},
|
|
1429
|
+
},
|
|
1430
|
+
})
|
|
1431
|
+
```
|
|
1432
|
+
|
|
1433
|
+
Then any subsequent expressions can use this fragment by specifying a special "Fragment Node", which contains the `fragment` and (optionally) `parameters` fields:
|
|
1434
|
+
```js
|
|
1435
|
+
{
|
|
1436
|
+
fragment: "getCapital",
|
|
1437
|
+
parameters: {
|
|
1438
|
+
$country: { operator: "getData", property: "path.to.country.name" }
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
```
|
|
1442
|
+
|
|
1443
|
+
Like the `branches` field in the ["Match" operator](#match), the properties of the `parameters` field can be specified at the root level as well -- it just depends on whichever is most appropriate for your use case. So the following is equivalent to the previous fragment node:
|
|
1444
|
+
```js
|
|
1445
|
+
{
|
|
1446
|
+
fragment: "getCapital",
|
|
1447
|
+
$country: { operator: "getData", property: "path.to.country.name" }
|
|
1448
|
+
}
|
|
1449
|
+
```
|
|
1450
|
+
|
|
1451
|
+
See `22_fragments.test.ts` for more complex examples.
|
|
1452
|
+
|
|
1453
|
+
Unlike Alias Nodes, which are evaluated *once* and then the result re-used whenever the alias is referenced, Fragments are evaluated every time, as the input parameters may differ.
|
|
1454
|
+
|
|
1386
1455
|
## Caching (Memoization)
|
|
1387
1456
|
|
|
1388
|
-
FigTree Evaluator has basic [memoization](https://en.wikipedia.org/wiki/Memoization)
|
|
1457
|
+
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
1458
|
|
|
1390
1459
|
Currently, caching is only implemented for the following operators, since they perform requests to external resources, which are inherently slow:
|
|
1391
1460
|
|
|
@@ -1431,6 +1500,9 @@ Please open an issue: https://github.com/CarlosNZ/fig-tree-evaluator/issues
|
|
|
1431
1500
|
|
|
1432
1501
|
## Changelog
|
|
1433
1502
|
|
|
1503
|
+
*Trivial upgrades (e.g. documentation only) not included*
|
|
1504
|
+
|
|
1505
|
+
- **v2.4.0**: Implement [Fragments](#fragments) (#74)
|
|
1434
1506
|
- **v2.3.2**: Bug fix: alias nodes not working with `evaluateFullObject` (#72)
|
|
1435
1507
|
- **v2.3.0**: Implement [caching/memoization](#caching-memoization) (#68)
|
|
1436
1508
|
- **v2.2.3**: Change option `objects` name to `data` (but keep backward compatibility) (#66)
|
|
@@ -1455,6 +1527,5 @@ Please open an issue: https://github.com/CarlosNZ/fig-tree-evaluator/issues
|
|
|
1455
1527
|
- more well-organised codebase
|
|
1456
1528
|
- **v1.x.x**: created specifically for [Conforma](https://github.com/openmsupply/conforma-server/wiki/Query-Syntax) application manager by [mSupplyFoundation](https://github.com/openmsupply). v2 is a complete re-write with numerous improvements, but should be 99% backwards compatible.
|
|
1457
1529
|
|
|
1458
|
-
|
|
1459
1530
|
## Credit
|
|
1460
1531
|
Icon: Tree by ka reemov from <a href="https://thenounproject.com/icon/tree-2665898/" target="_blank" title="Tree Icon">Noun Project</a>
|
package/build/evaluate.js
CHANGED
|
@@ -51,102 +51,117 @@ exports.evaluatorFunction = void 0;
|
|
|
51
51
|
var _operatorUtils_1 = require("./operators/_operatorUtils");
|
|
52
52
|
var helpers_1 = require("./helpers");
|
|
53
53
|
var evaluatorFunction = function (input, config) { return __awaiter(void 0, void 0, void 0, function () {
|
|
54
|
-
var options, operators, operatorAliases, expression, _a, fallback, returnErrorAsString,
|
|
55
|
-
var
|
|
56
|
-
return __generator(this, function (
|
|
57
|
-
switch (
|
|
54
|
+
var options, operators, operatorAliases, expression, _a, fallback, returnErrorAsString, _b, fragment, parameters, fragmentReplacement, _c, operator, _d, _e, requiredProperties, propertyAliases, evaluate, parseChildren, _f, _g, validationError, _h, _j, _k, result, err_1, _l, outputType, evaluatedOutputType, _m, err_2, _o;
|
|
55
|
+
var _p, _q, _r;
|
|
56
|
+
return __generator(this, function (_s) {
|
|
57
|
+
switch (_s.label) {
|
|
58
58
|
case 0:
|
|
59
59
|
options = config.options, operators = config.operators, operatorAliases = config.operatorAliases;
|
|
60
60
|
expression = (options === null || options === void 0 ? void 0 : options.allowJSONStringInput) ? (0, helpers_1.parseIfJson)(input) : input;
|
|
61
61
|
if (!Array.isArray(expression)) return [3, 2];
|
|
62
62
|
return [4, (0, _operatorUtils_1.evaluateArray)(expression, config)];
|
|
63
63
|
case 1:
|
|
64
|
-
expression =
|
|
65
|
-
|
|
64
|
+
expression = _s.sent();
|
|
65
|
+
_s.label = 2;
|
|
66
66
|
case 2:
|
|
67
|
-
if (!(options.evaluateFullObject && !(0, helpers_1.isOperatorNode)(expression))) return [3, 4];
|
|
67
|
+
if (!(options.evaluateFullObject && !(0, helpers_1.isOperatorNode)(expression) && !(0, helpers_1.isFragmentNode)(expression))) return [3, 4];
|
|
68
68
|
_a = helpers_1.replaceAliasNodeValues;
|
|
69
69
|
return [4, (0, helpers_1.evaluateObject)(expression, config)];
|
|
70
|
-
case 3: return [2, _a.apply(void 0, [
|
|
70
|
+
case 3: return [2, _a.apply(void 0, [_s.sent(), config])];
|
|
71
71
|
case 4:
|
|
72
|
-
if (!(0, helpers_1.isOperatorNode)(expression))
|
|
72
|
+
if (!(0, helpers_1.isOperatorNode)(expression) && !(0, helpers_1.isFragmentNode)(expression))
|
|
73
73
|
return [2, (0, helpers_1.replaceAliasNodeValues)(expression, config)];
|
|
74
74
|
fallback = expression.fallback;
|
|
75
|
-
returnErrorAsString = (
|
|
76
|
-
|
|
75
|
+
returnErrorAsString = (_p = options === null || options === void 0 ? void 0 : options.returnErrorAsString) !== null && _p !== void 0 ? _p : false;
|
|
76
|
+
if (!(0, helpers_1.isFragmentNode)(expression)) return [3, 8];
|
|
77
|
+
return [4, (0, _operatorUtils_1.evaluateArray)([expression.fragment, expression.parameters], config)];
|
|
77
78
|
case 5:
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (!!
|
|
81
|
-
|
|
79
|
+
_b = (_s.sent()), fragment = _b[0], parameters = _b[1];
|
|
80
|
+
fragmentReplacement = (_q = options === null || options === void 0 ? void 0 : options.fragments) === null || _q === void 0 ? void 0 : _q[fragment];
|
|
81
|
+
if (!!fragmentReplacement) return [3, 7];
|
|
82
|
+
_c = helpers_1.fallbackOrError;
|
|
82
83
|
return [4, (0, exports.evaluatorFunction)(fallback, config)];
|
|
83
|
-
case 6: return [2,
|
|
84
|
+
case 6: return [2, _c.apply(void 0, [_s.sent(), "Fragment not defined: ".concat(fragment), returnErrorAsString])];
|
|
84
85
|
case 7:
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
86
|
+
if (!(0, helpers_1.isOperatorNode)(fragmentReplacement))
|
|
87
|
+
return [2, fragmentReplacement];
|
|
88
|
+
expression = __assign(__assign(__assign({}, expression), fragmentReplacement), parameters);
|
|
89
|
+
delete expression.fragment;
|
|
90
|
+
delete expression.parameters;
|
|
91
|
+
_s.label = 8;
|
|
90
92
|
case 8:
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (
|
|
94
|
-
|
|
93
|
+
_s.trys.push([8, 29, , 31]);
|
|
94
|
+
operator = (0, helpers_1.getOperatorName)(expression.operator, operatorAliases);
|
|
95
|
+
if (!!operator) return [3, 10];
|
|
96
|
+
_d = helpers_1.fallbackOrError;
|
|
95
97
|
return [4, (0, exports.evaluatorFunction)(fallback, config)];
|
|
96
|
-
case 9: return [2,
|
|
98
|
+
case 9: return [2, _d.apply(void 0, [_s.sent(), "Invalid operator: ".concat(expression.operator), returnErrorAsString])];
|
|
97
99
|
case 10:
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
_e = operators[operator], requiredProperties = _e.requiredProperties, propertyAliases = _e.propertyAliases, evaluate = _e.evaluate, parseChildren = _e.parseChildren;
|
|
101
|
+
expression = (0, helpers_1.mapPropertyAliases)(propertyAliases, expression);
|
|
102
|
+
_f = config;
|
|
103
|
+
_g = [__assign({}, config.resolvedAliasNodes)];
|
|
104
|
+
return [4, (0, helpers_1.evaluateNodeAliases)(expression, config)];
|
|
102
105
|
case 11:
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if (!!Array.isArray(expression.children)) return [3, 14];
|
|
106
|
+
_f.resolvedAliasNodes = __assign.apply(void 0, _g.concat([(_s.sent())]));
|
|
107
|
+
validationError = (0, helpers_1.checkRequiredNodes)(requiredProperties, expression);
|
|
108
|
+
if (!validationError) return [3, 13];
|
|
107
109
|
_h = helpers_1.fallbackOrError;
|
|
108
110
|
return [4, (0, exports.evaluatorFunction)(fallback, config)];
|
|
109
|
-
case
|
|
110
|
-
case
|
|
111
|
+
case 12: return [2, _h.apply(void 0, [_s.sent(), "Operator: ".concat(operator, "\n- ").concat(validationError), returnErrorAsString])];
|
|
112
|
+
case 13:
|
|
113
|
+
if (!('children' in expression)) return [3, 19];
|
|
114
|
+
if (!!Array.isArray(expression.children)) return [3, 15];
|
|
115
|
+
_j = expression;
|
|
116
|
+
return [4, (0, exports.evaluatorFunction)(expression.children, config)];
|
|
117
|
+
case 14:
|
|
118
|
+
_j.children = _s.sent();
|
|
119
|
+
_s.label = 15;
|
|
111
120
|
case 15:
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
case 17:
|
|
118
|
-
_p.trys.push([17, 19, , 21]);
|
|
119
|
-
return [4, evaluate(expression, config)];
|
|
121
|
+
if (!!Array.isArray(expression.children)) return [3, 17];
|
|
122
|
+
_k = helpers_1.fallbackOrError;
|
|
123
|
+
return [4, (0, exports.evaluatorFunction)(fallback, config)];
|
|
124
|
+
case 16: return [2, _k.apply(void 0, [_s.sent(), "Operator: ".concat(operator, "\n- Property \"children\" is not of type: array"), returnErrorAsString])];
|
|
125
|
+
case 17: return [4, parseChildren(expression, config)];
|
|
120
126
|
case 18:
|
|
121
|
-
|
|
122
|
-
|
|
127
|
+
expression = _s.sent();
|
|
128
|
+
_s.label = 19;
|
|
123
129
|
case 19:
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
return [4, (0, exports.evaluatorFunction)(fallback, config)];
|
|
130
|
+
result = void 0;
|
|
131
|
+
_s.label = 20;
|
|
127
132
|
case 20:
|
|
128
|
-
|
|
129
|
-
return [
|
|
133
|
+
_s.trys.push([20, 22, , 24]);
|
|
134
|
+
return [4, evaluate(expression, config)];
|
|
130
135
|
case 21:
|
|
131
|
-
|
|
136
|
+
result = _s.sent();
|
|
137
|
+
return [3, 24];
|
|
138
|
+
case 22:
|
|
139
|
+
err_1 = _s.sent();
|
|
140
|
+
_l = helpers_1.fallbackOrError;
|
|
141
|
+
return [4, (0, exports.evaluatorFunction)(fallback, config)];
|
|
142
|
+
case 23:
|
|
143
|
+
result = _l.apply(void 0, [_s.sent(), "Operator: ".concat(operator, "\n").concat((0, helpers_1.errorMessage)(err_1)), returnErrorAsString]);
|
|
144
|
+
return [3, 24];
|
|
145
|
+
case 24:
|
|
146
|
+
outputType = (_r = expression === null || expression === void 0 ? void 0 : expression.outputType) !== null && _r !== void 0 ? _r : expression === null || expression === void 0 ? void 0 : expression.type;
|
|
132
147
|
if (!outputType)
|
|
133
148
|
return [2, result];
|
|
134
149
|
return [4, (0, exports.evaluatorFunction)(outputType, config)];
|
|
135
|
-
case
|
|
136
|
-
evaluatedOutputType = (
|
|
137
|
-
if (!!(evaluatedOutputType in helpers_1.convertOutputMethods)) return [3,
|
|
138
|
-
|
|
150
|
+
case 25:
|
|
151
|
+
evaluatedOutputType = (_s.sent());
|
|
152
|
+
if (!!(evaluatedOutputType in helpers_1.convertOutputMethods)) return [3, 27];
|
|
153
|
+
_m = helpers_1.fallbackOrError;
|
|
139
154
|
return [4, (0, exports.evaluatorFunction)(fallback, config)];
|
|
140
|
-
case
|
|
141
|
-
case
|
|
142
|
-
case
|
|
143
|
-
case
|
|
144
|
-
err_2 =
|
|
145
|
-
|
|
155
|
+
case 26: return [2, _m.apply(void 0, [_s.sent(), "Operator: ".concat(operator, "\n- Invalid output type: ").concat(evaluatedOutputType), returnErrorAsString])];
|
|
156
|
+
case 27: return [2, helpers_1.convertOutputMethods[evaluatedOutputType](result)];
|
|
157
|
+
case 28: return [3, 31];
|
|
158
|
+
case 29:
|
|
159
|
+
err_2 = _s.sent();
|
|
160
|
+
_o = helpers_1.fallbackOrError;
|
|
146
161
|
return [4, (0, exports.evaluatorFunction)(fallback, config)];
|
|
147
|
-
case
|
|
162
|
+
case 30: return [2, _o.apply(void 0, [_s.sent(), (0, helpers_1.errorMessage)(err_2),
|
|
148
163
|
returnErrorAsString])];
|
|
149
|
-
case
|
|
164
|
+
case 31: return [2];
|
|
150
165
|
}
|
|
151
166
|
});
|
|
152
167
|
}); };
|
package/build/helpers.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { OutputType, EvaluatorNode, CombinedOperatorNode, Operator, EvaluatorOutput, FigTreeOptions, OperatorNodeUnion, FigTreeConfig } from './types';
|
|
2
2
|
export declare const parseIfJson: (input: EvaluatorNode) => any;
|
|
3
3
|
export declare const isOperatorNode: (input: EvaluatorNode) => boolean;
|
|
4
|
+
export declare const isFragmentNode: (input: EvaluatorNode) => boolean;
|
|
4
5
|
export declare const getOperatorName: (operator: string, operatorAliases: {
|
|
5
6
|
[key: string]: "AND" | "OR" | "EQUAL" | "NOT_EQUAL" | "PLUS" | "SUBTRACT" | "MULTIPLY" | "DIVIDE" | "GREATER_THAN" | "LESS_THAN" | "CONDITIONAL" | "REGEX" | "OBJECT_PROPERTIES" | "STRING_SUBSTITUTION" | "SPLIT" | "COUNT" | "GET" | "POST" | "PG_SQL" | "GRAPHQL" | "BUILD_OBJECT" | "MATCH" | "CUSTOM_FUNCTIONS" | "PASSTHRU";
|
|
6
7
|
}) => "AND" | "OR" | "EQUAL" | "NOT_EQUAL" | "PLUS" | "SUBTRACT" | "MULTIPLY" | "DIVIDE" | "GREATER_THAN" | "LESS_THAN" | "CONDITIONAL" | "REGEX" | "OBJECT_PROPERTIES" | "STRING_SUBSTITUTION" | "SPLIT" | "COUNT" | "GET" | "POST" | "PG_SQL" | "GRAPHQL" | "BUILD_OBJECT" | "MATCH" | "CUSTOM_FUNCTIONS" | "PASSTHRU";
|
package/build/helpers.js
CHANGED
|
@@ -47,7 +47,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
47
47
|
}
|
|
48
48
|
};
|
|
49
49
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
-
exports.evaluateObject = exports.errorMessage = exports.convertOutputMethods = exports.mergeOptions = exports.checkRequiredNodes = exports.replaceAliasNodeValues = exports.evaluateNodeAliases = exports.mapPropertyAliases = exports.fallbackOrError = exports.truncateString = exports.getOperatorName = exports.isOperatorNode = exports.parseIfJson = void 0;
|
|
50
|
+
exports.evaluateObject = exports.errorMessage = exports.convertOutputMethods = exports.mergeOptions = exports.checkRequiredNodes = exports.replaceAliasNodeValues = exports.evaluateNodeAliases = exports.mapPropertyAliases = exports.fallbackOrError = exports.truncateString = exports.getOperatorName = exports.isFragmentNode = exports.isOperatorNode = exports.parseIfJson = void 0;
|
|
51
51
|
var change_case_1 = require("change-case");
|
|
52
52
|
var evaluate_1 = require("./evaluate");
|
|
53
53
|
var _operatorUtils_1 = require("./operators/_operatorUtils");
|
|
@@ -67,6 +67,10 @@ var isOperatorNode = function (input) {
|
|
|
67
67
|
return input instanceof Object && 'operator' in input;
|
|
68
68
|
};
|
|
69
69
|
exports.isOperatorNode = isOperatorNode;
|
|
70
|
+
var isFragmentNode = function (input) {
|
|
71
|
+
return input instanceof Object && 'fragment' in input;
|
|
72
|
+
};
|
|
73
|
+
exports.isFragmentNode = isFragmentNode;
|
|
70
74
|
var standardiseOperatorName = function (name) {
|
|
71
75
|
var camelCaseName = (0, change_case_1.camelCase)(name);
|
|
72
76
|
return camelCaseName ? camelCaseName : name;
|
|
@@ -146,6 +150,8 @@ var mergeOptions = function (origOptions, newOptions) {
|
|
|
146
150
|
combinedOptions.data = __assign(__assign({}, origOptions.data), newOptions.data);
|
|
147
151
|
if (origOptions.functions || newOptions.functions)
|
|
148
152
|
combinedOptions.functions = __assign(__assign({}, origOptions.functions), newOptions.functions);
|
|
153
|
+
if (origOptions.fragments || newOptions.fragments)
|
|
154
|
+
combinedOptions.fragments = __assign(__assign({}, origOptions.fragments), newOptions.fragments);
|
|
149
155
|
if (origOptions.headers || newOptions.headers)
|
|
150
156
|
combinedOptions.headers = __assign(__assign({}, origOptions.headers), newOptions.headers);
|
|
151
157
|
return combinedOptions;
|
package/build/index.js
CHANGED
|
@@ -1,15 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __assign = (this && this.__assign) || function () {
|
|
3
|
-
__assign = Object.assign || function(t) {
|
|
4
|
-
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
-
s = arguments[i];
|
|
6
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
-
t[p] = s[p];
|
|
8
|
-
}
|
|
9
|
-
return t;
|
|
10
|
-
};
|
|
11
|
-
return __assign.apply(this, arguments);
|
|
12
|
-
};
|
|
13
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
3
|
if (k2 === undefined) k2 = k;
|
|
15
4
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -127,7 +116,7 @@ var FigTreeEvaluator = (function () {
|
|
|
127
116
|
return this.options;
|
|
128
117
|
};
|
|
129
118
|
FigTreeEvaluator.prototype.updateOptions = function (options) {
|
|
130
|
-
this.options =
|
|
119
|
+
this.options = (0, helpers_1.mergeOptions)(this.options, standardiseOptionNames(options));
|
|
131
120
|
};
|
|
132
121
|
return FigTreeEvaluator;
|
|
133
122
|
}());
|
package/build/types.d.ts
CHANGED
|
@@ -12,6 +12,9 @@ export interface FigTreeOptions {
|
|
|
12
12
|
functions?: {
|
|
13
13
|
[key: string]: Function;
|
|
14
14
|
};
|
|
15
|
+
fragments?: {
|
|
16
|
+
[key: string]: EvaluatorNode;
|
|
17
|
+
};
|
|
15
18
|
pgConnection?: PGConnection;
|
|
16
19
|
graphQLConnection?: GraphQLConnection;
|
|
17
20
|
baseEndpoint?: string;
|
|
@@ -47,10 +50,17 @@ export interface BaseOperatorNode {
|
|
|
47
50
|
useCache?: boolean;
|
|
48
51
|
[key: string]: EvaluatorNode;
|
|
49
52
|
}
|
|
53
|
+
export interface FragmentNode {
|
|
54
|
+
fragment: string;
|
|
55
|
+
parameters?: {
|
|
56
|
+
[key: string]: EvaluatorNode;
|
|
57
|
+
};
|
|
58
|
+
[key: string]: EvaluatorNode;
|
|
59
|
+
}
|
|
50
60
|
export type CombinedOperatorNode = BaseOperatorNode & BasicExtendedNode & SubtractionNode & DivisionNode & ComparatorNode & ConditionalNode & RegexNode & StringSubNode & SplitNode & ObjPropNode & APINode & PGNode & GraphQLNode & BuildObjectNode & MatchNode & FunctionNode & PassThruNode;
|
|
51
61
|
export type OperatorNodeUnion = BasicExtendedNode | SubtractionNode | DivisionNode | ComparatorNode | ConditionalNode | RegexNode | StringSubNode | SplitNode | ObjPropNode | PGNode | GraphQLNode | APINode | BuildObjectNode | MatchNode | FunctionNode | PassThruNode;
|
|
52
62
|
export type EvaluatorOutput = string | boolean | number | GenericObject | null | undefined | any[];
|
|
53
|
-
export type EvaluatorNode = CombinedOperatorNode | EvaluatorOutput;
|
|
63
|
+
export type EvaluatorNode = CombinedOperatorNode | FragmentNode | EvaluatorOutput;
|
|
54
64
|
export type OperatorObject = {
|
|
55
65
|
requiredProperties: readonly string[];
|
|
56
66
|
operatorAliases: string[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fig-tree-evaluator",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "Module to evaluate JSON-structured expression trees",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"axios": "^0.27.2",
|
|
38
38
|
"change-case": "^4.1.2",
|
|
39
39
|
"dequal": "^2.0.3",
|
|
40
|
-
"object-property-extractor": "^1.0.
|
|
40
|
+
"object-property-extractor": "^1.0.6"
|
|
41
41
|
},
|
|
42
42
|
"bugs": {
|
|
43
43
|
"url": "https://github.com/CarlosNZ/fig-tree-evaluator/issues"
|