1.0.13 • Published 4 years ago

micro-expressions v1.0.13

Weekly downloads
5
License
ISC
Repository
github
Last release
4 years ago

Micro Expressions for NodeJS

Lightweight and easily extensible string-based expression engine

Goals & Design

I created this tiny project to read (and parse) collections from JSON files that contained simple conditionals. As my architecture grew, I started using the same expressions for almost anything – even to query several databases. Keeping one simplistic language throughout my ecosystem simplified both development and maintenance for me.

Installation

Install using npm:

$ npm install micro-expressions

Usage

Newly created MicroExpressions take one argument: the expression. The input is being parsed automagically and turned into functions that take a data container as argument for rendering.

const { MicroExpression } = require('micro-expressions');

new MicroExpression( expression );

Use render_with( data_container ) to render all templates using data_container as context.

new MicroExpression(expression).render_with( data_container );

As MicroExpression is using lodash's get helper, it supports object paths in dot notation:

new MicroExpression('foo.bar < 10').render_with({ foo: { bar: 4 } });

Extending

To create micro expressions with your own set of operators, you can extend the MicroExpression class and overwrite the default behavior by declaring an override_operators() and/or a get( expression ) method.

const { MicroExpression } = require('micro-expressions');

class MyExpression extends MicroExpression {
	override_operators() { 
		... 
	}

	get(expression) { 
		... 
	}
}

Overriding Operators

The override_operators method takes no arguments, but must return an object with the operators as keys and according callbacks as values. The callback takes 2 arguments: left and right, representing both sides of the operator. If your operator e.g. doesn't have a left side, you must still declare a left parameter, but can ignore the passed argument.

{
	'!': function(left, right) {
		return !right;
	}
}

Overriding Templating

The get method takes one argument: expression. All operands are passed to this method before the entire expression is being evaluated.

In its simplest form, you can override get like so:

const { MicroExpression } = require('micro-expressions');

class SQLExpression extends MicroExpression {
	get(expression) {
		return data => data[expression] || expression;
	}
}

Hooking into .render and .render_with

You can declare a method on_render that gets passed the current rendering results as single argument.

Examples

In the following example, I used the MicroExpression class to parse conditions loaded from a JSON file:

steps.json

[
	{
		"if": "answer=yes",
		"message": "affirmative."
	}, 
	{
		"if": "answer=no",
		"message": "negative."
	}
]

index.js

let message = 'maybe.';
const steps = require('./steps.json');
const answer = 'no';

_.each(steps, (step, i) => {
	const condition = new MicroExpression(step.if);
	if(condition.render_with({ answer })) {
		message = step.message;
	}
});

console.log('The outcome is', message);

The output will be:

The outcome is negative

Here is an example of extending MicroExpression:

class MyExpression extends MicroExpression {
	override_operators() 	{  
		return {
			'=':  (left, right) => left === right,
			'!=': (left, right) => left !== right,
			'!':  (left, right) => !right,
			'~':  (left, right) => Math.abs(left - right) < 10
		}
	}
}

Make sure you check out the subclass MongoExpression and the tests to see examples of implementation.

License

MIT License