84 lines
2.3 KiB
JavaScript
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 };
|