Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

evaluatex

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

evaluatex - npm Package Compare versions

Comparing version 1.0.0 to 2.0.1

.travis.yml

61

package.json
{
"name": "evaluatex",
"version": "1.0.0",
"description": "Converts Latex to evaluatable Javascript.",
"main": "src/Evaluatex.js",
"repository": {
"type": "git",
"url": "git+https://github.com/arthanzel/evaluatex.git"
},
"scripts": {
"compile": "browserify src/Evaluatex.js -o evaluatex.js",
"test": "mocha"
},
"keywords": [
"latex",
"js",
"math",
"eval",
"evaluate"
],
"author": "Martin Hanzel",
"license": "MIT",
"devDependencies": {
"chai": "^3.0.0",
"mocha": "^2.2.5",
"watchify": "^3.3.0"
},
"bugs": {
"url": "https://github.com/arthanzel/evaluatex/issues"
},
"homepage": "https://github.com/arthanzel/evaluatex#readme",
"directories": {
"test": "test"
}
"name": "evaluatex",
"version": "2.0.1",
"description": "An ASCII and LaTeX math parser and evaluator",
"main": "index.js",
"repository": "https://github.com/arthanzel/evaluatex.git",
"author": "Martin Hanzel <arthanzel@gmail.com>",
"license": "MIT",
"private": false,
"scripts": {
"build": "babel -d dist src",
"test": "mocha --require babel-register"
},
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-preset-env": "^1.6.1",
"babel-register": "^6.26.0",
"chai": "^4.1.2",
"mocha": "^5.1.1"
},
"dependencies": {
"babel-preset-stage-2": "^6.24.1"
},
"babel": {
"presets": [
"env",
"stage-2"
]
}
}

@@ -1,5 +0,1 @@

This npm package is a placeholder for a coming, npm-optimized version of evaluatex.
[arthanzel.github.io/evaluatex](arthanzel.github.io/evaluatex)
Evaluatex

@@ -17,41 +13,63 @@ =========

