Code Monkey home page Code Monkey logo

illogical's Introduction

illogical

A micro conditional javascript engine used to parse the raw logical and comparison expressions, evaluate the expression in the given data context, and provide access to a text form of the given expressions.

Revision: March 22, 2022.

About

This project has been developed to provide a shared conditional logic between front-end and back-end code, stored in JSON or in any other data serialization format.

Code documentation could be found here: https://briza-insurance.github.io/illogical/index.html.

The library is being build as CommonJS module and ESM.

Installation via NPM or Yarn

npm install -D @briza/illogical
yarn add @briza/illogical -D

Table of Content



Basic Usage

// Import the illogical engine
import Engine from '@briza/illogical'

// Create a new instance of the engine
const engine = new Engine()

// Evaluate the raw expression
const result = engine.evaluate(['==', 5, 5])

For advanced usage, please Engine Options.

Evaluate

Evaluate comparison or logical expression as TRUE or FALSE result:

engine.evaluate(Comparison Expression or Logical Expression, Evaluation Data Context) => boolean

Data context is optional.

Example

// Comparison expression
engine.evaluate(['==', 5, 5])
engine.evaluate(['==', 'circle', 'circle'])
engine.evaluate(['==', true, true])
engine.evaluate(['==', '$name', 'peter'], { name: 'peter' })
engine.evaluate(['UNDEFINED', '$RefA'], {})

// Logical expression
engine.evaluate(['AND', ['==', 5, 5], ['==', 10, 10]])
engine.evaluate(['AND', ['==', 'circle', 'circle'], ['==', 10, 10]])
engine.evaluate(['OR', ['==', '$name', 'peter'], ['==', 5, 10]], {
  name: 'peter',
})

Statement

Get expression string representation:

engine.statement(Comparison Expression or Logical Expression) => string

Example

/* Comparison expression */

engine.statement(['==', 5, 5])
// (5 == 5)

engine.statement(['==', 'circle', 'circle'])
// ("circle" == "circle")

engine.statement(['==', true, true])
// (true == true)

engine.statement(['==', '$name', 'peter'], { name: 'peter' })
// ({name} == "peter")

engine.statement(['UNDEFINED', '$RefA'])
// ({RefA} is UNDEFINED)

/* Logical expression */

engine.statement(['AND', ['==', 5, 5], ['==', 10, 10]])
// ((5 == 5) AND (10 == 10))

engine.statement(['AND', ['==', 'circle', 'circle'], ['==', 10, 10]])
// (("circle" == "circle") AND (10 == 10))

engine.statement(['OR', ['==', '$name', 'peter'], ['==', 5, 10]], {
  name: 'peter',
})
// (({name} == "peter") OR (5 == 10))

Parse

Parse the expression into a evaluable object, i.e. it returns the parsed self-evaluable condition expression.

engine.parse(Comparison Expression or Logical Expression) => evaluable

Evaluate Function

Example

let evaluable = engine.parse(['==', '$name', 'peter'])

evaluable.evaluate({ name: 'peter' }) // true

evaluable.toString()
// ({name} == "peter")

Simplify

Simplifies an expression with a given context. This is useful when you already have some of the properties of context and wants to try to evaluate the expression.

Example

engine.simplify(['AND', ['==', '$a', 10], ['==', '$b', 20]], { a: 10 }) // ['==', '$b', 20]

engine.simplify(['AND', ['==', '$a', 10], ['==', '$b', 20]], { a: 20 }) // false

Values not found in the context will cause the parent operand not to be evaluated and returned as part of the simplified expression.

In some situations we might want to evaluate the expression even if referred value is not present. You can provide a list of keys that will be strictly evaluated even if they are not present in the context.

Example

engine.simplify(
  ['AND', ['==', '$a', 10], ['==', '$b', 20]],
  { a: 10 },
  ['b'] // '$b' will be evaluated to undefined.
) // false

