Files
DiceCloud/app/imports/api/properties/Constants.js
2021-02-11 13:03:31 +02:00

84 lines
2.3 KiB
JavaScript

import SimpleSchema from 'simpl-schema';
import VARIABLE_NAME_REGEX from '/imports/constants/VARIABLE_NAME_REGEX.js';
import ErrorSchema from '/imports/api/properties/subSchemas/ErrorSchema.js';
import { parse, CompilationContext } from '/imports/parser/parser.js';
import AccessorNode from '/imports/parser/parseTree/AccessorNode.js';
import SymbolNode from '/imports/parser/parseTree/SymbolNode.js';
/*
* Constants are primitive values that can be used elsewhere in computations
*/
let ConstantSchema = new SimpleSchema({
name: {
type: String,
optional: true,
},
// The technical, lowercase, single-word name used in formulae
variableName: {
type: String,
regEx: VARIABLE_NAME_REGEX,
min: 2,
defaultValue: 'newConstant',
},
// The input value to be parsed, must return a constant node or an array
// of constant nodes to be valid
calculation: {
type: String,
optional: true,
},
errors: {
type: Array,
autoValue(){
let calc = this.field('calculation');
if (!calc.isSet && this.isModifier) {
this.unset()
return;
}
let string = calc.value;
// Evaluate the calculation with no scope
let {result, errors} = parseString(string);
// Any errors will result in a failure
if (errors.length) return errors;
// Ban variables in constants if necessary
result && result.traverse(node => {
if (node instanceof SymbolNode || node instanceof AccessorNode){
errors.push({
type: 'error',
message: 'Variables can\'t be used to define a constant'
});
}
});
return errors;
}
},
'errors.$':{
type: ErrorSchema,
},
});
function parseString(string, fn = 'compile'){
let errors = [];
if (!string){
return {result: string, errors};
}
// Parse the string using mathjs
let node;
try {
node = parse(string);
} catch (e) {
let message = e.toString().split('.')[0];
errors.push({type: 'error', message});
return {result: string, errors};
}
// Parsing incomplete
if (node === null){
errors.push({type: 'warning', message: 'Unexpected end of input'});
return {result: string, errors};
}
let context = new CompilationContext();
let result = node[fn]({/*empty scope*/}, context);
return {result, errors: context.errors}
}
export { ConstantSchema };