fig-tree-evaluator 2.0.3 → 2.1.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 +73 -6
- package/build/evaluate.js +2 -1
- package/build/helpers.d.ts +5 -1
- package/build/helpers.js +29 -1
- package/build/index.js +1 -0
- package/build/operators/customFunctions.js +2 -2
- package/build/types.d.ts +4 -0
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -43,6 +43,7 @@ A range of built-in operators are available, from simple logic, arithmetic and s
|
|
|
43
43
|
- [BUILD_OBJECT](#build_object)
|
|
44
44
|
- [PASSTHRU](#passthru)
|
|
45
45
|
- [CUSTOM_FUNCTIONS](#custom_functions)
|
|
46
|
+
- [Alias Nodes](#alias-nodes)
|
|
46
47
|
- [More examples](#more-examples)
|
|
47
48
|
- [Development environment](#development-environment)
|
|
48
49
|
- [Tests](#tests)
|
|
@@ -846,11 +847,6 @@ e.g.
|
|
|
846
847
|
`children` array: `[value, delimiter]`
|
|
847
848
|
(`trimWhiteSpace` and `excludeTrailing` not available, since array can only support one optional parameter)
|
|
848
849
|
|
|
849
|
-
- `urlObject`: either a url string, or an object structured as `{url: <string>, headers: <object>}` (if additional headers are required)
|
|
850
|
-
- `parameterKeys`: an array of strings representing the keys of any query parameters
|
|
851
|
-
- `...values`: one value for each key specified in `parameterKeys`
|
|
852
|
-
- `returnProperty` (optional): as above
|
|
853
|
-
|
|
854
850
|
---
|
|
855
851
|
### GET
|
|
856
852
|
|
|
@@ -1218,6 +1214,77 @@ e.g.
|
|
|
1218
1214
|
// => 198
|
|
1219
1215
|
```
|
|
1220
1216
|
|
|
1217
|
+
## Alias Nodes
|
|
1218
|
+
|
|
1219
|
+
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.
|
|
1220
|
+
|
|
1221
|
+
For example, if you have the expression:
|
|
1222
|
+
```js
|
|
1223
|
+
{
|
|
1224
|
+
operator: "?",
|
|
1225
|
+
condition: {
|
|
1226
|
+
operator: "!=",
|
|
1227
|
+
values: [
|
|
1228
|
+
{
|
|
1229
|
+
operator: "GET",
|
|
1230
|
+
children: [
|
|
1231
|
+
"https://restcountries.com/v3.1/name/zealand",
|
|
1232
|
+
[],
|
|
1233
|
+
"name.common"
|
|
1234
|
+
],
|
|
1235
|
+
type: "string"
|
|
1236
|
+
},
|
|
1237
|
+
null
|
|
1238
|
+
]
|
|
1239
|
+
},
|
|
1240
|
+
valueIfTrue: {
|
|
1241
|
+
operator: "GET",
|
|
1242
|
+
children: [
|
|
1243
|
+
"https://restcountries.com/v3.1/name/zealand",
|
|
1244
|
+
[],
|
|
1245
|
+
"name.common"
|
|
1246
|
+
],
|
|
1247
|
+
type: "string"
|
|
1248
|
+
},
|
|
1249
|
+
valueIfFalse: "Not New Zealand"
|
|
1250
|
+
}
|
|
1251
|
+
```
|
|
1252
|
+
|
|
1253
|
+
The `GET` operation is used twice -- once to compare it for non-equality with `null`, and once again to return its value if `true`. This is particularly wasteful since it is a network request.
|
|
1254
|
+
|
|
1255
|
+
We can create an alias for this whole node, resulting in this equivalent expression:
|
|
1256
|
+
```js
|
|
1257
|
+
{
|
|
1258
|
+
$getCountry: {
|
|
1259
|
+
operator: "GET",
|
|
1260
|
+
children: [
|
|
1261
|
+
"https://restcountries.com/v3.1/name/zealand",
|
|
1262
|
+
[],
|
|
1263
|
+
"name.common"
|
|
1264
|
+
],
|
|
1265
|
+
type: "string"
|
|
1266
|
+
},
|
|
1267
|
+
operator: "?",
|
|
1268
|
+
condition: {
|
|
1269
|
+
operator: "!=",
|
|
1270
|
+
values: [
|
|
1271
|
+
"$getCountry",
|
|
1272
|
+
null
|
|
1273
|
+
]
|
|
1274
|
+
},
|
|
1275
|
+
valueIfTrue: "$getCountry",
|
|
1276
|
+
valueIfFalse: "Not New Zealand"
|
|
1277
|
+
}
|
|
1278
|
+
```
|
|
1279
|
+
|
|
1280
|
+
Alias nodes are defined as part of the expression object, using `$` prefix to identify them as such, in this case `$getCountry`, which returns the result of the network request that was called twice in the previous expression.
|
|
1281
|
+
|
|
1282
|
+
Alias nodes are evaluated first, then the results are substituted in whenever they are referenced elsewhere.
|
|
1283
|
+
|
|
1284
|
+
Like all expression nodes, alias nodes can themselves contain complex expressions with their own alias nodes defined within. As long as the alias references are descendent nodes of the alias definition, they will be resolved.
|
|
1285
|
+
|
|
1286
|
+
(If an alias reference does not having a matching definition, the reference value will just be returned as a literal string, e.g. `"$getCountry"`)
|
|
1287
|
+
|
|
1221
1288
|
## More examples
|
|
1222
1289
|
|
|
1223
1290
|
More examples, included large, complex expressions can be found within the test suites in the [repository](https://github.com/CarlosNZ/fig-tree-evaluator).
|
|
@@ -1250,7 +1317,7 @@ Please open an issue: https://github.com/CarlosNZ/fig-tree-evaluator/issues
|
|
|
1250
1317
|
|
|
1251
1318
|
## Changelog
|
|
1252
1319
|
|
|
1253
|
-
|
|
1320
|
+
- **v2.0.4**: Backwards compatibility for customFunctions (#53)
|
|
1254
1321
|
- **v2.0.1**: Add deep equality comparison for objects/arrayr in =/!= operators
|
|
1255
1322
|
- **v2.0.0**: Re-write as stand-alone package. Major improvements include:
|
|
1256
1323
|
- more [operators](#operator-reference)
|
package/build/evaluate.js
CHANGED
|
@@ -20,7 +20,7 @@ const evaluatorFunction = (input, config) => __awaiter(void 0, void 0, void 0, f
|
|
|
20
20
|
expression = yield (0, _operatorUtils_1.evaluateArray)(expression, config);
|
|
21
21
|
}
|
|
22
22
|
if (!(0, helpers_1.isOperatorNode)(expression))
|
|
23
|
-
return expression;
|
|
23
|
+
return (0, helpers_1.replaceAliasNodeValues)(expression, config);
|
|
24
24
|
const { fallback } = expression;
|
|
25
25
|
const returnErrorAsString = (_a = options === null || options === void 0 ? void 0 : options.returnErrorAsString) !== null && _a !== void 0 ? _a : false;
|
|
26
26
|
try {
|
|
@@ -29,6 +29,7 @@ const evaluatorFunction = (input, config) => __awaiter(void 0, void 0, void 0, f
|
|
|
29
29
|
return (0, helpers_1.fallbackOrError)(yield (0, exports.evaluatorFunction)(fallback, config), `Invalid operator: ${expression.operator}`, returnErrorAsString);
|
|
30
30
|
const { requiredProperties, propertyAliases, evaluate, parseChildren } = operators[operator];
|
|
31
31
|
expression = (0, helpers_1.mapPropertyAliases)(propertyAliases, expression);
|
|
32
|
+
config.resolvedAliasNodes = Object.assign(Object.assign({}, config.resolvedAliasNodes), (yield (0, helpers_1.evaluateNodeAliases)(expression, config)));
|
|
32
33
|
const validationError = (0, helpers_1.checkRequiredNodes)(requiredProperties, expression);
|
|
33
34
|
if (validationError)
|
|
34
35
|
return (0, helpers_1.fallbackOrError)(yield (0, exports.evaluatorFunction)(fallback, config), `Operator: ${operator}\n- ${validationError}`, returnErrorAsString);
|
package/build/helpers.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { OutputType, EvaluatorNode, CombinedOperatorNode, Operator, EvaluatorOutput, FigTreeOptions } from './types';
|
|
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
4
|
export declare const getOperatorName: (operator: string, operatorAliases: {
|
|
@@ -9,6 +9,10 @@ export declare const fallbackOrError: (fallback: any, errorMessage: string, retu
|
|
|
9
9
|
export declare const mapPropertyAliases: (propertyAliases: {
|
|
10
10
|
[key: string]: string;
|
|
11
11
|
}, expression: CombinedOperatorNode) => CombinedOperatorNode;
|
|
12
|
+
export declare const evaluateNodeAliases: (expression: OperatorNodeUnion, config: FigTreeConfig) => Promise<{
|
|
13
|
+
[x: string]: EvaluatorOutput;
|
|
14
|
+
}>;
|
|
15
|
+
export declare const replaceAliasNodeValues: (value: EvaluatorOutput, { resolvedAliasNodes }: FigTreeConfig) => EvaluatorOutput;
|
|
12
16
|
export declare const checkRequiredNodes: (requiredProps: readonly string[], expression: CombinedOperatorNode) => string | false;
|
|
13
17
|
export declare const mergeOptions: (origOptions: FigTreeOptions, newOptions: FigTreeOptions) => FigTreeOptions;
|
|
14
18
|
export declare const convertOutputMethods: {
|
package/build/helpers.js
CHANGED
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
2
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.errorMessage = exports.convertOutputMethods = exports.mergeOptions = exports.checkRequiredNodes = exports.mapPropertyAliases = exports.fallbackOrError = exports.truncateString = exports.getOperatorName = exports.isOperatorNode = exports.parseIfJson = void 0;
|
|
12
|
+
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;
|
|
4
13
|
const change_case_1 = require("change-case");
|
|
14
|
+
const evaluate_1 = require("./evaluate");
|
|
15
|
+
const _operatorUtils_1 = require("./operators/_operatorUtils");
|
|
5
16
|
const parseIfJson = (input) => {
|
|
6
17
|
if (typeof input !== 'string')
|
|
7
18
|
return input;
|
|
@@ -40,6 +51,23 @@ const mapObjectKeys = (inputObj, mapFunction) => {
|
|
|
40
51
|
const mappedKeys = keyVals.map(([key, value]) => [mapFunction(key), value]);
|
|
41
52
|
return Object.fromEntries(mappedKeys);
|
|
42
53
|
};
|
|
54
|
+
const isAliasString = (value) => /^\$.+/.test(value);
|
|
55
|
+
const evaluateNodeAliases = (expression, config) => __awaiter(void 0, void 0, void 0, function* () {
|
|
56
|
+
const aliasKeys = Object.keys(expression).filter(isAliasString);
|
|
57
|
+
if (aliasKeys.length === 0)
|
|
58
|
+
return expression;
|
|
59
|
+
const evaluations = [];
|
|
60
|
+
aliasKeys.forEach((alias) => evaluations.push((0, evaluate_1.evaluatorFunction)(expression[alias], config)));
|
|
61
|
+
return (0, _operatorUtils_1.zipArraysToObject)(aliasKeys, yield Promise.all(evaluations));
|
|
62
|
+
});
|
|
63
|
+
exports.evaluateNodeAliases = evaluateNodeAliases;
|
|
64
|
+
const replaceAliasNodeValues = (value, { resolvedAliasNodes }) => {
|
|
65
|
+
var _a;
|
|
66
|
+
if (typeof value !== 'string' || !isAliasString(value))
|
|
67
|
+
return value;
|
|
68
|
+
return (_a = resolvedAliasNodes === null || resolvedAliasNodes === void 0 ? void 0 : resolvedAliasNodes[value]) !== null && _a !== void 0 ? _a : value;
|
|
69
|
+
};
|
|
70
|
+
exports.replaceAliasNodeValues = replaceAliasNodeValues;
|
|
43
71
|
const checkRequiredNodes = (requiredProps, expression) => {
|
|
44
72
|
const missingProps = requiredProps.filter((prop) => !(prop in expression));
|
|
45
73
|
if (missingProps.length === 0)
|
package/build/index.js
CHANGED
|
@@ -33,11 +33,11 @@ const propertyAliases = {
|
|
|
33
33
|
variables: 'args',
|
|
34
34
|
};
|
|
35
35
|
const evaluate = (expression, config) => __awaiter(void 0, void 0, void 0, function* () {
|
|
36
|
-
var _a;
|
|
36
|
+
var _a, _b;
|
|
37
37
|
const [functionPath, ...args] = (yield (0, _operatorUtils_1.evaluateArray)([expression.functionPath, ...(expression.args || [])], config));
|
|
38
38
|
config.typeChecker({ name: 'functionPath', value: functionPath, expectedType: 'string' });
|
|
39
39
|
const { objects, functions } = config.options;
|
|
40
|
-
const func = ((_a = (0, object_property_extractor_1.default)(functions, functionPath, null)) !== null && _a !== void 0 ? _a : (0, object_property_extractor_1.default)(objects, functionPath));
|
|
40
|
+
const func = ((_b = (_a = (0, object_property_extractor_1.default)(functions, functionPath, null)) !== null && _a !== void 0 ? _a : (0, object_property_extractor_1.default)(objects, functionPath, null)) !== null && _b !== void 0 ? _b : (0, object_property_extractor_1.default)(config.options, functionPath));
|
|
41
41
|
return yield func(...args);
|
|
42
42
|
});
|
|
43
43
|
const parseChildren = (expression) => {
|
package/build/types.d.ts
CHANGED
|
@@ -28,6 +28,9 @@ export interface FigTreeConfig {
|
|
|
28
28
|
[key: string]: Operator;
|
|
29
29
|
};
|
|
30
30
|
typeChecker: (...input: TypeCheckInput[]) => void;
|
|
31
|
+
resolvedAliasNodes: {
|
|
32
|
+
[key: string]: EvaluatorOutput;
|
|
33
|
+
};
|
|
31
34
|
}
|
|
32
35
|
export declare type OutputType = 'string' | 'number' | 'boolean' | 'bool' | 'array';
|
|
33
36
|
export interface BaseOperatorNode {
|
|
@@ -35,6 +38,7 @@ export interface BaseOperatorNode {
|
|
|
35
38
|
outputType?: OutputType;
|
|
36
39
|
children?: Array<EvaluatorNode>;
|
|
37
40
|
fallback?: any;
|
|
41
|
+
[key: string]: EvaluatorNode;
|
|
38
42
|
}
|
|
39
43
|
export declare type CombinedOperatorNode = BaseOperatorNode & BasicExtendedNode & SubtractionNode & DivisionNode & ComparatorNode & ConditionalNode & RegexNode & StringSubNode & SplitNode & ObjPropNode & APINode & PGNode & GraphQLNode & BuildObjectNode & FunctionNode & PassThruNode;
|
|
40
44
|
export declare type OperatorNodeUnion = BasicExtendedNode | SubtractionNode | DivisionNode | ComparatorNode | ConditionalNode | RegexNode | StringSubNode | SplitNode | ObjPropNode | PGNode | GraphQLNode | APINode | BuildObjectNode | FunctionNode | PassThruNode;
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fig-tree-evaluator",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Module to evaluate JSON-structured expression trees",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
7
7
|
"files": [
|
|
8
8
|
"build/**/*"
|
|
9
9
|
],
|
|
10
|
-
"repository": "git+https://github.com/CarlosNZ/fig-tree.git",
|
|
10
|
+
"repository": "git+https://github.com/CarlosNZ/fig-tree-evaluator.git",
|
|
11
11
|
"author": "Carl Smith <5456533+CarlosNZ@users.noreply.github.com>",
|
|
12
12
|
"license": "GPL-3.0",
|
|
13
13
|
"devDependencies": {
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"object-property-extractor": "^1.0.3"
|
|
40
40
|
},
|
|
41
41
|
"bugs": {
|
|
42
|
-
"url": "https://github.com/CarlosNZ/fig-tree/issues"
|
|
42
|
+
"url": "https://github.com/CarlosNZ/fig-tree-evaluator/issues"
|
|
43
43
|
},
|
|
44
|
-
"homepage": "https://github.com/CarlosNZ/fig-tree#readme"
|
|
44
|
+
"homepage": "https://github.com/CarlosNZ/fig-tree-evaluator#readme"
|
|
45
45
|
}
|