```bash
$ npm install evaluatex # (coming soon!)
$ bower install evaluatex # (coming soon!)
npm install evaluatex
# or
yarn install/add evaluatex
```
```javascript
// Node.js
var Evaluatex = require("evaluatex");
const evaluatex = require("evaluatex");
// or
import evaluatex from "evaluatex";
```
// Angular V1
angular.module("myModule", ["evaluatex"])
.service("MyService", function(Evaluatex) {});
Building
--------
Get [yarn](https://yarnpkg.com/en/) and do `yarn install`.
`yarn build` transpiles ES6 sources to `dist/`.
`yarn test` runs tests in the `test/` directory.
API
---
```javascript
const fn = evaluatex(expression, constants = {}, options = {});
const result = fn(variables = {});
```
```html
<!-- Vanilla JS -->
<script src="evaluatex.js"></script>
<script type="text/javascript">
console.log(Evaluatex);
</script>
- `evaluatex()` compiles a text math expression into a function `fn`.
- `expression` is an ASCII or LaTeX expression to be parsed and evaluated.
- `constants` is a map of constant values - values that don't change if you invoke `fn` more than once.
- `options` is a map of options for the compiler.
- `result` is the numerical result of the calculation.
- `variables` is a map of variables that *can* change between invocations.
Features and usage
------------------
Evaluatex compiles a string into a Javascript function that you can invoke anytime. It's like calling `eval()`, but without the [evil](http://linterrors.com/js/eval-is-evil).
```javascript
const fn = evaluatex("1 + 2 * 3 ^ 4")
fn()
// 163
```
Building
--------
`npm` test will run a set of unit tests defined in `./test/evaluatex.spec.js`. These tests run in Node, and not in any browser runtime.
A one-liner:
`npm run compile` will build the full script to `./evalulatex.js`. You can include this in your HTML files.
```javascript
const result = evaluatex("1 + 2 * 3 ^ 4")()
// result = 163
```
Usage
-----
Evaluatex returns a function because you can then invoke it multiple times with different variables.
```javascript
> Evaluatex.evaluate("1 + 2 * 3 ^ 4")
163
> Evaluatex.evaluate("sin(0.5PI) + magic", { magic: 3 })
4
fn2 = evaluatex("1 + magic")
fn2({ magic: 3 })
// 4
fn2({ magic: 99 })
// 100
```
Features
--------
By default, Evaluatex acts in ASCII mode. To use LaTeX-specific behaviour, pass in `{ latex: true }` as the **third** argument to `Evaluatex.evaluate`. Read on to learn more.
### Evaluatex is a calculator

@@ -61,18 +79,18 @@ Evaluatex supports all of the features you should expect from a simple calculator, including order of operations. Exponents use the `^` operator.

```javascript
> Evaluatex.evaluate("1 + 2 * 3 ^ 4")
163
evaluatex("1 + 2 * 3 ^ 4")()
// 163
```
You can use variables in expressions that are visible to the expression only:
You can use named values in expressions that are visible to the expression only. This avoids the need for `eval`. See the *Constants and variables* section for more.
```javascript
> Evaluatex.evaluate("1 + a / b", { a: 3, b: 4 })
1.75
evaluatex("1 + a / b", { a: 3, b: 4 })()
// 1.75
```
Implicit multiplication with parens or variables is not a problem.
Implicit multiplication with brackets or variables is not a problem.
```javascript
> Evaluatex.evaluate("4a(1+b)", { a: 3, b: 4 })
60
evaluatex("4a(1 + b)", { a: 3, b: 4 })()
// 60
```

@@ -83,21 +101,23 @@

```javascript
> Evaluatex.evaluate("sin(0.5PI) + magic", { magic: 3 })
4
evaluatex("sin(0.5PI) + magic", { magic: 3 })()
// 4
```
You can omit parens from simple functions, but be careful with implicit multiplication.
You can omit brackets from simple functions, but be careful with implicit multiplication.
```javascript
> Evaluatex.evaluate("sin 2PI") // Interpreted as sin(2) * PI
2.8566
> Evaluatex.evaluate("sin PI^2") // Interpreted as sin(PI^2)
-0.43
evaluatex("sin 2PI")() // Interpreted as sin(2) * PI
// 2.8566
evaluatex("sin PI^2")() // Interpreted as sin(PI^2)
// -0.43
```
> There is no globally-accepted standard for treating coefficients inside paren-less functions. Whenever in doubt, use parentheses.
> There is no universally-accepted standard for treating coefficients inside paren-less functions. Whenever in doubt, use parentheses.
## Custom functions
You can even define custom functions.
```javascript
> Evaluatex.evaluate("incr(4)", { incr: function(x) { return x + 1; } })
5
evaluatex("incr(4)", { incr: function(x) { return x + 1; } })()
// 5
```

@@ -108,6 +128,6 @@

```javascript
> Evaluatex.evaluate("hypot(3, 4)")
5
> Evaluatex.evaluate("min(5,4,3,2,1)")
1
evaluatex("hypot(3, 4)")()
// 5
evaluatex("min(5, 4, 3, 2, 1)")()
// 1
```

@@ -118,8 +138,8 @@

```javascript
> Evaluatex.evaluate("logn(81, 3)")
4
> Evaluatex.evaluate("rootn(8, 3)")
2
> Evaluatex.evaluate("csc(0.25PI)")
1.414
evaluatex("logn(81, 3)")()
// 4
evaluatex("rootn(8, 3)")()
// 2
evaluatex("csc(0.25PI)")()
// 1.414
```

@@ -130,4 +150,4 @@

```javascript
> Evaluatex.evaluate("|5 - 20|")
15
evaluatex("|5 - 20|")()
// 15
```

@@ -138,6 +158,39 @@

```javascript
> Evaluatex.evaluate("3.6!")
24
evaluatex("3.6!")()
// 24
```
### Constants and variables
You can refer to symbols, such as `x`, in a math expression. These symbols can be **constant** or **variable**.
**Constants** are specified in the call to `evaluatex()` as the second parameter. Their values are compiled by Evaluatex into the resultant equation. Use constants if you know that they won't change between invocations. Constants may be numeric values or functions.
```javascript
const fn = evaluatex("100 + x + incr(1)", { x: 5, incr: x => x + 1 });
fn();
// 107
```
**Variables** are specified in the output function. Their values can be changed between invocations. If you compile an expression with a variable, you *must* give a value for that variable, otherwise Evaluatex will complain. Variables may only be numeric values, and not functions.
```javascript
const fn = evaluatex("100 + x");
fn({ x: 5 }); // 105
fn({ x: 6 }); // 106
```
You can combine constants and variables. Do note that constants have priority over variables - if you define a constant, you can't change it without re-compiling the equation.
```javascript
const fn = evaluatex("x + y", { x: 100 });
fn({ y: 5 }); // 105
fn({ x: 0, y: 6 }); // 106
```
### Constants and variables: performance notes
Using a variable requires looking up the variable every time that it is used. This is a little slow. If a variable doesn't change, prefer constants.
If you use a constant and need to change it, you need to call `evaluatex()` again to re-compile the math expression. This is **really** slow. If there's a chance that a constant may change (e.g. user input), prefer variables.
LaTeX-specific behaviour

@@ -148,4 +201,4 @@ ------------------------

```javascript
> Evaluatex.evaluate("x^24", { x: 2 }, { latex: true })
16
evaluatex("x^24", { x: 2 }, { latex: true })()
// 16
```

@@ -156,4 +209,4 @@

```javascript
> Evaluatex.evaluate("x^{24}", { x: 2 }, { latex: true })
16777216
evaluatex("x^{24}", { x: 2 }, { latex: true })()
// 16777216
```

@@ -164,3 +217,3 @@

```javascript
> Evaluatex.evaluate("x^(24)", { x: 2 }, { latex: true })
evaluatex("x^(24)", { x: 2 }, { latex: true })
Error!

@@ -174,4 +227,4 @@ ```

```javascript
> Evaluatex.evaluate("\\frac 123") // Interpreted as (1/2) * 3
evaluatex("\\frac 123") // Interpreted as (1/2) * 3
1.5
```

@@ -1,133 +0,147 @@

var interpolate = require("./utils/interpolate");
var isNumber = require("./utils/isNumber");
/**
* Node represents a node in an abstract syntax tree. Nodes have the following properties:
* - A type, which determines how it is evaluated;
* - A value, such as a number or function; and
* - An ordered list of children.
*/
export default class Node {
constructor(type, value = "") {
this.type = type;
this.value = value;
this.children = [];
}
// Nodes that are allowed to have only one child. Nodes that have one child and are not in this list will be simplified during parsing.
var UNARY_NODES = ["FACTORIAL", "FUNCTION", "INVERSE", "NEGATE"];
/**
* Adds a node to the list of children and returns this Node.
* @param node Child node to addChild.
* @returns {Node} This node.
*/
addChild(node) {
this.children.push(node);
return this;
}
// Represents a node in an abstract syntax tree. Nodes have a type (such as NUMBER), a value (such as the actual number value), and a list of child nodes.
var Node = module.exports = function Node(type, value) {
if (value === undefined) value = "";
/**
* Returns this Node's first child.
*/
get child() {
return this.children[0];
}
this.type = type;
this.value = value;
this.children = [];
};
/**
* Evaluates this Node and all child nodes recursively, returning the numerical result of this Node.
*/
evaluate(vars) {
let result = 0;
// Adds a child node.
Node.prototype.add = function(node) {
this.children.push(node); return this;
};
switch (this.type) {
case Node.TYPE_FUNCTION:
const evaluatedChildren = this.children.map(childNode => childNode.evaluate(vars));
result = this.value.apply(this, evaluatedChildren);
break;
case Node.TYPE_INVERSE:
result = 1.0 / this.child.evaluate(vars);
break;
case Node.TYPE_NEGATE:
result = -this.child.evaluate(vars);
break;
case Node.TYPE_NUMBER:
result = this.value;
break;
case Node.TYPE_POWER:
result = Math.pow(
this.children[0].evaluate(vars),
this.children[1].evaluate(vars)
);
break;
case Node.TYPE_PRODUCT:
result = this.children.reduce((product, child) => product * child.evaluate(vars), 1);
break;
case Node.TYPE_SUM:
result = this.children.reduce((sum, child) => sum + child.evaluate(vars), 0);
break;
case Node.TYPE_SYMBOL:
if (isFinite(vars[this.value])) {
return vars[this.value];
}
throw "Symbol " + this.value + " is undefined or not a number";
}
// Calculates the numerical representation of this node, evaluating any child nodes as well.
Node.prototype.evaluate = function(locals) {
switch (this.type) {
case "FACTORIAL":
result = 1;
var i = Math.round(this.children[0].evaluate(locals));
return result;
}
// Factorials for numbers < 0 are not defined.
if (i < 0) {
throw "Can't take the factorial of a negative number!";
}
/**
* Determines whether this Node is unary, i.e., whether it can have only one child.
* @returns {boolean}
*/
isUnary() {
return UNARY_NODES.indexOf(this.type) >= 0;
}
// Compute the factorial.
for (i; i > 0; i--) {
result *= i;
}
return result;
case "FUNCTION":
var evaluatedChildren = [];
for (i in this.children) {
evaluatedChildren.push(this.children[i].evaluate(locals));
}
return this.value.apply(this, evaluatedChildren);
case "INVERSE":
return 1.0 / this.children[0].evaluate(locals);
case "NEGATE":
return -this.children[0].evaluate(locals);
case "NUMBER":
return this.value;
case "POWER":
return Math.pow(
this.children[0].evaluate(locals),
this.children[1].evaluate(locals)
);
case "PRODUCT":
var result = 1;
for (i in this.children) {
result *= this.children[i].evaluate(locals);
}
return result;
case "SUM":
var result = 0;
for (i in this.children) {
result += this.children[i].evaluate(locals);
}
return result;
case "SYMBOL":
if (isNumber(locals[this.value])) {
return locals[this.value];
}
throw "Symbol " + this.value +
" is undefined or not a number";
get nodeCount() {
let count = 1;
for (let i of this.children) {
count += i.nodeCount;
}
return count;
}
};
Node.prototype.isUnary = function isUnary() {
return UNARY_NODES.indexOf(this.type) >= 0;
};
/**
* Prints a tree-like representation of this Node and all child Nodes to the console.
* Useful for debugging parser problems.
* If printTree() is called on the root node, it prints the whole AST!
* @param level (Integer, Optional) Initial level of indentation. You shouldn't need to use this.
*/
printTree(level = 0) {
// Generate the indent string from the current `level`.
// Child nodes will have a greater `level` and will appear indented.
let indent = "";
let indentString = " ";
for (let i = 0; i < level; i++) {
indent += indentString;
}
// Prints a tree-like representation of this Node and its children to the console.
// Useful for debugging parser problems.
// If `printTree` is called on the root node, it prints the whole AST!
Node.prototype.printTree = function(level) {
level = level || 0;
console.log(indent + this.toString());
// Generate the indent string from the current `level`.
// Child nodes will have a greater `level` and will appear indented.
var indent = "";
var iString = " ";
for (var i = 0; i < level; i++) {
indent += iString;
};
// Print each child.
for (let i in this.children) {
this.children[i].printTree(level + 1);
}
}
// Format: `TYPE value (children)`
// OR
// `TYPE (children)`.
if (this.value) {
console.log(interpolate("%% % (%)",
indent,
this.type,
this.value.name || this.value,
this.children.length));
simplify() {
if (this.children.length > 1 || this.isUnary()) {
// Node can't be simplified.
// Clone this Node and simplify its children.
let newNode = new Node(this.type, this.value);
for (let i in this.children) {
newNode.addChild(this.children[i].simplify());
}
return newNode;
}
else if (this.children.length === 1) {
// A non-unary node with no children has no function.
return this.children[0].simplify();
}
else {
// A node with no children is a terminal.
return this;
}
}
else {
console.log(interpolate("%% (%)",
indent,
this.type,
this.children.length));
}
// Print each child.
for (var i in this.children) {
this.children[i].printTree(level + 1);
toString() {
let val = typeof this.value === "function" ? this.value.name : this.value;
return `${ this.children.length } ${ this.type } [${ val }]`;
}
};
// Simplifies this Node and all children recursively, returning a new
// node tree.
Node.prototype.simplify = function() {
if (this.children.length > 1 || this.isUnary()) {
var newNode = new Node(this.type, this.value);
for (i in this.children) {
newNode.add(this.children[i].simplify());
}
return newNode;
}
else if (this.children.length == 1) {
return this.children[0].simplify();
}
else { // No children
return this;
}
};
static TYPE_FUNCTION = "FUNCTION";
static TYPE_INVERSE = "INVERSE";
static TYPE_NEGATE = "NEGATE";
static TYPE_NUMBER = "NUMBER";
static TYPE_POWER = "POWER";
static TYPE_PRODUCT = "PRODUCT";
static TYPE_SUM = "SUM";
static TYPE_SYMBOL = "SYMBOL";
}
const UNARY_NODES = ["FACTORIAL", "FUNCTION", "INVERSE", "NEGATE"];

@@ -1,22 +0,64 @@

// A `Token` is a generic construct that has a `type` and `value`. Tokens are used by the lexer and parser.
// The lexer assigns each token a type, such as `NUMBER`; and a value, such as the actual numeric value of the token.
var Token = module.exports = function(type, value) {
if (value === undefined) value = "";
/**
* Token represents a lexical token. It has a type and a value.
* @param type (String) Token type. A list of types is found in "utils/tokens.js".
* @param value Value of the token.
*/
export default class Token {
constructor(type, value = "") {
this.type = type;
this.value = value;
}
this.type = type;
this.value = value;
};
equals(token) {
return this.type === token.type &&
this.value === token.value;
}
Token.prototype.equals = function(type, value) {
if (value === undefined) {
return this.type === type;
toString() {
if (TRIVIAL_TOKENS.indexOf(this.type) >= 0) {
return this.type;
}
// Does the value contain a function? If so, print a human-readable name.
let value = typeof this.value === "function" ? this.value.name : this.value;
return `${ this.type }[${ value }]`;
}
else {
return this.type === type &&
this.value === value;
}
static TYPE_LPAREN = "LPAREN";
static TYPE_RPAREN = "RPAREN";
static TYPE_PLUS = "PLUS";
static TYPE_MINUS = "MINUS";
static TYPE_TIMES = "TIMES";
static TYPE_DIVIDE = "DIVIDE";
static TYPE_COMMAND = "COMMAND";
static TYPE_SYMBOL = "SYMBOL";
static TYPE_WHITESPACE = "WHITESPACE";
static TYPE_ABS = "ABSOLUTEVAL";
static TYPE_BANG = "BANG";
static TYPE_COMMA = "COMMA";
static TYPE_POWER = "POWER";
static TYPE_NUMBER = "NUMBER";
static patterns = new Map([
[Token.TYPE_LPAREN, /(\(|\[|{|\\left\(|\\left\[)/], // Match (, [, {, \left(, \left[
[Token.TYPE_RPAREN, /(\)|]|}|\\right\)|\\right])/], // Match ), ], }, \right), \right]
[Token.TYPE_PLUS, /\+/],
[Token.TYPE_MINUS, /-/],
[Token.TYPE_TIMES, /\*/],
[Token.TYPE_DIVIDE, /\//],
[Token.TYPE_COMMAND, /\\[A-Za-z]+/],
[Token.TYPE_SYMBOL, /[A-Za-z][A-Za-z0-9]*/],
[Token.TYPE_WHITESPACE, /\s+/], // Whitespace
[Token.TYPE_ABS, /\|/],
[Token.TYPE_BANG, /!/],
[Token.TYPE_COMMA, /,/],
[Token.TYPE_POWER, /\^/],
[Token.TYPE_NUMBER, /\d+(\.\d+)?/]
]);
};
Token.prototype.toString = function() {
return this.type + "(" + this.value + ")";
};
/**
* Trivial tokens are those that can only have a single value, so printing their value is unnecessary.
*/
const TRIVIAL_TOKENS = ["TPLUS", "TMINUS", "TTIMES", "TDIVIDE", "TWS", "TABS", "TBANG", "TCOMMA", "TPOWER"];

@@ -1,18 +0,25 @@

var assert = require("chai").assert;
require("./helpers/aboutEqual");
import { assert } from "chai";
import evaluatex from "../src/evaluatex";
var Evaluatex = require("../src/evaluatex.js");
function test(expression, expectedResult, constants = {}, variables = {}, opts = {}) {
const fn = evaluatex(expression, constants, opts);
const result = fn(variables);
try {
assert.closeTo(fn(variables), expectedResult, 1E-6);
}
catch (e) {
console.log(fn.tokens.toString());
fn.ast.printTree();
throw e;
}
}
var test = function(expression, result, locals, opts) {
assert.aboutEqual(Evaluatex.evaluate(expression, locals, opts), result);
};
describe("Evaluatex.js", function() {
it("evaluates simple formulae", function() {
describe("Evaluatex", function () {
it("computes simple formulae", function () {
test("2", 2);
test("-5 - -4", -1);
test("(1 + 2 / 3 * 4 - 5)^2", 16/9);
test("(1 + 2 / 3 * 4 - 5)^2", 16 / 9);
});
it("evaluates variables", function() {
it("allows constants", function () {
test("x", 5, { x: 5 });

@@ -23,6 +30,9 @@ test("x^2 + y^2 - 13", 0, { x: 3, y: 2 });

it("supports Javascript's Math functions and constants", function() {
test("sin(PI) + tan(PI/4) + cos(-PI * 2)", 2);
test("cos(PI)^2", 1);
test("sqrt(LN2 + x)", Math.sqrt(Math.LN2 + 5), { x: 5 });
it("doesn't overwrite constants with variables", function () {
test("x", 5, { /* constant */ x: 5 }, { /* variable - should be ignored */ x: 6 });
});
it("supports Javascript's Math functions and constants", function () {
test("PI", Math.PI);
test("sqrt(4)", 2);
test("hypot(10)", 10);

@@ -33,26 +43,24 @@ test("hypot(3, 4)", 5);

it("supports absolute values", function() {
it("supports absolute values", function () {
test("|5|", 5);
test("|-5|", 5);
test("|--5|", 5);
test("|5 - 10|^2", 25);
test("2 * -|2 - 4|", -4);
});
it("supports factorials", function() {
it("supports factorials", function () {
test("4!", 24);
test("(4 + 1)!", 120);
test("4 + 1 !", 5);
test("3.9! + 3.1!", 30);
test("4 + 1!", 5);
test("3.9!", 4 * 3 * 2);
test("3.9! + 3.1!", 30); // Round to nearest integer
});
it("supports custom functions", function() {
test("incr(5)", 6, { incr: function(a) { return a + 1; } });
test("add(5, 6)", 11, { add: function(a, b) { return a + b; } });
it("supports custom functions", function () {
test("incr(5)", 6, { incr: a => a + 1 });
test("add(5, 6)", 11, { add: (a, b) => a + b });
});
it("supports parens", function() {
test("{1 + [2 - {3 + 4}])", -4);
test("{1 + \\left[2 - \\left(3 + 4\\right)\\right]}", -4);
});
it("has own convenience functions", function() {
it("has own convenience functions", function () {
test("logn(81, 3)", 4);

@@ -65,15 +73,32 @@ test("rootn(8, 3)", 2);

it("supports implicit multiplication", function() {
it("supports implicit multiplication", function () {
// Test implicit multiplication
// ["-2a + - 2 a + (2)(a a) + 2(a) + a(2)", 18, { a: 3 }],
// ["4a(1+b)", 60, { a: 3, b: 4 }],
// Terms separated by whitespace always multiply.
// Numbers followed by symbols always multiply.
test("2a", 6, { a: 3 });
test("a 2", 6, { a: 3 });
test("a2", 100, { a: 3, a2: 100 }); // a2 is a symbol and not a * 2
test("a b", 6, { a: 3, b: 2 });
test("a sin(0.5PI)", 3, { a: 3 });
test("2 sin(0.5PI)", 2);
test("2(a)", 6, { a: 3 });
test("(2)4", 8);
test("(2)(4)", 8);
// A symbol followed by a term in brackets is a multiplication unless the symbol is a function.
test("a(2)", 6, { a: 3 });
test("a(2)", 3, { a: arg => arg + 1 });
test("a(2)b", 9, { a: arg => arg + 1, b: 3 });
// Bracketed terms always multiply...
test("(2)(3)", 6);
test("2(3)", 6);
test("(2)3", 6);
test("a(2+3)", 20, { a: 4 });
test("2(a + b)", 14, { a: 3, b: 4 });
// ...unless one is part of a function
test("a(2)(3)", 24, { a: 4 });
test("a(2)(3)", 9, { a: arg => arg + 1 });
test("3a(2)(3)", 27, { a: arg => arg + 1 });
// Some complicated examples
test("2x^2 + 5x + 7", 18 + 15 + 7, { x: 3 });

@@ -84,31 +109,39 @@ test("-2a + - 2 a + (2)(a a) + 2(a) + a(2)", 18, { a: 3 });

it("supports paren-less functions", function() {
test("cos PI^2", Math.cos(Math.PI * Math.PI));
test("cos 0.5PI", Math.cos(0.5) * Math.PI);
test("log10 100 + 2", 4);
test("log10 100 * 2", 4);
test("log10 100 ^ 2", 4);
it("supports paren-less functions", function () {
const PI = Math.PI;
// In ASCII mode, functions can take a single argument without parens.
// Single powers, absolute value, negatives, etc. are all part of the argument.
// Any additions or multiplications are not.
test("cos PI", -1);
test("cos PI + PI", -1 + PI);
test("cos PI * PI", -1 * PI);
test("cos PI^PI", Math.cos(Math.pow(PI, PI)));
test("cos 3PI", Math.cos(3) * PI);
// Same thing with logs
test("log10 100 + 2", 4); // log10(100) + 2
test("log10 100 * 2", 4); // log10(100) * 2
test("log10 100 ^ 2", 4); // log10(100^2)
});
it("support LaTeX's stupid one-number expressions", function() {
test("2^24", 16, {}, { latex: true });
test("2^{12}", 4096, {}, { latex: true });
test("\\frac 4 2", 2, {}, { latex: true });
test("\\frac 4 2 ^ 3", 8, {}, { latex: true });
test("\\frac {4 ^ 2} 3", 16/3, {}, { latex: true });
test("\\frac {(4 ^ 2)} {3}", 16/3, {}, { latex: true });
test("\\frac {4 ^ 2} 32", 32/3, {}, { latex: true });
it("supports parens", function () {
test("{1 + [2 - {3 + 4}]}", -4);
test("{1 + \\left[2 - \\left(3 + 4\\right)\\right]}", -4);
});
it("supports LaTeX typesetting", function() {
test("\\frac{1}{2}x^{-\\frac{1}{2}}", 1/6, { x: 9 }, { latex: true });
test("\\sqrt 45", 10, {}, { latex: true });
it("support LaTeX's stupid one-number expressions", function () {
test("2^24", 16, {}, {}, { latex: true });
test("2^{12}", 4096, {}, {}, { latex: true });
test("\\frac 4 2", 2, {}, {}, { latex: true });
test("\\frac 4 2 ^ 3", 8, {}, {}, { latex: true });
test("\\frac {4 ^ 2} 3", 16 / 3, {}, {}, { latex: true });
test("\\frac {(4 ^ 2)} {3}", 16 / 3, {}, {}, { latex: true });
test("\\frac {4 ^ 2} 32", 32 / 3, {}, {}, { latex: true });
});
});
describe("Evaluatex utilities", function() {
it("interpolates strings", function() {
var interpolate = require("../src/utils/interpolate");
assert.equal(interpolate("a % b % c \\% d", 3, "foo"), "a 3 b foo c % d");
it.only("supports LaTeX typesetting", function () {
test("\\frac{1}{2}x^{-\\frac{1}{2}}", 1 / 6, { x: 9 }, {}, { latex: true });
test("\\sqrt 45", 10, {}, {}, { latex: true });
});
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc