0.1.0 • Published 1 year ago

booltils v0.1.0

Weekly downloads
-
License
MIT
Repository
-
Last release
1 year ago

booltils

Condition evaluation supporting mathematical and boolean operators. Ideal for embedding complex conditional logic into JSON or other static text formats.

A condition is a tuple of three values – [string, string, number] –where the number (the operator) is an eight-bit integer.

The smallest three digits dictate the mathematical operator for the condition.

OperatorValue
=0b000_00_001
0b000_00_110
<0b000_00_010
>0b000_00_100
0b000_00_011
0b000_00_101

The next two digits dictate the boolean operator used to link the previous and current expressions — defaulting to AND.

OperatorValue
AND0b000_00_000
OR0b000_01_000
XOR0b000_10_000
NOR0b000_11_000

The last three are unused/reserved for future features.

Example

The condition's operator is equal to the intersection (|) of the relevant mathematical and boolean operators.

import evaluate, { Op } from 'booltils';

const conditions = [
  [1, 2, Op.LT], //     1 < 2
  [1, 2, Op.LT | Op.EQ], // AND 1 ≤ 2
  [1, 2, Op.EQ | Op.XOR], // XOR 1 = 2
  [2, 1, Op.GT | Op.OR], //  OR 2 ≥ 1
  [2, 2, Op.NE | Op.NOR] // NOR 2 ≠ 2
];

evaluate(conditions); // true
JSON.stringify(conditions); // [[2,3,18]]

booltils in user interfaces

It's worth noting that resulting representation is not human-readable. It should be assembled using some sort of UI. The following options/values/change handlers (JSX) should be enough to get you started.

const options = {
  math: [
    { label: '=', value: Op.EQ },
    { label: '≠', value: Op.NE },
    { label: '>', value: Op.GT },
    { label: '<', value: Op.LT },
    { label: '≥', value: Op.GTE },
    { label: '≤', value: Op.LTE }
  ],
  bool: [
    { label: 'AND', value: Op.AND },
    { label: 'OR',  value: Op.OR },
    { label: 'XOR', value: Op.XOR },
    { label: 'NOR', value: Op.NOR }
  ]
};

const [value, setValue] = useState(0b000_00_000);

const props = {
  math: {
    value: value & 0b000_11_000,
    onChange: e => setValue(
      +e.target.value | (value & ^0b000_11_000)
    )
  },
  bool: {
    value: value & 0b000_00_111,
    onChange: e => setValue(
      +e.target.value | (value & ^0b000_00_111)
    )
  }
}

const inputs = (
  <>
    <select value={props.math.value} onChange={props.math.onChange}>
      {options.math.map(o => <option value={o.value}>{o.label}</option>)}
    </select>
    <select value={props.bool.value} onChange={props.bool.onChange}>
      {options.bool.map(o => <option value={o.value}>{o.label}</option>)}
    </select>
  </>
);

Misc

Can be used alongside subwriter to interpolate variables, &c., while still permitting plaintext serialization.

import { sub } from 'subwriter';
import evaluate, { Op } from 'booltils';

const filters = {
  '-': (str, val) => str - val,
  '+': (str, val) => str + val
};

const data = { abc: 1, def: 2 };

const items = [
  [3, 4, Op.LT],
  ['{abc|-=1}', '{def|-=2}', Op.EQ | Op.XOR]
];

const map = ([a, b, op]) => [sub(a, data, filters), sub(b, data, filters), op];

evaluate(Array.from(items, map)); // false

JSON.stringify(items); // [["{abc}","{def}",2],["{abc|-=1}","{def|-=2}",17]]