Alternatively we might want to do the opposite and strictly evaluate the expression for all referred values not present in the context except for a specified list of optional keys.

Example

engine.simplify(
  ['OR', ['==', '$a', 10], ['==', '$b', 20], ['==', '$c', 20]],
  { c: 10 },
  undefined,
  ['b'] // except for '$b' everything not in context will be evaluated to undefined.
) // ['==', '$b', 20]

Working with Expressions

Evaluation Data Context

The evaluation data context is used to provide the expression with variable references, i.e. this allows for the dynamic expressions. The data context is object with properties used as the references keys, and its values as reference values.

Valid reference values: object, string, number, boolean, string[], number[].

To reference the nested reference, please use "." delimiter, e.g.: $address.city

If the key of the nested reference includes the "." delimiter, please wrap the whole key with backticks `, e.g.: $address.`city.code` can reference the object

{
  address: {
    'city.code': 'TOR'
  }
}

$address.`city.code`[0] can reference the object

{
  address: {
    'city.code': ['TOR']
  }
}

when the value of the nested reference is an array.

Accessing Array Element:

$options[1]

Accessing Array Element via Reference:

$options[{index}]

  • The index reference is resolved within the data context as an array index.

Nested Referencing

$address.{segment}

  • The segment reference is resolved within the data context as a property key.

Composite Reference Key

$shape{shapeType}

  • The shapeType reference is resolved within the data context, and inserted into the outer reference key.
  • E.g. shapeType is resolved as "B" and would compose the $shapeB outer reference.
  • This resolution could be n-nested.

Data Type Casting

$payment.amount.(Type)

Cast the given data context into the desired data type before being used as an operand in the evaluation.

Note: If the conversion is invalid, then a warning message is being logged.

Supported data type conversions:

  • .(String): cast a given reference to String.
  • .(Number): cast a given reference to Number.

Example

// Data context
const ctx = {
  name: 'peter',
  country: 'canada',
  age: 21,
  options: [1, 2, 3],
  address: {
    city: 'Toronto',
    country: 'Canada',
  },
  index: 2,
  segment: 'city',
  shapeA: 'box',
  shapeB: 'circle',
  shapeType: 'B',
}

// Evaluate an expression in the given data context
engine.evaluate(['>', '$age', 20], ctx) // true

// Evaluate an expression in the given data context
engine.evaluate(['==', '$address.city', 'Toronto'], ctx) // true

// Accessing Array Element
engine.evaluate(['==', '$options[1]', 2], ctx) // true

// Accessing Array Element via Reference
engine.evaluate(['==', '$options[{index}]', 3], ctx) // true

// Nested Referencing
engine.evaluate(['==', '$address.{segment}', 'Toronto'], ctx) // true

// Composite Reference Key
engine.evaluate(['==', '$shape{shapeType}', 'circle'], ctx) // true

// Data Type Casting
engine.evaluate(['==', '$age.(String)', '21'], ctx) // true

Operand Types

The Comparison Expression expect operands to be one of the below:

Value

Simple value types: string, number, boolean.

Example

;['==', 5, 5][('==', 'circle', 'circle')][('==', true, true)]

Reference

The reference operand value is resolved from the Evaluation Data Context, where the the operands name is used as key in the context.

The reference operand must be prefixed with $ symbol, e.g.: $name. This might be customized via Reference Predicate Parser Option.

Example

Expression Data Context
['==', '$age', 21] {age: 21}
['==', 'circle', '$shape'] {shape: 'circle'}
['==', '$visible', true] {visible: true}
['==', '$circle', '$shape'] {circle: 'circle', shape: 'circle'}

Collection

The operand could be an array mixed from Value and Reference.

Example

Expression Data Context
['IN', [1, 2], 1] {}
['IN', 'circle', ['$shapeA', $shapeB] {shapeA: 'circle', shapeB: 'box'}
['IN', [$number, 5], 5] {number: 3}

Comparison Expressions

Equal

Expression format: ["==", Left Operand, Right Operand].

Valid operand types: string, number, boolean.

["==", 5, 5]
engine.evaluate(['==', 5, 5]) // true

Not Equal

Expression format: ["!=", Left Operand, Right Operand].

Valid operand types: string, number, boolean.

["!=", "circle", "square"]
engine.evaluate(['!=', 'circle', 'square']) // true

Greater Than

Expression format: [">", Left Operand, Right Operand].

Valid operand types: number, string.

  • String comparison only supports ISO-8601 formatted dates.
[">", 10, 5]
[">", "2023-01-01", "2022-12-31"]
engine.evaluate(['>', 10, 5]) // true
engine.evaluate(['>', '2023-01-01', '2022-12-31']) // true

Greater Than or Equal

Expression format: [">=", Left Operand, Right Operand].

Valid operand types: number, string.

  • String comparison only supports ISO-8601 formatted dates.
[">=", 5, 5]
[">=", "2023-01-01",  "2023-01-01"]
engine.evaluate(['>=', 5, 5]) // true
engine.evaluate(['>=', '2023-01-01', '2023-01-01']) // true

Less Than

Expression format: ["<", Left Operand, Right Operand].

Valid operand types: number, string.

  • String comparison only supports ISO-8601 formatted dates.
["<", 5, 10]
["<", "2022-12-31",  "2023-01-01"]
engine.evaluate(['<', 5, 10]) // true
engine.evaluate(['<', '2022-12-31', '2023-01-01']) // true

Less Than or Equal

Expression format: ["<=", Left Operand, Right Operand].

Valid operand types: number, string.

  • String comparison only supports ISO-8601 formatted dates.
["<=", 5, 5]
["<=", "2023-01-01",  "2023-01-01"]
engine.evaluate(['<=', 5, 5]) // true
engine.evaluate(['<=', '2023-01-01', '2023-01-01']) // true

In

Expression format: ["IN", Left Operand, Right Operand].

Valid operand types: number and number[] or string and string[].

["IN", 5, [1,2,3,4,5]]
["IN", ["circle", "square", "triangle"], "square"]
engine.evaluate(['IN', 5, [1, 2, 3, 4, 5]]) // true
engine.evaluate(['IN', ['circle', 'square', 'triangle'], 'square']) // true

Not In

Expression format: ["NOT IN", Left Operand, Right Operand].

Valid operand types: number and number[] or string and string[].

["IN", 10, [1,2,3,4,5]]
["IN", ["circle", "square", "triangle"], "oval"]
engine.evaluate(['NOT IN', 10, [1, 2, 3, 4, 5]]) // true
engine.evaluate(['NOT IN', ['circle', 'square', 'triangle'], 'oval']) // true

Prefix

Expression format: ["PREFIX", Left Operand, Right Operand].

Valid operand types: string.

  • Left operand is the PREFIX term.
  • Right operand is the tested word.
["PREFIX", "hemi", "hemisphere"]
engine.evaluate(['PREFIX', 'hemi', 'hemisphere']) // true
engine.evaluate(['PREFIX', 'hemi', 'sphere']) // false

Suffix

Expression format: ["SUFFIX", Left Operand, Right Operand].

Valid operand types: string.

  • Left operand is the tested word.
  • Right operand is the SUFFIX term.
["SUFFIX", "establishment", "ment"]
engine.evaluate(['SUFFIX', 'establishment', 'ment']) // true
engine.evaluate(['SUFFIX', 'establish', 'ment']) // false

Overlap

Expression format: ["OVERLAP", Left Operand, Right Operand].

Valid operand types number[] or string[].

["OVERLAP", [1, 2], [1, 2, 3, 4, 5]]
["OVERLAP", ["circle", "square", "triangle"], ["square"]]
engine.evaluate(['OVERLAP', [1, 2, 6], [1, 2, 3, 4, 5]]) // true
engine.evaluate([
  'OVERLAP',
  ['circle', 'square', 'triangle'],
  ['square', 'oval'],
]) // true

Undefined

Expression format: ["UNDEFINED", Reference Operand].

["UNDEFINED", "$RefA"]
engine.evaluate(['UNDEFINED', 'RefA'], {}) // true
engine.evaluate(['UNDEFINED', 'RefA'], { RefA: undefined }) // true
engine.evaluate(['UNDEFINED', 'RefA'], { RefA: 10 }) // false

Present

Evaluates as FALSE when the operand is UNDEFINED or NULL.

Expression format: ["PRESENT", Reference Operand].

["PRESENT", "$RefA"]
engine.evaluate(['PRESENT', 'RefA'], {}) // false
engine.evaluate(['PRESENT', 'RefA'], { RefA: undefined }) // false
engine.evaluate(['PRESENT', 'RefA'], { RefA: null }) // false
engine.evaluate(['PRESENT', 'RefA'], { RefA: 10 }) // true
engine.evaluate(['PRESENT', 'RefA'], { RefA: false }) // true
engine.evaluate(['PRESENT', 'RefA'], { RefA: 0 }) // true

Logical Expressions

And

The logical AND operator (&&) returns the boolean value TRUE if both operands are TRUE and returns FALSE otherwise.

Expression format: ["AND", Left Operand 1, Right Operand 2, ... , Right Operand N].

Valid operand types: Comparison Expression or Nested Logical Expression.

["AND", ["==", 5, 5], ["==", 10, 10]]
engine.evaluate(['AND', ['==', 5, 5], ['==', 10, 10]]) // true

Or

The logical OR operator (||) returns the boolean value TRUE if either or both operands is TRUE and returns FALSE otherwise.

Expression format: ["OR", Left Operand 1, Right Operand 2, ... , Right Operand N].

Valid operand types: Comparison Expression or Nested Logical Expression.

["OR", ["==", 5, 5], ["==", 10, 5]]
engine.evaluate(['OR', ['==', 5, 5], ['==', 10, 5]]) // true

Nor

The logical NOR operator returns the boolean value TRUE if both operands are FALSE and returns FALSE otherwise.

Expression format: ["NOR", Left Operand 1, Right Operand 2, ... , Right Operand N]

Valid operand types: Comparison Expression or Nested Logical Expression.

["NOR", ["==", 5, 1], ["==", 10, 5]]
engine.evaluate(['NOR', ['==', 5, 1], ['==', 10, 5]]) // true

Xor

The logical NOR operator returns the boolean value TRUE if both operands are FALSE and returns FALSE otherwise.

Expression format: ["XOR", Left Operand 1, Right Operand 2, ... , Right Operand N]

Valid operand types: Comparison Expression or Nested Logical Expression.

["XOR", ["==", 5, 5], ["==", 10, 5]]
engine.evaluate(['XOR', ['==', 5, 5], ['==', 10, 5]]) // true
["XOR", ["==", 5, 5], ["==", 10, 10]]
engine.evaluate(['XOR', ['==', 5, 5], ['==', 10, 10]]) // false

Not

The logical NOT operator returns the boolean value TRUE if the operand is FALSE, TRUE otherwise.

Expression format: ["NOT", Operand]

Valid operand types: Comparison Expression or Nested Logical Expression.

["NOT", ["==", 5, 5]]
engine.evaluate(['NOT', ['==', 5, 5]]) // true

Arithmetic Expressions

Arithmetic Expressions are not supported as root level expressions since they must evaluate to a boolean. But it can be used nested within Comparisson Expressions.

Division

The arithmetical operator for division produces the quotient of its operands where the left-most operand is the dividend and the subsequent one is the divisor, done from left to right.

Expression format: ["/", First Operand, Second Operand, ... , Nth Operand].

Valid operand types: Arithmetic Expressions or Operands.

["==", ["/", 100, 10], 10]
engine.evaluate(["==", ["/", 100, 10], 10]) // true

Multiplication

The arithmetical operator for multiplication produces the product of the operands.

Expression format: ["*", First Operand, Second Operand, ... , Nth Operand].

Valid operand types: Arithmetic Expressions or Operands.

["==", ["*", 100, 10], 10]
engine.evaluate(["==", ["*", 10, 10], 100]) // true

Subtraction

The arithmetical operator for subtraction subtracts the operands, producing their difference.

Expression format: ["-", First Operand, Second Operand, ... , Nth Operand].

Valid operand types: Arithmetic Expressions or Operands.

["==", ["-", 20, 10], 10]
engine.evaluate(["==", ["-", 20, 10], 10]) // true

Addition

The arithmetical operator for addition produces the sum of the operands.

Expression format: ["+", First Operand, Second Operand, ... , Nth Operand].

Valid operand types: Arithmetic Expressions or Operands.

["==", ["+", 5, 5], 10]
engine.evaluate(["==", ["+", 5, 5], 10]) // true

Engine Options

Parser Options

Below described, are individual options object properties which could be used individually. Any missing options will be substituted with the default options.

Usage

// Import the illogical engine
import Engine from '@briza/illogical'

// Create a new instance of the engine
const opts = {
  referencePredicate: (operand) => operand.startsWith('$'),
}
const engine = new Engine(opts)

Reference Predicate

A function used to determine if the operand is a reference type, otherwise evaluated as a static value.

referencePredicate: (operand: string) => boolean

Return value:

  • true = reference type
  • false = value type

Default reference predicate:

The $ symbol at the begging of the operand is used to predicate the reference type., E.g. $State, $Country.

Reference Transform

A function used to transform the operand into the reference annotation stripped form. I.e. remove any annotation used to detect the reference type. E.g. "$Reference" => "Reference".

referenceTransform: (operand: string) => string

Default reference transform: It removes the $ symbol at the begging of the operand name.

Operator Mapping

Mapping of the operators. The key is unique operator key, and the value is the key used to represent the given operator in the raw expression.

operatorMapping: Map<symbol, string>

Default operator mapping:

  // Comparison
  [OPERATOR_EQ, '=='],
  [OPERATOR_NE, '!='],
  [OPERATOR_GT, '>'],
  [OPERATOR_GE, '>='],
  [OPERATOR_LT, '<'],
  [OPERATOR_LE, '<='],
  [OPERATOR_IN, 'IN'],
  [OPERATOR_NOT_IN, 'NOT IN'],
  [OPERATOR_PREFIX, 'PREFIX'],
  [OPERATOR_SUFFIX, 'SUFFIX'],
  [OPERATOR_OVERLAP, 'OVERLAP'],
  [OPERATOR_UNDEFINED, 'UNDEFINED'],
  [OPERATOR_PRESENT, 'PRESENT'],
  // Logical
  [OPERATOR_AND, 'AND'],
  [OPERATOR_OR, 'OR'],
  [OPERATOR_NOR, 'NOR'],
  [OPERATOR_XOR, 'XOR'],
  [OPERATOR_NOT, 'NOT'],
  // Arithmetic
  [OPERATOR_SUM, '+'],
  [OPERATOR_SUBTRACT, '-'],
  [OPERATOR_MULTIPLY, '*'],
  [OPERATOR_DIVIDE, '/'],

The operator keys are unique symbols which could be imported from the engine package:

import {
  OPERATOR_EQ,
  OPERATOR_NE,
  OPERATOR_GT,
  OPERATOR_GE,
  OPERATOR_LT,
  OPERATOR_LE,
  OPERATOR_IN,
  OPERATOR_NOT_IN,
  OPERATOR_PREFIX,
  OPERATOR_SUFFIX,
  OPERATOR_OVERLAP,
  OPERATOR_UNDEFINED,
  OPERATOR_PRESENT,
  OPERATOR_AND,
  OPERATOR_OR,
  OPERATOR_NOR,
  OPERATOR_XOR,
  OPERATOR_NOT,
  OPERATOR_DIVIDE,
  OPERATOR_MULTIPLY,
  OPERATOR_SUBTRACT,
  OPERATOR_SUM,
} from '@briza/illogical'

Breaking Changes

v1.4.2

  • Change on @babel/env preset to target > 1%, node 12 this will remove some polyfills that were causing performance problems in some projects.

v1.2.0

  • Removed strict mode from the Engine constructor options. const engine = new Engine(strictMode, opts); -> const engine = new Engine(opts);

Contributing

See contributing.md.

License

Illogical is released under the MIT license. See license.txt.

illogical's People

Contributors

andrewxu avatar atoledo avatar countcain avatar davidhorak avatar dependabot-preview[bot] avatar jlambertazzo avatar justinchang91 avatar lilyvanoekel avatar lsmag avatar luiz290788 avatar menghaoyu2002 avatar rajeevnaikte avatar rpedrosanto avatar rthreei avatar ryannieuwoudt avatar strawberriesaregreat avatar theslyone avatar visrozar avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

illogical's Issues

Complex Reference Keys

Description

We can explore a new illogical functionality to resolve complex reference keys to avoid more dynamic conditons.

Implementation Proposal

Composite Reference Key

$Q1{Q2}.state

  • Inner {} reference, is resolved first, therefore the final reference key would be: Q1X, where X is the evaluated reference, as string.

Nested references

$Q1.{Q2}.state

  • any nested key, annotated with {} is evaluated first, and resolved as property string key.

Nested references via array index

$Q1[{Q2}].state

  • any nested key, annotated with {} is evaluated first, and resolved as property array index.

Concerns

  • Prevent/detect cyclic references, e.g.: $Q1{Q1}

graceful handling of nils in isObject

Currently it seems that the "in" (reference) expression would error if we are checking for isObject of a nil (null/undefined), we should update isObject to not throw error if the value is null or undefined, but instead, gracefully return false.

NOT operator

  • To negate result of other expressions

Examples

  • ["NOT", ["IN", 1, [1, 2]]] -> false

Update Docs

I wish to update the Contributing.md file to make it easily understandable for first-time contributors.

"IN" Operator Definitions

Current system behaviour

Currently, there's an edge case in which the "IN" operator could be misinterpreted. For example:

   ["OVERLAP", ["$Location1.region", "$Location2.region"....], ["IN"]]

In this case, IN really stands for Indiana but its mistakenly interpreted as the IN operator

Expected system behaviour

Given the fact that an OVERLAP assumes left and right operand to array of values or references, the example above is grammatically correct. Having that said, an IN should be able to be placed in the example above without misinterpretation

Acceptance Criteria

  1. Any changes should contain tests

References

Discussion

Typedoc generating incorrect modules docs

Describe the Bug
When running typedoc it's generating incorrect modules docs, presenting indexes which are full of repeated links such as the snippet below from docs/modules.html:

<section class="tsd-index-section ">
	<h3>Modules</h3>
	<ul class="tsd-index-list">
		<li class="tsd-kind-module"><a href="modules/common_util.html" class="tsd-kind-icon">common/util</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical.html" class="tsd-kind-icon">illogical</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_common.html" class="tsd-kind-icon">illogical/common</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_common.html" class="tsd-kind-icon">illogical/common</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_expression_comparison.html" class="tsd-kind-icon">illogical/expression/comparison</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_expression_comparison.html" class="tsd-kind-icon">illogical/expression/comparison</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_expression_comparison.html" class="tsd-kind-icon">illogical/expression/comparison</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_expression_comparison.html" class="tsd-kind-icon">illogical/expression/comparison</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_expression_comparison.html" class="tsd-kind-icon">illogical/expression/comparison</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_expression_comparison.html" class="tsd-kind-icon">illogical/expression/comparison</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_expression_comparison.html" class="tsd-kind-icon">illogical/expression/comparison</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_expression_comparison.html" class="tsd-kind-icon">illogical/expression/comparison</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_expression_comparison.html" class="tsd-kind-icon">illogical/expression/comparison</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_expression_comparison.html" class="tsd-kind-icon">illogical/expression/comparison</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_expression_comparison.html" class="tsd-kind-icon">illogical/expression/comparison</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_expression_comparison.html" class="tsd-kind-icon">illogical/expression/comparison</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_expression_logical.html" class="tsd-kind-icon">illogical/expression/logical</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_expression_logical.html" class="tsd-kind-icon">illogical/expression/logical</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_expression_logical.html" class="tsd-kind-icon">illogical/expression/logical</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_expression_logical.html" class="tsd-kind-icon">illogical/expression/logical</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_expression_logical.html" class="tsd-kind-icon">illogical/expression/logical</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_expression_logical.html" class="tsd-kind-icon">illogical/expression/logical</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_expression_prefix.html" class="tsd-kind-icon">illogical/expression/prefix</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_expression_suffix.html" class="tsd-kind-icon">illogical/expression/suffix</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_operand.html" class="tsd-kind-icon">illogical/operand</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_operand.html" class="tsd-kind-icon">illogical/operand</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_operand.html" class="tsd-kind-icon">illogical/operand</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_operand.html" class="tsd-kind-icon">illogical/operand</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_parser.html" class="tsd-kind-icon">illogical/parser</a></li>
		<li class="tsd-kind-module"><a href="modules/illogical_parser.html" class="tsd-kind-icon">illogical/parser</a></li>
	</ul>
</section>

This is likely being caused by a combination of a breaking change in typedoc itself along with repeated typedoc annotations such as @module illogical/expression/comparison in illogical source files.

To Reproduce
In a terminal window run npm run docs from illogical root folder.

Expected Behavior
Each repeated link in the indexes should be unique and pointing to different elements of each referenced module.

Package Updates

Overview

The following changes to the library's packages are required:

  1. @babel/core. ^7.14.2 => ^7.14.6
  2. @babel/plugin-proposal-class-properties. 7.12.13 => ^7.14.5
  3. @babel/preset-typescript. ^7.12.13 => ^7.14.5
  4. @typescript-eslint/eslint-plugin. ^4.24.0 => ^4.28.1
  5. @typescript-eslint/parser. ^4.24.0 => ^4.28.1
  6. eslint. ^7.26.0 => ^7.29.0
  7. eslint-plugin-import. ^2.23.2 => ^2.23.4
  8. prettier. ^2.3.0 => ^2.3.2
  9. rollup. ^2.48.0 => ^2.52.6
  10. typedoc. ^0.20.36 => ^0.21.2
  11. ws. ^7.4.4 => ^7.4.6

Reference

Screen Shot 2021-07-20 at 3 03 52 PM

Support conditions that need to be agnostic of undefined/null

Currently we have the option to compare a value against null, or to use the UNDEFINED comparison expression.

It would be nice if we had a way to cover both cases easily.

For example, the following condition:

"condition": [
    "NOR",
    [
      "UNDEFINED",
      "$Loss1Date"
    ],
    [
      "==",
      "$Loss1Date",
      null
    ]
  ]

Say it's possible for Loss1Date to be on the page but left empty, or maybe conditionally not shown at all, or filled out, and then emptied by the user. By the time it comes to evaluate the condition it might be either null or undefined. It would be nice if we can capture that in a single expression.

Some options:

  • UNDEFINED_OR_NULL expression
  • Updating UNDEFINED to check for null as well
  • EMPTY / NOT_EMPTY expression
  • NIL / NOT_NIL expression

Operator to check if intersecting sets

Given two array, check if there is at least one common item.
E.g.

[
  "INTERSECT",
  [
    "$Location1ClassOfBusiness",
    "$Location2ClassOfBusiness",
    "$Location3ClassOfBusiness"
  ],
  [
    "123456-0-0",
    "123457-0-9"
  ]
]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.