Compile MongoDB-style boolean expressions ($and, $or, $not, $nor) with callbacks and custom functions
Use one of the two based on your project's dependency manager.
$ npm install logical-compiler --save
$ yarn add logical-compilerimport compile from 'logical-compiler'; // ESM
// or: const compile = require('logical-compiler'); // CommonJS
compile(expression, options);Arguments:
expression- the boolean expression to be executed.options- an optional object specifying options.fns- an optional attribute specifying any function(s) used on the expression.
let expression = { $and: [true, true] };
compile(expression); // true
expression = { $and: [true, false] };
compile(expression); // false
expression = { $and: [false, true] };
compile(expression); // false
expression = { $and: [false, false] };
compile(expression); // falselet expression = { $or: [true, true] };
compile(expression); // true
expression = { $or: [true, false] };
compile(expression); // true
expression = { $or: [false, true] };
compile(expression); // true
expression = { $or: [false, false] };
compile(expression); // false$not takes a single expression and returns its negation.
let expression = { $not: true };
compile(expression); // false
expression = { $not: { $and: [true, true] } };
compile(expression); // false$nor takes an array and returns the negation of $or over it, i.e. true
only when every operand is false.
let expression = { $nor: [false, false] };
compile(expression); // true
expression = { $nor: [false, true] };
compile(expression); // falseconst expression = { $someOp: ['x', 'y'] };
compile(expression); // Error: Unrecognized operator: '$someOp'compile(); // Error: Expected an expressioncompile(true); // true
compile(false); // falseconst expression = 'test';
compile(expression); // Error: Unexpected token 'test'const expression = 201;
compile(expression); // Error: Unexpected token '201'A callback is a function that returns a boolean. If it returns a promise,
compile resolves to a promise you await.
let cb = () => true;
compile(cb); // true
cb = () => Promise.resolve(false);
await compile(cb); // falseconst expression = {
$and: [true, () => Promise.resolve(true)],
};
await compile(expression); // trueA function is defined on the fns attribute of the options argument. It may
return a boolean or a promise.
const options = {
fns: {
isEven: (number) => number % 2 === 0,
isEqual: (num1, num2) => Promise.resolve(num1 === num2),
},
};
compile({ isEven: 6 }, options); // true
await compile({ isEqual: [3, 5] }, options); // falseconst options = {
fns: {
authenticated: () => Promise.resolve(true),
},
};
const expression = {
$or: [false, { authenticated: null }],
};
await compile(expression, options); // trueconst expression = { someFn: ['x', 'y'] };
compile(expression, options); // Error: Undefined function: 'someFn'let expression = {
$or: [{ $and: [true, true] }, false],
};
compile(expression); // trueexpression = {
$or: [() => false, () => false],
};
compile(expression); // falseexpression = {
$and: [() => true, true],
};
compile(expression); // trueexpression = {
$or: [
() => false,
false,
{
$and: [true, { $or: [() => true, false] }],
},
],
};
compile(expression); // trueconst options = {
fns: {
any: (target, values) => values.includes(target),
all: (targets, values) => targets.every((target) => values.includes(target)),
},
};
expression = {
$and: [
() => true,
{ $or: [true, false] },
{ any: [5, [1, 3, 4, 6, 7]] }
],
};
compile(expression, options); // false
expression = {
$or: [
() => false,
false,
{ $and: [true, false] },
{
all: [
[3, 4, 7],
[2, 3, 4, 5, 6, 7],
],
},
],
};
compile(expression, options); // trueOperators can be nested in any fashion to achieve the desired logical check.
When an object expression has more than one key, the keys are AND-ed together, at any nesting depth. This applies to operators and functions alike.
const options = {
fns: {
isEven: (number) => number % 2 === 0,
},
};
let expression = { $or: [false, true], isEven: 6 };
compile(expression, options); // true ($or AND isEven)
expression = { $or: [false, true], isEven: 7 };
compile(expression, options); // false ($or is true, but isEven is false)An empty object is not a valid expression and throws:
compile({}); // Error: Expected an expressionAll errors thrown by compile are instances of LogicalCompilerError, a
subclass of Error that carries a .code field for programmatic handling. The
human-readable .message is unchanged.
import compile, { LogicalCompilerError } from 'logical-compiler';
try {
compile({ $unknown: [] });
} catch (error) {
error instanceof LogicalCompilerError; // true
error.code; // 'UNRECOGNIZED_OPERATOR'
}In CommonJS the class is also available as compile.LogicalCompilerError.
Codes: UNRECOGNIZED_OPERATOR, UNDEFINED_FUNCTION, UNEXPECTED_TOKEN,
UNEXPECTED_RETURN_TYPE, EXPECTED_EXPRESSION.
Type declarations ship with the package (both CommonJS and ESM), so no separate
@types install is needed. LogicalCompilerError and the Expression,
Options, Fn, Callback, and ErrorCode types are exported for use in your
own code.
-
compilereturnsbooleanfor fully synchronous expressions andPromise<boolean>when any callback or function returns a promise.$andstops at the firstfalse;$orstops at the firsttrue. Later operands (including async ones) are not evaluated. -
Callbacks and functions must explicitly return boolean values to avoid the ambiguity of relying on truthiness. Relying on truthiness would pose a serious loophole because the executable might accidentally resolve to true on a non-boolean value. If the library encounters a callback that resolves to a non-boolean value, it throws an exception. See MDN documentation on truthy values.
MIT © Mutai Mwiti | GitHub | GitLab
DISCLAIMER: All opinions expressed in this repository are mine and do not reflect any company or organisation I'm involved with.