fig-tree-evaluator 2.4.3 → 2.5.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/README.md +20 -9
- package/build/FigTreeEvaluator.js +32 -75
- package/build/cache.js +29 -75
- package/build/evaluate.js +68 -154
- package/build/helpers.d.ts +1 -0
- package/build/helpers.js +57 -134
- package/build/index.js +1 -1
- package/build/operators/_operatorUtils.js +50 -109
- package/build/operators/buildObject.js +26 -84
- package/build/operators/conditional.js +18 -70
- package/build/operators/count.js +14 -48
- package/build/operators/customFunctions.js +25 -95
- package/build/operators/divide.js +26 -61
- package/build/operators/equal.js +23 -57
- package/build/operators/getRequest.js +36 -97
- package/build/operators/graphQL.js +40 -97
- package/build/operators/greaterThan.js +20 -54
- package/build/operators/lessThan.js +20 -54
- package/build/operators/logicalAnd.js +16 -61
- package/build/operators/logicalOr.js +14 -48
- package/build/operators/match.js +38 -101
- package/build/operators/multiply.js +14 -48
- package/build/operators/notEqual.js +23 -57
- package/build/operators/objectProperties.js +21 -66
- package/build/operators/passThru.js +15 -58
- package/build/operators/pgSQL.js +54 -134
- package/build/operators/plus.js +24 -70
- package/build/operators/postRequest.js +28 -82
- package/build/operators/regex.js +24 -70
- package/build/operators/split.js +29 -74
- package/build/operators/stringSubstitution.js +25 -79
- package/build/operators/subtract.js +16 -50
- package/build/typeCheck.js +22 -27
- package/build/types.d.ts +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
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). Examples 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
|
|
10
|
+
- configure a [decision tree](https://en.wikipedia.org/wiki/Decision_tree) to implement branching logic. (See implementation in `20_match.test.ts`)
|
|
11
11
|
- extend [JSON Forms](https://jsonforms.io) with more complex logic and dynamic lookups: https://github.com/CarlosNZ/jsonforms-with-figtree-demo
|
|
12
12
|
|
|
13
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.
|
|
@@ -105,7 +105,7 @@ Or, with a deeper structure that results in the same final output:
|
|
|
105
105
|
// -> 6
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
-
Which would be represented
|
|
108
|
+
Which would be represented diagrammatically with the following expression tree:
|
|
109
109
|
|
|
110
110
|

|
|
111
111
|
|
|
@@ -135,6 +135,12 @@ exp.evaluate(expression, [options]) // Options over-ride initial options for thi
|
|
|
135
135
|
const result = await exp.evaluate(expression, [options])
|
|
136
136
|
```
|
|
137
137
|
|
|
138
|
+
FigTreeEvaluator is written in **Typescript**, and the following types are available to import from the package:
|
|
139
|
+
- `FigTreeOptions`: `options` object, as per [options](#available-options) below
|
|
140
|
+
- `Operator`: string literal canonical [Operator](#operator-nodes) names (`AND`, `OR`, `EQUAL`, etc.)
|
|
141
|
+
- `EvaluatorNode`: Evaluator input
|
|
142
|
+
- `EvaluatorOutput`
|
|
143
|
+
|
|
138
144
|
## Available options
|
|
139
145
|
|
|
140
146
|
The `options` parameter is an object with the following available properties (all optional):
|
|
@@ -142,15 +148,15 @@ The `options` parameter is an object with the following available properties (al
|
|
|
142
148
|
- `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.
|
|
143
149
|
- `functions` -- a single object containing any *custom functions* available for use by the [customFunctions](#custom_functions) operator.
|
|
144
150
|
- `fragments` -- commonly-used expressions (with optional parameters) that can be re-used in any other expression. See [Fragments](#fragments)
|
|
145
|
-
- `pgConnection` -- if you wish to make calls to a Postgres database using the [`pgSQL` operator](#pg_sql), pass a [node-
|
|
151
|
+
- `pgConnection` -- if you wish to make calls to a Postgres database using the [`pgSQL` operator](#pg_sql), pass a [node-postgres](https://node-postgres.com/) connection object here.
|
|
146
152
|
- `graphQLConnection` -- a GraphQL connection object, if using the [`graphQL` operator](#graphql). See operator details below.
|
|
147
153
|
- `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.
|
|
148
|
-
- `headers` -- A general http headers object that will be passed to *all* http-based operators. Useful for
|
|
154
|
+
- `headers` -- A general http headers object that will be passed to *all* http-based operators. Useful for authentication headers, for example. Each operator and instance can have its own headers, though, so see specific operator reference for details.
|
|
149
155
|
- `returnErrorAsString` -- by default the evaluator will throw errors with invalid evaluation expressions (with helpful error messages indicating the node which threw the error and what the problem was). But if you have `returnErrorAsString: true` set, the evaluator will never throw, but instead return error messages as a valid string output. (See also the [`fallback`](#other-common-properties) parameter below)
|
|
150
156
|
- `allowJSONStringInput` -- the evaluator is expecting the input expression to be a javascript object. However, it will also accept JSON strings if this option is set to `true`. We have to perform additional logic on every evaluation input to determine if a string is a JSON expression or a standard string, so this is skipped by default for performance reasons. However, if you want to send (for example) user input directly to the evaluator without running it through your own `JSON.parse()`, then enable this option.
|
|
151
157
|
- `skipRuntimeTypeCheck` -- we perform comprehensive type checking at runtime to ensure that each operator only performs its operation on valid inputs. If type checking fails, we throw an error detailing the explicit problem. However, if `skipRuntimeTypeCheck` is set to `true`, then all inputs are passed to the operator regardless, and any errors will come from whatever standard javascript errors might be encountered (e.g. trying to pass a primitive value when an array is expected => `.map is not a function`)
|
|
152
158
|
- `nullEqualsUndefined` -- this only affects the [`equal`/`notEqual` operators](#equal) (see there for more detail).
|
|
153
|
-
- `evaluateFullObject` -- by default, FigTree expects the root of an input expression to be an [Operator Node](#operator-nodes), and if not, will return the input unmodified. However, you may have cases where the evaluation expressions are deep within a larger structure (such as a JSON schema, for example). In this case, you can set `evaluateFullObject` to `true` and the evaluator will find *any* operator nodes within the structure and evaluate them
|
|
159
|
+
- `evaluateFullObject` -- by default, FigTree expects the root of an input expression to be an [Operator Node](#operator-nodes), and if not, will return the input unmodified. However, you may have cases where the evaluation expressions are deep within a larger structure (such as a JSON schema, for example). In this case, you can set `evaluateFullObject` to `true` and the evaluator will find *any* operator nodes within the structure and evaluate them within the object tree.
|
|
154
160
|
- `useCache` -- caches the results from certain operators to avoid repeated network requests with the same input values. By default, this is set to `true`, and it can be overridden for specific nodes. See [Memoization/Caching section](#caching-memoization) for more detail
|
|
155
161
|
- `maxCacheSize` -- the maximum number of results that will be held in the aforementioned cache (default: `50`)
|
|
156
162
|
|
|
@@ -193,7 +199,7 @@ For example, the following two representations are equivalent `conditional` oper
|
|
|
193
199
|
```js
|
|
194
200
|
{
|
|
195
201
|
operator: "?", // conditional (alias)
|
|
196
|
-
condition: 1 + 1 ==== 2
|
|
202
|
+
condition: 1 + 1 ==== 2,
|
|
197
203
|
valueIfTrue: "True output",
|
|
198
204
|
valueIfFalse: "False output"
|
|
199
205
|
}
|
|
@@ -1043,7 +1049,7 @@ Aliases: `pgSql`, `sql`, `postgres`, `pg`, `pgDb`
|
|
|
1043
1049
|
|
|
1044
1050
|
- `query`<sup>*</sup>: (string) -- SQL query string, with parameterised replacements (i.e. `$1`, `$2`, etc)
|
|
1045
1051
|
- `values` (or `replacements`): (array) -- replacements for the `query` parameters
|
|
1046
|
-
- `type
|
|
1052
|
+
- `type` (or `queryType`): (`"array" | "string" | "number"`) -- determines the shape of the resulting data. To quote `node-postgres`:
|
|
1047
1053
|
> By default node-postgres reads rows and collects them into JavaScript objects with the keys matching the column names and the values matching the corresponding row value for each column. If you do not need or do not want this behavior you can pass rowMode: 'array' to a query object. This will inform the result parser to bypass collecting rows into a JavaScript object, and instead will return each row as an array of values.
|
|
1048
1054
|
|
|
1049
1055
|
We extend this a step further by flattening the array, and (if `"string"` or `"number"`) converting the result to a concatenated string or (if possible) number.
|
|
@@ -1468,6 +1474,8 @@ This is different to the memoization provided by [Alias Nodes](#alias-nodes):
|
|
|
1468
1474
|
- Alias nodes are still evaluated once for every evaluation -- they're more for re-use *within* a complex expression.
|
|
1469
1475
|
- Cached nodes will persist *between* different evaluations as long as the input values are the same as a previously evaluated node.
|
|
1470
1476
|
|
|
1477
|
+
Caching is enabled by default for most of the above operators, but this can be overridden by setting `useCache: false` in [options](#available-options), either globally or per expression. If you're querying a database or API that is likely to have a different result for the same request (i.e. data has changed), then you probably want to turn the cache off.
|
|
1478
|
+
|
|
1471
1479
|
## More examples
|
|
1472
1480
|
|
|
1473
1481
|
More examples, included large, complex expressions can be found within the test suites in the [repository](https://github.com/CarlosNZ/fig-tree-evaluator).
|
|
@@ -1502,6 +1510,9 @@ Please open an issue: https://github.com/CarlosNZ/fig-tree-evaluator/issues
|
|
|
1502
1510
|
|
|
1503
1511
|
*Trivial upgrades (e.g. documentation, small re-factors, types, etc.) not included*
|
|
1504
1512
|
|
|
1513
|
+
- **v2.5.0**:
|
|
1514
|
+
- Bug fixes for edge cases (mainly related to backwards compatibility)
|
|
1515
|
+
- More backwards compatibility for very old (pre-v1) syntax (undocumented)
|
|
1505
1516
|
- **v2.4.1**: Small bug fix for Fragments edge case
|
|
1506
1517
|
- **v2.4.0**: Implement [Fragments](#fragments) (#74)
|
|
1507
1518
|
- **v2.3.2**: Bug fix: alias nodes not working with `evaluateFullObject` (#72)
|
|
@@ -1510,7 +1521,7 @@ Please open an issue: https://github.com/CarlosNZ/fig-tree-evaluator/issues
|
|
|
1510
1521
|
- **v2.2.2**: Option to evaluate whole object if operator nodes are deep within it (#64)
|
|
1511
1522
|
- **v2.2.1**: More efficient branch evaluation for condition/match operators (#63)
|
|
1512
1523
|
- **v2.2.0**:
|
|
1513
|
-
- New "[Match](#match) operator (#61)
|
|
1524
|
+
- New "[Match](#match)" operator (#61)
|
|
1514
1525
|
- Fix for regex incompatibility with Safari (#60)
|
|
1515
1526
|
- **v2.1.5**: Demo updates (no changes to core evaluator)
|
|
1516
1527
|
- **v2.1.4**: Upgrade dependencies
|
|
@@ -31,101 +31,58 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
31
31
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
32
|
});
|
|
33
33
|
};
|
|
34
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
35
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
36
|
-
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
37
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
38
|
-
function step(op) {
|
|
39
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
40
|
-
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
41
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
42
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
43
|
-
switch (op[0]) {
|
|
44
|
-
case 0: case 1: t = op; break;
|
|
45
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
46
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
47
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
48
|
-
default:
|
|
49
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
50
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
51
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
52
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
53
|
-
if (t[2]) _.ops.pop();
|
|
54
|
-
_.trys.pop(); continue;
|
|
55
|
-
}
|
|
56
|
-
op = body.call(thisArg, _);
|
|
57
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
58
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
34
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
62
35
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
63
36
|
};
|
|
64
37
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
65
38
|
exports.evaluateExpression = void 0;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
var args = [];
|
|
78
|
-
for (var _i = 0; _i < arguments.length; _i++) {
|
|
79
|
-
args[_i] = arguments[_i];
|
|
80
|
-
}
|
|
81
|
-
var result = typeCheck_1.typeCheck.apply(void 0, args);
|
|
39
|
+
const evaluate_1 = require("./evaluate");
|
|
40
|
+
const typeCheck_1 = require("./typeCheck");
|
|
41
|
+
const _operatorAliases_json_1 = __importDefault(require("./operators/_operatorAliases.json"));
|
|
42
|
+
const operators = __importStar(require("./operators"));
|
|
43
|
+
const helpers_1 = require("./helpers");
|
|
44
|
+
const cache_1 = __importDefault(require("./cache"));
|
|
45
|
+
const pkg = require('../package.json');
|
|
46
|
+
class FigTreeEvaluator {
|
|
47
|
+
constructor(options = {}) {
|
|
48
|
+
this.typeChecker = (...args) => {
|
|
49
|
+
const result = (0, typeCheck_1.typeCheck)(...args);
|
|
82
50
|
if (result === true)
|
|
83
51
|
return;
|
|
84
52
|
throw new Error(result);
|
|
85
53
|
};
|
|
86
|
-
this.getVersion =
|
|
54
|
+
this.getVersion = () => pkg.version;
|
|
87
55
|
this.options = standardiseOptionNames(options);
|
|
88
56
|
this.operators = operators;
|
|
89
57
|
this.operatorAliases = _operatorAliases_json_1.default;
|
|
90
58
|
this.cache = new cache_1.default(options.maxCacheSize);
|
|
91
59
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
operators: this.operators,
|
|
105
|
-
operatorAliases: this.operatorAliases,
|
|
106
|
-
typeChecker: currentOptions.skipRuntimeTypeCheck ? function () { } : this.typeChecker,
|
|
107
|
-
resolvedAliasNodes: {},
|
|
108
|
-
cache: this.cache,
|
|
109
|
-
})];
|
|
110
|
-
case 1: return [2, _a.sent()];
|
|
111
|
-
}
|
|
60
|
+
evaluate(expression, options = {}) {
|
|
61
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
62
|
+
const currentOptions = (0, helpers_1.mergeOptions)(this.options, standardiseOptionNames(options));
|
|
63
|
+
if (currentOptions.maxCacheSize && currentOptions.maxCacheSize !== this.cache.getMax())
|
|
64
|
+
this.cache.setMax(currentOptions.maxCacheSize);
|
|
65
|
+
return yield (0, evaluate_1.evaluatorFunction)(expression, {
|
|
66
|
+
options: currentOptions,
|
|
67
|
+
operators: this.operators,
|
|
68
|
+
operatorAliases: this.operatorAliases,
|
|
69
|
+
typeChecker: currentOptions.skipRuntimeTypeCheck ? () => { } : this.typeChecker,
|
|
70
|
+
resolvedAliasNodes: {},
|
|
71
|
+
cache: this.cache,
|
|
112
72
|
});
|
|
113
73
|
});
|
|
114
|
-
}
|
|
115
|
-
|
|
74
|
+
}
|
|
75
|
+
getOptions() {
|
|
116
76
|
return this.options;
|
|
117
|
-
}
|
|
118
|
-
|
|
77
|
+
}
|
|
78
|
+
updateOptions(options) {
|
|
119
79
|
this.options = (0, helpers_1.mergeOptions)(this.options, standardiseOptionNames(options));
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
}());
|
|
80
|
+
}
|
|
81
|
+
}
|
|
123
82
|
exports.default = FigTreeEvaluator;
|
|
124
|
-
|
|
125
|
-
return new FigTreeEvaluator(options).evaluate(expression);
|
|
126
|
-
};
|
|
83
|
+
const evaluateExpression = (expression, options) => new FigTreeEvaluator(options).evaluate(expression);
|
|
127
84
|
exports.evaluateExpression = evaluateExpression;
|
|
128
|
-
|
|
85
|
+
const standardiseOptionNames = (options) => {
|
|
129
86
|
if ('objects' in options) {
|
|
130
87
|
options.data = options.objects;
|
|
131
88
|
delete options.objects;
|
package/build/cache.js
CHANGED
|
@@ -8,88 +8,42 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
-
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
-
function step(op) {
|
|
16
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
-
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
-
switch (op[0]) {
|
|
21
|
-
case 0: case 1: t = op; break;
|
|
22
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
-
default:
|
|
26
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
-
if (t[2]) _.ops.pop();
|
|
31
|
-
_.trys.pop(); continue;
|
|
32
|
-
}
|
|
33
|
-
op = body.call(thisArg, _);
|
|
34
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
12
|
+
const MAX_CACHED_ITEMS = 50;
|
|
13
|
+
class FigTreeCache {
|
|
14
|
+
constructor(maxSize) {
|
|
15
|
+
this.useCache = (shouldUseCache, action, ...args) => __awaiter(this, void 0, void 0, function* () {
|
|
16
|
+
if (!shouldUseCache)
|
|
17
|
+
return yield action(...args);
|
|
18
|
+
const key = stringifyInput(args);
|
|
19
|
+
if (key in this.store) {
|
|
20
|
+
this.queue = this.queue.filter((val) => val !== key);
|
|
21
|
+
this.queue.unshift(key);
|
|
22
|
+
return this.store[key];
|
|
47
23
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
this.queue.unshift(key);
|
|
62
|
-
return [2, this.store[key]];
|
|
63
|
-
}
|
|
64
|
-
return [4, action.apply(void 0, args)];
|
|
65
|
-
case 3:
|
|
66
|
-
result = _a.sent();
|
|
67
|
-
this.store[key] = result;
|
|
68
|
-
if (this.queue.length >= this.maxSize) {
|
|
69
|
-
keysToRemove = this.queue.slice(this.maxSize - 1);
|
|
70
|
-
keysToRemove.forEach(function (key) { return delete _this.store[key]; });
|
|
71
|
-
this.queue = this.queue.slice(0, this.maxSize - 1);
|
|
72
|
-
}
|
|
73
|
-
this.queue.unshift(key);
|
|
74
|
-
return [2, result];
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
};
|
|
79
|
-
this.getMax = function () { return _this.maxSize; };
|
|
80
|
-
this.setMax = function (size) {
|
|
81
|
-
_this.maxSize = size;
|
|
24
|
+
const result = yield action(...args);
|
|
25
|
+
this.store[key] = result;
|
|
26
|
+
if (this.queue.length >= this.maxSize) {
|
|
27
|
+
const keysToRemove = this.queue.slice(this.maxSize - 1);
|
|
28
|
+
keysToRemove.forEach((key) => delete this.store[key]);
|
|
29
|
+
this.queue = this.queue.slice(0, this.maxSize - 1);
|
|
30
|
+
}
|
|
31
|
+
this.queue.unshift(key);
|
|
32
|
+
return result;
|
|
33
|
+
});
|
|
34
|
+
this.getMax = () => this.maxSize;
|
|
35
|
+
this.setMax = (size) => {
|
|
36
|
+
this.maxSize = size;
|
|
82
37
|
};
|
|
83
38
|
this.store = {};
|
|
84
39
|
this.queue = [];
|
|
85
40
|
this.maxSize = maxSize !== null && maxSize !== void 0 ? maxSize : MAX_CACHED_ITEMS;
|
|
86
41
|
}
|
|
87
|
-
|
|
88
|
-
}());
|
|
42
|
+
}
|
|
89
43
|
exports.default = FigTreeCache;
|
|
90
|
-
|
|
91
|
-
return args.reduce(
|
|
92
|
-
|
|
93
|
-
return index === 0 ?
|
|
44
|
+
const stringifyInput = (args) => {
|
|
45
|
+
return args.reduce((outputString, arg, index) => {
|
|
46
|
+
const part = typeof arg === 'object' ? JSON.stringify(arg) : arg;
|
|
47
|
+
return index === 0 ? `${part}` : `${outputString}_${part}`;
|
|
94
48
|
}, '');
|
|
95
49
|
};
|
package/build/evaluate.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 __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
14
3
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
15
4
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -19,150 +8,75 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
19
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20
9
|
});
|
|
21
10
|
};
|
|
22
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
23
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
24
|
-
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
25
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
26
|
-
function step(op) {
|
|
27
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
28
|
-
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
29
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
30
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
31
|
-
switch (op[0]) {
|
|
32
|
-
case 0: case 1: t = op; break;
|
|
33
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
34
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
35
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
36
|
-
default:
|
|
37
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
38
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
39
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
40
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
41
|
-
if (t[2]) _.ops.pop();
|
|
42
|
-
_.trys.pop(); continue;
|
|
43
|
-
}
|
|
44
|
-
op = body.call(thisArg, _);
|
|
45
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
46
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
12
|
exports.evaluatorFunction = void 0;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
var
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
case 9: return [2, _d.apply(void 0, [_s.sent(), "Invalid operator: ".concat(expression.operator), returnErrorAsString])];
|
|
99
|
-
case 10:
|
|
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)];
|
|
105
|
-
case 11:
|
|
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];
|
|
109
|
-
_h = helpers_1.fallbackOrError;
|
|
110
|
-
return [4, (0, exports.evaluatorFunction)(fallback, config)];
|
|
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;
|
|
120
|
-
case 15:
|
|
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)];
|
|
126
|
-
case 18:
|
|
127
|
-
expression = _s.sent();
|
|
128
|
-
_s.label = 19;
|
|
129
|
-
case 19:
|
|
130
|
-
result = void 0;
|
|
131
|
-
_s.label = 20;
|
|
132
|
-
case 20:
|
|
133
|
-
_s.trys.push([20, 22, , 24]);
|
|
134
|
-
return [4, evaluate(expression, config)];
|
|
135
|
-
case 21:
|
|
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;
|
|
147
|
-
if (!outputType)
|
|
148
|
-
return [2, result];
|
|
149
|
-
return [4, (0, exports.evaluatorFunction)(outputType, config)];
|
|
150
|
-
case 25:
|
|
151
|
-
evaluatedOutputType = (_s.sent());
|
|
152
|
-
if (!!(evaluatedOutputType in helpers_1.convertOutputMethods)) return [3, 27];
|
|
153
|
-
_m = helpers_1.fallbackOrError;
|
|
154
|
-
return [4, (0, exports.evaluatorFunction)(fallback, config)];
|
|
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;
|
|
161
|
-
return [4, (0, exports.evaluatorFunction)(fallback, config)];
|
|
162
|
-
case 30: return [2, _o.apply(void 0, [_s.sent(), (0, helpers_1.errorMessage)(err_2),
|
|
163
|
-
returnErrorAsString])];
|
|
164
|
-
case 31: return [2];
|
|
13
|
+
const _operatorUtils_1 = require("./operators/_operatorUtils");
|
|
14
|
+
const helpers_1 = require("./helpers");
|
|
15
|
+
const evaluatorFunction = (input, config) => __awaiter(void 0, void 0, void 0, function* () {
|
|
16
|
+
var _a, _b, _c;
|
|
17
|
+
const { options, operators, operatorAliases } = config;
|
|
18
|
+
let expression = (options === null || options === void 0 ? void 0 : options.allowJSONStringInput) ? (0, helpers_1.parseIfJson)(input) : input;
|
|
19
|
+
if (Array.isArray(expression)) {
|
|
20
|
+
expression = yield (0, _operatorUtils_1.evaluateArray)(expression, config);
|
|
21
|
+
}
|
|
22
|
+
const isOperator = (0, helpers_1.isOperatorNode)(expression);
|
|
23
|
+
const isFragment = (0, helpers_1.isFragmentNode)(expression);
|
|
24
|
+
if (options.evaluateFullObject && !isOperator && !isFragment)
|
|
25
|
+
return (0, helpers_1.replaceAliasNodeValues)(yield (0, helpers_1.evaluateObject)(expression, config), config);
|
|
26
|
+
if (!isOperator && !isFragment) {
|
|
27
|
+
if (options.supportDeprecatedValueNodes && (0, helpers_1.isObject)(expression) && 'value' in expression)
|
|
28
|
+
return expression.value;
|
|
29
|
+
return (0, helpers_1.replaceAliasNodeValues)(expression, config);
|
|
30
|
+
}
|
|
31
|
+
const { fallback } = expression;
|
|
32
|
+
const returnErrorAsString = (_a = options === null || options === void 0 ? void 0 : options.returnErrorAsString) !== null && _a !== void 0 ? _a : false;
|
|
33
|
+
if (isFragment) {
|
|
34
|
+
const [fragment, parameters] = (yield (0, _operatorUtils_1.evaluateArray)([expression.fragment, expression.parameters], config));
|
|
35
|
+
const fragmentReplacement = (_b = options === null || options === void 0 ? void 0 : options.fragments) === null || _b === void 0 ? void 0 : _b[fragment];
|
|
36
|
+
if (fragmentReplacement === undefined)
|
|
37
|
+
return (0, helpers_1.fallbackOrError)(yield (0, exports.evaluatorFunction)(fallback, config), `Fragment not defined: ${fragment}`, returnErrorAsString);
|
|
38
|
+
if (!(0, helpers_1.isOperatorNode)(fragmentReplacement))
|
|
39
|
+
return fragmentReplacement;
|
|
40
|
+
expression = Object.assign(Object.assign(Object.assign({}, expression), fragmentReplacement), parameters);
|
|
41
|
+
delete expression.fragment;
|
|
42
|
+
delete expression.parameters;
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const operator = (0, helpers_1.getOperatorName)(expression.operator, operatorAliases);
|
|
46
|
+
if (!operator)
|
|
47
|
+
return (0, helpers_1.fallbackOrError)(yield (0, exports.evaluatorFunction)(fallback, config), `Invalid operator: ${expression.operator}`, returnErrorAsString);
|
|
48
|
+
const { requiredProperties, propertyAliases, evaluate, parseChildren } = operators[operator];
|
|
49
|
+
expression = (0, helpers_1.mapPropertyAliases)(propertyAliases, expression);
|
|
50
|
+
config.resolvedAliasNodes = Object.assign(Object.assign({}, config.resolvedAliasNodes), (yield (0, helpers_1.evaluateNodeAliases)(expression, config)));
|
|
51
|
+
const validationError = (0, helpers_1.checkRequiredNodes)(requiredProperties, expression);
|
|
52
|
+
if (validationError)
|
|
53
|
+
return (0, helpers_1.fallbackOrError)(yield (0, exports.evaluatorFunction)(fallback, config), `Operator: ${operator}\n- ${validationError}`, returnErrorAsString);
|
|
54
|
+
if ('children' in expression) {
|
|
55
|
+
if (!Array.isArray(expression.children))
|
|
56
|
+
expression.children = yield (0, exports.evaluatorFunction)(expression.children, config);
|
|
57
|
+
if (!Array.isArray(expression.children))
|
|
58
|
+
return (0, helpers_1.fallbackOrError)(yield (0, exports.evaluatorFunction)(fallback, config), `Operator: ${operator}\n- Property "children" is not of type: array`, returnErrorAsString);
|
|
59
|
+
expression = yield parseChildren(expression, config);
|
|
165
60
|
}
|
|
166
|
-
|
|
167
|
-
|
|
61
|
+
let result;
|
|
62
|
+
try {
|
|
63
|
+
result = yield evaluate(expression, config);
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
result = (0, helpers_1.fallbackOrError)(yield (0, exports.evaluatorFunction)(expression.fallback, config), `Operator: ${operator}\n${(0, helpers_1.errorMessage)(err)}`, returnErrorAsString);
|
|
67
|
+
}
|
|
68
|
+
const outputType = (_c = expression === null || expression === void 0 ? void 0 : expression.outputType) !== null && _c !== void 0 ? _c : expression === null || expression === void 0 ? void 0 : expression.type;
|
|
69
|
+
if (!outputType)
|
|
70
|
+
return result;
|
|
71
|
+
const evaluatedOutputType = (yield (0, exports.evaluatorFunction)(outputType, config));
|
|
72
|
+
if (!(evaluatedOutputType in helpers_1.convertOutputMethods))
|
|
73
|
+
return (0, helpers_1.fallbackOrError)(yield (0, exports.evaluatorFunction)(fallback, config), `Operator: ${operator}\n- Invalid output type: ${evaluatedOutputType}`, returnErrorAsString);
|
|
74
|
+
else {
|
|
75
|
+
return helpers_1.convertOutputMethods[evaluatedOutputType](result);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
return (0, helpers_1.fallbackOrError)(yield (0, exports.evaluatorFunction)(fallback, config), (0, helpers_1.errorMessage)(err), returnErrorAsString);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
168
82
|
exports.evaluatorFunction = evaluatorFunction;
|
package/build/helpers.d.ts
CHANGED
|
@@ -20,4 +20,5 @@ export declare const convertOutputMethods: {
|
|
|
20
20
|
[key in OutputType]: (value: EvaluatorOutput) => EvaluatorOutput | EvaluatorOutput[];
|
|
21
21
|
};
|
|
22
22
|
export declare const errorMessage: (err: unknown) => string;
|
|
23
|
+
export declare const isObject: (input: unknown) => boolean;
|
|
23
24
|
export declare const evaluateObject: (input: EvaluatorNode, config: FigTreeConfig) => Promise<EvaluatorOutput>;
|