UNPKG

@instructure/quiz-interactions

Version:

A React UI component Library for quiz interaction types.

73 lines (71 loc) 2.91 kB
import uniq from 'lodash/uniq'; import { mathjsLoadingWrapper } from '../components/formula/common/util'; import { Decimal } from '@instructure/quiz-i18n'; import t from '@instructure/quiz-i18n/es/format-message'; export var variablesFromItemBody = function variablesFromItemBody(itemBody) { var body = itemBody || ''; var matches = body.match(/`[A-Za-z]\w*`/g) || []; var matchesWithoutBackticks = matches.map(function (match) { return match.replace(/`/g, ''); }); return uniq(matchesWithoutBackticks).sort(); }; export var formulaSyntaxError = function formulaSyntaxError(variables, formula) { var substitutions = {}; variables.forEach(function (varName) { return substitutions[varName] = 1; }); try { // TODO: This will fail if nothing has called components/formula/Edit/util/loadMathJs() yet. // we should either change this function signature to return a promise and do // loadMathjs().then(mathjs => mathjs.eval...) or make sure it is always preloaded by // the time we get here., var math = mathjsLoadingWrapper.mathjs; // This parses the formula detecting if the locale uses comma as separator var parsedFormula = parseFormulaDecimalSeparator(window.document.documentElement.lang || 'en-US', formula); // we replace function e() with the constant e // and function pi() with the constant pi // this is to match legacy canvas quizzes behavior which accepted both e/pi and e()/pi() var node = math.parse(parsedFormula); var transformed = node.transform(function (node, path, parent) { if (node.isFunctionNode && node.fn.isSymbolNode && node.fn.name === 'e') { return new math.expression.node.ConstantNode(Math.E); } else if (node.isFunctionNode && node.fn.isSymbolNode && node.fn.name === 'pi') { return new math.expression.node.ConstantNode(Math.PI); } else { return node; } }); var compiled = transformed.compile(); compiled.eval(substitutions); } catch (e) { var message = e.message; console.error('Formula Error: ' + e.message); var match = message.match(/Undefined symbol ([A-Za-z]+)/); if (match) { return t('Undefined symbol {symbol}', { symbol: match[1] }); } match = message.match(/Unexpected end of expression/); if (match) { return t('Unexpected end of expression'); } match = message.match(/Unexpected operator ([^\s]+)/); if (match) { return t('Unexpected operator {operator}', { operator: match[1] }); } return t('Invalid formula'); } return null; }; export var parseFormulaDecimalSeparator = function parseFormulaDecimalSeparator(locale, formula) { var _Decimal$getDelimiter = Decimal.getDelimiters(locale), decimal = _Decimal$getDelimiter.decimal; if (decimal === '.') { return formula; } return formula.replace(/(\d+),(\d+)/g, '$1.$2'); };