fig-tree-evaluator 2.0.0 → 2.0.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 CHANGED
@@ -140,6 +140,7 @@ The `options` parameter is an object with the following available properties (al
140
140
  - `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)
141
141
  - `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.
142
142
  - `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 encoutered (e.g. trying to pass a primitive value when an array is expected => `.map is not a function`)
143
+ - `nullEqualsUndefined` -- this only affects the [`equal`/`notEqual` operators](#equal) (see there for more detail).
143
144
 
144
145
  As mentioned above, `options` can be provided as part of the constructor as part of each seperate evaluation. You can also change the options permanently for a given evaluator instance with:
145
146
 
@@ -200,7 +201,7 @@ Most of the time named properties is preferable; however there are situations wh
200
201
  In each operator node, as well as the operator-specific properties, the following two optional properties can be provided:
201
202
 
202
203
  - `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.
203
- - `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](LINK) to see the outcome of applying different `outputType` values to various results.
204
+ - `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.
204
205
 
205
206
  Remember that *all* operator node properties can themselves be operator nodes, *including* the `fallback` and `outputType` properties.
206
207
 
@@ -297,7 +298,8 @@ Aliases: `=`, `eq`, `equal`, `equals`
297
298
 
298
299
  #### Properties
299
300
 
300
- - `values`<sup>*</sup>: (array) -- any number of elements; will be compared using Javascript `==` operator
301
+ - `values`<sup>*</sup>: (array) -- any number of elements; will be compared for strict equality. This includes simple types as well as deep equality of objects and arrays.
302
+ - `nullEqualsUndefined`: (boolean, default `false`) -- there are times when it is convenient for `null` to be considered equal to `undefined`. If this is desiered, set this property to `true`, otherwise all equality checks will be "strict" equality. If you find that you want this setting enabled globally, then you can set it in the overall [evaluator options](#available-options) instead of having to add this additional property to every equality expression.
301
303
 
302
304
  e.g.
303
305
  ```js
@@ -319,7 +321,8 @@ Aliases: `!=`, `!`, `ne`, `notEqual`
319
321
 
320
322
  #### Properties
321
323
 
322
- - `values`<sup>*</sup>: (array) -- any number of elements; will be compared using Javascript `!=` operator
324
+ - `values`<sup>*</sup>: (array) -- any number of elements; will be compared for inequality. This includes simple types as well as deep comparison of objects and arrays.
325
+ - `nullEqualsUndefined`: (boolean, default `false`) -- as [above](#equal)
323
326
 
324
327
  e.g.
325
328
  ```js
@@ -1247,6 +1250,8 @@ Please open an issue: https://github.com/CarlosNZ/fig-tree-evaluator/issues
1247
1250
 
1248
1251
  ## Changelog
1249
1252
 
1253
+
1254
+ - **v2.0.1**: Add deep equality comparison for objects/arrayr in =/!= operators
1250
1255
  - **v2.0.0**: Re-write as stand-alone package. Major improvements include:
1251
1256
  - more [operators](#operator-reference)
1252
1257
  - operator (and property) [aliases](#operator--property-aliases)
@@ -1,4 +1,4 @@
1
- import { OutputType, EvaluatorNode, CombinedOperatorNode, Operator, EvaluatorOutput } from './types';
1
+ import { OutputType, EvaluatorNode, CombinedOperatorNode, Operator, EvaluatorOutput, FigTreeOptions } 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: {
@@ -10,6 +10,7 @@ export declare const mapPropertyAliases: (propertyAliases: {
10
10
  [key: string]: string;
11
11
  }, expression: CombinedOperatorNode) => CombinedOperatorNode;
12
12
  export declare const checkRequiredNodes: (requiredProps: readonly string[], expression: CombinedOperatorNode) => string | false;
13
+ export declare const mergeOptions: (origOptions: FigTreeOptions, newOptions: FigTreeOptions) => FigTreeOptions;
13
14
  export declare const convertOutputMethods: {
14
15
  [key in OutputType]: <T>(value: T) => EvaluatorOutput | T[];
15
16
  };
package/build/helpers.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.errorMessage = exports.convertOutputMethods = exports.checkRequiredNodes = exports.mapPropertyAliases = exports.fallbackOrError = exports.truncateString = exports.getOperatorName = exports.isOperatorNode = exports.parseIfJson = void 0;
3
+ exports.errorMessage = exports.convertOutputMethods = exports.mergeOptions = exports.checkRequiredNodes = exports.mapPropertyAliases = exports.fallbackOrError = exports.truncateString = exports.getOperatorName = exports.isOperatorNode = exports.parseIfJson = void 0;
4
4
  const change_case_1 = require("change-case");
5
5
  const parseIfJson = (input) => {
6
6
  if (typeof input !== 'string')
@@ -49,6 +49,17 @@ const checkRequiredNodes = (requiredProps, expression) => {
49
49
  return false;
50
50
  };
51
51
  exports.checkRequiredNodes = checkRequiredNodes;
52
+ const mergeOptions = (origOptions, newOptions) => {
53
+ const combinedOptions = Object.assign(Object.assign({}, origOptions), newOptions);
54
+ if (origOptions.objects || newOptions.objects)
55
+ combinedOptions.objects = Object.assign(Object.assign({}, origOptions.objects), newOptions.objects);
56
+ if (origOptions.functions || newOptions.functions)
57
+ combinedOptions.functions = Object.assign(Object.assign({}, origOptions.functions), newOptions.functions);
58
+ if (origOptions.headers || newOptions.headers)
59
+ combinedOptions.headers = Object.assign(Object.assign({}, origOptions.headers), newOptions.headers);
60
+ return combinedOptions;
61
+ };
62
+ exports.mergeOptions = mergeOptions;
52
63
  exports.convertOutputMethods = {
53
64
  number: (value) => extractNumber(value),
54
65
  string: (value) => String(value),
package/build/index.js CHANGED
@@ -40,6 +40,7 @@ const evaluate_1 = require("./evaluate");
40
40
  const typeCheck_1 = require("./typeCheck");
41
41
  const _operatorAliases_json_1 = __importDefault(require("./operators/_operatorAliases.json"));
42
42
  const operators = __importStar(require("./operators"));
43
+ const helpers_1 = require("./helpers");
43
44
  class FigTreeEvaluator {
44
45
  constructor(options = {}) {
45
46
  this.typeChecker = (...args) => {
@@ -54,12 +55,12 @@ class FigTreeEvaluator {
54
55
  }
55
56
  evaluate(expression, options = {}) {
56
57
  return __awaiter(this, void 0, void 0, function* () {
57
- const instanceOptions = Object.assign(Object.assign({}, this.options), options);
58
+ const currentOptions = (0, helpers_1.mergeOptions)(this.options, options);
58
59
  return yield (0, evaluate_1.evaluatorFunction)(expression, {
59
- options: instanceOptions,
60
+ options: currentOptions,
60
61
  operators: this.operators,
61
62
  operatorAliases: this.operatorAliases,
62
- typeChecker: instanceOptions.skipRuntimeTypeCheck ? () => { } : this.typeChecker,
63
+ typeChecker: currentOptions.skipRuntimeTypeCheck ? () => { } : this.typeChecker,
63
64
  });
64
65
  });
65
66
  }
@@ -12,13 +12,22 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.EQUAL = void 0;
13
13
  const logicalAnd_1 = require("./logicalAnd");
14
14
  const _operatorUtils_1 = require("./_operatorUtils");
15
+ const lite_1 = require("dequal/lite");
15
16
  const requiredProperties = ['values'];
16
17
  const operatorAliases = ['=', 'eq', 'equal', 'equals'];
17
18
  const propertyAliases = {};
18
19
  const evaluate = (expression, config) => __awaiter(void 0, void 0, void 0, function* () {
19
- const values = (yield (0, _operatorUtils_1.evaluateArray)(expression.values, config));
20
+ var _a;
21
+ const [values, nullMatch] = (yield (0, _operatorUtils_1.evaluateArray)([expression.values, expression.nullEqualsUndefined], config));
20
22
  config.typeChecker({ name: 'values', value: values, expectedType: 'array' });
21
- return values.every((value) => value == values[0]);
23
+ const nullEqualsUndefined = nullMatch !== undefined
24
+ ? nullMatch
25
+ : ((_a = config.options) === null || _a === void 0 ? void 0 : _a.nullEqualsUndefined) !== undefined
26
+ ? config.options.nullEqualsUndefined
27
+ : false;
28
+ if (nullEqualsUndefined && (values[0] === null || values[0] === undefined))
29
+ return values.every((value) => value === null || value === undefined);
30
+ return values.every((value) => (0, lite_1.dequal)(value, values[0]));
22
31
  });
23
32
  exports.EQUAL = {
24
33
  requiredProperties,
@@ -12,13 +12,22 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.NOT_EQUAL = void 0;
13
13
  const logicalAnd_1 = require("./logicalAnd");
14
14
  const _operatorUtils_1 = require("./_operatorUtils");
15
+ const lite_1 = require("dequal/lite");
15
16
  const requiredProperties = ['values'];
16
17
  const operatorAliases = ['!=', '!', 'ne', 'notEqual'];
17
18
  const propertyAliases = {};
18
19
  const evaluate = (expression, config) => __awaiter(void 0, void 0, void 0, function* () {
19
- const values = (yield (0, _operatorUtils_1.evaluateArray)(expression.values, config));
20
+ var _a;
21
+ const [values, nullMatch] = (yield (0, _operatorUtils_1.evaluateArray)([expression.values, expression.nullEqualsUndefined], config));
20
22
  config.typeChecker({ name: 'values', value: values, expectedType: 'array' });
21
- return values.some((val) => val !== values[0]);
23
+ const nullEqualsUndefined = nullMatch !== undefined
24
+ ? nullMatch
25
+ : ((_a = config.options) === null || _a === void 0 ? void 0 : _a.nullEqualsUndefined) !== undefined
26
+ ? config.options.nullEqualsUndefined
27
+ : false;
28
+ if (nullEqualsUndefined && (values[0] === null || values[0] === undefined))
29
+ return values.some((value) => value === null && value === undefined);
30
+ return values.some((val) => !(0, lite_1.dequal)(val, values[0]));
22
31
  });
23
32
  exports.NOT_EQUAL = {
24
33
  requiredProperties,
package/build/types.d.ts CHANGED
@@ -17,6 +17,7 @@ export interface FigTreeOptions {
17
17
  [key: string]: string;
18
18
  };
19
19
  returnErrorAsString?: boolean;
20
+ nullEqualsUndefined?: boolean;
20
21
  allowJSONStringInput?: boolean;
21
22
  skipRuntimeTypeCheck?: boolean;
22
23
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fig-tree-evaluator",
3
- "version": "2.0.0",
3
+ "version": "2.0.3",
4
4
  "description": "Module to evaluate JSON-structured expression trees",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -35,6 +35,7 @@
35
35
  "dependencies": {
36
36
  "axios": "^0.27.2",
37
37
  "change-case": "^4.1.2",
38
+ "dequal": "^2.0.3",
38
39
  "object-property-extractor": "^1.0.3"
39
40
  },
40
41
  "bugs": {