/* eslint-disable no-use-before-define */ import { ComplexExpression, Expression, SimpleExpression } from "."; /** * Validate a simple, leaf node expression. No nested expressions */ export function validateSimpleExpression(expression: SimpleExpression) { if (expression.type) { throw new Error( `Expected simple expression. Got ${ expression.type } expression: ${JSON.stringify(expression)}` ); } if (!expression.operator) { throw new Error( `Expression has no operator property: ${JSON.stringify(expression)}` ); } if (!expression.field) { throw new Error( `Expression is missing field property: ${JSON.stringify(expression)}` ); } switch (expression.operator) { case "gt": case "lt": case "gte": case "lte": case "eq": case "neq": if (typeof expression.value === "undefined") { throw new Error( `Operator ${ expression.operator } expects a value property: ${JSON.stringify(expression)}` ); } if ( typeof expression.value === "object" && !expression.value.field && !expression.value.fields ) { throw new Error( `Expression with value of type object is supposed to be a reference to a field to compare to. No field property found: : ${expression}` ); } break; // Validate range expression case "between": if (!expression.value) { throw new Error( `Expression with operator ${ expression.operator } must have a value property: ${JSON.stringify(expression)}` ); } if (!Array.isArray(expression.value)) { throw new Error( `Expression with operator ${ expression.operator } must have an array as the value property: ${JSON.stringify( expression )}` ); } if (expression.value.length !== 2) { throw new Error( `Expression with operator ${ expression.operator } expects an array containing two values. Got ${ expression.value.length }: ${JSON.stringify(expression)}` ); } expression.value.forEach((number) => { if (isNaN(parseFloat(number))) { throw new Error( `Expression with operator ${ expression.operator } expected a range of two numbers. ${number} is not a valid number: ${JSON.stringify( expression )}` ); } }); break; case "is": case "not": case "isnot": case "required": return true; default: throw new Error( `Unknown operator ${expression.operator}: ${JSON.stringify(expression)}` ); } return true; } /** * Validate an expression with nested expressions, typically an or/and * expression with a list of clauses */ export function validateComplexExpression( expression: ComplexExpression ): boolean { if (expression.type && ["and", "or"].indexOf(expression.type) === -1) { throw new Error(`Unknown expression type: ${expression.type}`); } if (expression.type && !expression.clauses) { throw new Error(`Missing clauses for ${expression.type} expression`); } // Validate children return expression.clauses.reduce((valid, childExpression) => { switch (expression.type) { case "and": return valid && validateExpression(childExpression); case "or": return valid || validateExpression(childExpression); default: return false; } }, true); } export function validateExpression(expression: Expression) { // Complex expression if (expression.type) { return validateComplexExpression(expression as ComplexExpression); } // Ok, so this is a simple expression return validateSimpleExpression(expression as SimpleExpression); }