Created
November 17, 2015 17:13
-
-
Save Vannevelj/95aa28887cafff10367b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 'use strict'; | |
| const logger = require('../../services/logger.js'); | |
| const util = require('util'); | |
| const math = require('mathjs'); | |
| /** | |
| * Evaluates the given expression | |
| * @param expression {string} - The expression to be evaluated. Should support an expression of the form 'log(10) + abs([VALUE])' | |
| * for a certain set of mathematical functions and placeholders. | |
| * @param valueEntry {object} - The entry of the value in the BF_VALUES table contain metadata to use for placeholders. | |
| */ | |
| function evaluateExpression(expression, valueEntry) { | |
| // In case our parsing of the mathematical interpretation fails, we just want to return the original expression | |
| const initialExpression = expression; | |
| if (util.isString(expression)) { | |
| // We allow the usage of placeholders to indicate certain values. | |
| // For example [VALUE] refers to the value currently being inserted while [NAME] refers to the name of the entity providing the value | |
| // All these placeholders are documented at https://phabricator.bigfinite.com/T5 | |
| // This regex matches [BeID.Attribute] and [Attribute], stores the (optional) BeID and the Attribute in a capturing group and passes it to the replacePlaceholders function. | |
| expression = expression.replace(/\[([^\.]*?)\.?([^\.\]]*)\]/g, | |
| /** | |
| * This function is used to delegate the replacing of placeholders to specific functions | |
| * The first parameter will always be ignored since it just represents the matched substring. | |
| * This should change [123abc-myBeID.VALUE] to the latest value of the entity with BeID '123abc-myBeID'. | |
| * @param ignore {string} - Never use this | |
| * @param beID {string} - The optional beID that should be used for the lookup | |
| * @param attribute {string} - The actual attribute that is being used | |
| */ | |
| function replacePlaceholders(ignore, beID, attribute) { | |
| switch (attribute) { | |
| case 'VALUE' && !beID: | |
| return getCurrentValue(valueEntry); | |
| default: | |
| logger.error(`An unrecognized attribute was encountered: ${attribute}`); | |
| } | |
| }); | |
| // Some functions are used differently by us than they are defined in mathjs | |
| // That's why we do a simple search-and-replace for these few cases | |
| // We have to replace 'log(a)' with 'log(a, 10)' so this has to be done before we change 'ln(b)' to 'log(b)' | |
| expression = expression | |
| .replace('average', 'mean') | |
| .replace('random', 'random()') | |
| .replace(/log\((\d*)\)/g, 'log($1, 10)') | |
| .replace('ln', 'log'); | |
| } | |
| let expressionResult; | |
| try { | |
| expressionResult = math.eval(expression); | |
| } catch (err) { | |
| logger.info(`Unable to parse ${initialExpression} mathematically.`); | |
| return expression; | |
| } | |
| if (expressionResult.im) { | |
| logger.info(`Parsed expression ${expression} into ${expressionResult.im}`); | |
| return expressionResult.im; | |
| } | |
| logger.info(`Parsed expression ${expression} into ${expressionResult}`); | |
| return expressionResult; | |
| } | |
| /** | |
| * Returns the actual value recorded in the BF_VALUES record | |
| */ | |
| function getCurrentValue(valueEntry) { | |
| if (valueEntry) { | |
| return valueEntry.ValueData; | |
| } else { | |
| logger.error('Expression uses [VALUE] but no field ValueData was found'); | |
| } | |
| } | |
| module.exports = { | |
| evaluateExpression, | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment