predicated v2.0.0
predicated
Create a predicate function from an expression
Usage
var compile = require('predicated').compile;
var predicate = compile('a === 1');
console.log(predicate({ a: 1 })); // true
console.log(predicate({ a: 2 })); // falseOptions
There are three options:
keys
To check for ReferenceError at compile time:
domain = { a: 2 };
var options = { keys: Object.keys(domain) };
predicate = compile('a === 1 && b === 2', options); // ReferenceError: b is not definedChecking for ReferenceErrors at compile time guarantees they will not occur at run time (i.e., predicate test time). It is also more reliable because all given keys are checked at compile time, whereas at run time ReferenceErrors may _or may not occur depending on the expression logic which may not evaluate all the variables in the expression (e.g., short-circuit evaluation). The predicate test after the delete in the compile example below illustrates this problem.
Note that 'true' and 'false' are added to keys automatically.
syntax
To invoke a syntax converter:
domain = { number_of_pets: 5, employed: false };
expression = 'number_of_pets < 3 and not employed';
predicate = compile(expression); // SyntaxError: Unexpected identifierFilter
predicate = compile(expression, { syntax: 'traditional' });
console.log(predicate(domain)); // trueNote that converters are not necessarily syntax checkers; they merely have to recognize syntax sufficiently to make the conversion.
assignments
Embedded assignments will throw a SyntaxError at compile time unless the assignments option is truthy.
API
compile function
var compile = require('predicated').compile;
var expression = 'number_of_pets < 3 || !employed';
var predicate = compile(expression);
var domain = { number_of_pets: 5, employed: false };
console.log(predicate(domain)); // true
domain.employed = true;
console.log(predicate(domain)); // false
domain.number_of_pets = 2;
console.log(predicate(domain)); // true
delete domain.employed;
console.log(predicate(domain)); // still true because left operand of `||` is true
domain.number_of_pets = 5;
console.log(predicate(domain)); // ReferenceError: employed is not definedconverters collection
Syntax converters are functions that take an expression with foreign syntax and return an equivalent JavaScript expression.
To invoke a syntax converter, pass a converter name in the syntax option to compile().
Pre-packaged converters
var converters = require('predicated').converters;
console.log(Object.keys(converters)); // ['javascript', 'traditional']The javascript converter is just a no-op (pass-through function).
The traditional converter converts syntax such as used in VB expressions or SQL where-clause expressions to JavaScript expression syntax. Specifically, it just searches for the following tokens outside of string literals and replaces them replaces them with JavaScript tokens:
- replaces
andwith&& - replaces
orwith|| - replaces
notwith! - replaces
=with=== - replaces
<>with!==
Custom converters
To add custom syntax converters:
converters.rpn = function(literalz) {
// Interesting code goes here to convert `literalz` to a JavaScript expression.
// `literalz.replace()` returns itself (for chaining):
return literalz.replace(/\bcos\b/g, 'cosine').replace(/\bsin\b/g, 'sine');
// Any other operations need to be performed on `literalz.extract` (string).
literalz.extract = prune(literalz.extract);
// In any case, converters are expected to return the `literalz` object.
return literalz;
}See also
Revision history
2.0.0- Added a check for assignment operators which are almost certainly unintended.
- Added
assignmentsoption to skip this check. - Converters are now passed a
Literalzobject rather than a string (breaking change for custom converters)
1.0.2- Add implicit
trueandfalseto optionkeys(when defined)
- Add implicit
1.0.1- Correction to regex that replaces
=with===
- Correction to regex that replaces