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

@mathigon/hilbert

Package Overview
Dependencies
Maintainers
1
Versions
58
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@mathigon/hilbert - npm Package Compare versions

Comparing version 0.3.5 to 0.3.6

test/voice-test.ts

125

dist/hilbert.js

@@ -702,7 +702,2 @@ 'use strict';

lArr: '⇐',
CC: 'ℂ',
NN: 'ℕ',
QQ: 'ℚ',
RR: 'ℝ',
ZZ: 'ℤ'
};

@@ -742,3 +737,8 @@ const SPECIAL_IDENTIFIERS = {

psi: 'ψ',
omega: 'ω'
omega: 'ω',
CC: 'ℂ',
NN: 'ℕ',
QQ: 'ℚ',
RR: 'ℝ',
ZZ: 'ℤ'
};

@@ -753,2 +753,8 @@ const ALPHABET = 'abcdefghijklmnopqrstuvwxyz';

const OPERATOR_SYMBOLS = [...SIMPLE_SYMBOLS, ...COMPLEX_SYMBOLS];
const FUNCTION_NAMES = {
'_': 'sub',
'^': 'sup',
'//': '/',
'÷': '/'
};
const ESCAPES = {

@@ -767,2 +773,20 @@ '<': '&lt;',

}
const VOICE_STRINGS = {
'+': 'plus',
'−': 'minus',
'·': 'times',
'×': 'times',
'/': 'over',
'//': 'divided by',
'%': 'percent',
'!': 'factorial',
'±': 'plus-minus',
'=': 'equals',
'≠': 'does not equal',
'<': 'is less than',
'>': 'is greater than',
'≤': 'is less than or equal to',
'≥': 'is greater than or equal to',
'π': 'pi'
};

@@ -789,2 +813,4 @@ // =============================================================================

/** Converts the expression to a MathML string. */
toVoice(custom = {}) { return ''; }
/** Converts the expression to a MathML string. */
toMathML(custom = {}) { return ''; }

@@ -800,2 +826,3 @@ }

toString() { return '' + this.n; }
toVoice() { return '' + this.n; }
toMathML() { return `<mn>${this.n}</mn>`; }

@@ -822,2 +849,5 @@ }

toString() { return this.i; }
toVoice(custom = {}) {
return (this.i in custom) ? custom[this.i] : VOICE_STRINGS[this.i] || this.i;
}
}

@@ -835,2 +865,3 @@ class ExprString extends ExprElement {

toString() { return '"' + this.s + '"'; }
toVoice() { return this.s; }
toMathML() { return `<mtext>${this.s}</mtext>`; }

@@ -848,2 +879,5 @@ }

toString() { return this.o.replace('//', '/'); }
toVoice(custom = {}) {
return (this.o in custom) ? custom[this.o] : VOICE_STRINGS[this.o] || this.o;
}
get functions() { return [this.o]; }

@@ -857,3 +891,4 @@ toMathML() {

// =============================================================================
const PRECEDENCE = words('+ − * × · / ÷ // sup sub');
const PRECEDENCE = words('+ − * × · / ÷ // sup sub subsup');
const SUBSUP = words('sub sup subsup');
const COMMA = '<mo value="," lspace="0">,</mo>';

@@ -869,2 +904,4 @@ function needsBrackets(expr, parentFn) {

return false;
if (SUBSUP.includes(expr.fn) && SUBSUP.includes(parentFn))
return true;
return PRECEDENCE.indexOf(parentFn) > PRECEDENCE.indexOf(expr.fn);

@@ -947,2 +984,4 @@ }

return args.join('_');
if (this.fn === 'subsup')
return `${args[0]}_${args[1]}^${args[2]}`;
if (words('+ * × · / = < > ≤ ≥ ≈').includes(this.fn))

@@ -1001,2 +1040,7 @@ return args.join(' ' + this.fn + ' ');

}
if (this.fn === 'subsup') {
const args1 = [addMRow(this.args[0], argsF[0]),
addMRow(this.args[1], args[1]), addMRow(this.args[2], args[2])];
return `<msubsup>${args1.join('')}</msubsup>`;
}
if (isOneOf(this.fn, '(', '[', '{'))

@@ -1016,2 +1060,32 @@ return `<mfenced open="${this.fn}" close="${BRACKETS[this.fn]}">${argsF.join(COMMA)}</mfenced>`;

}
toVoice(custom = {}) {
const args = this.args.map(a => a.toVoice(custom));
const joined = args.join(' ');
if (this.fn in custom && !custom[this.fn])
return joined;
if (isOneOf(this.fn, '(', '[', '{'))
return `open bracket ${joined} close bracket`;
if (this.fn === 'sqrt')
return `square root of ${joined}`;
if (this.fn === '%')
return `${joined} percent`;
if (this.fn === '!')
return `${joined} factorial`;
if (this.fn === '/')
return `${args[0]} over ${args[1]}`;
if (this.fn === '//')
return `${args[0]} divided by ${args[1]}`;
if (this.fn === 'sup')
return `${args[0]} to the power of ${args[1]}`;
if (this.fn === 'sub')
return joined;
if (this.fn === 'subsup')
return `${args[0]} ${args[1]} to the power of ${args[2]}`;
if (VOICE_STRINGS[this.fn])
return args.join(` ${VOICE_STRINGS[this.fn]} `);
// TODO Implement other cases
if (isSpecialFunction(this.fn))
return `${this.fn} ${joined}`;
return `${this.fn} of ${joined}`;
}
}

@@ -1033,2 +1107,5 @@ // -----------------------------------------------------------------------------

}
toVoice(custom = {}) {
return this.items.map(i => i.toVoice(custom)).join(' ');
}
collapse() { return collapseTerm(this.items).collapse(); }

@@ -1050,2 +1127,5 @@ }

function createToken(buffer, type) {
if (type === TokenType.STR)
return new ExprString(buffer);
// Strings can be empty, but other types cannot.
if (!buffer || !type)

@@ -1055,4 +1135,2 @@ return undefined;

return new ExprSpace();
if (type === TokenType.STR)
return new ExprString(buffer);
if (type === TokenType.NUM) {

@@ -1156,3 +1234,3 @@ // This can happen if users simply type ".", which get parsed as number.

}
function findBinaryFunction(tokens, fn, toFn) {
function findBinaryFunction(tokens, fn) {
if (isOperator(tokens[0], fn))

@@ -1172,5 +1250,20 @@ throw ExprError.startOperator(tokens[0]);

throw ExprError.consecutiveOperators(token.o, b.o);
const args = [removeBrackets(a), removeBrackets(b)];
tokens.splice(i - 1, 3, new ExprFunction(toFn || token.o, args));
i -= 2;
const token2 = tokens[i + 2];
if (fn === '^ _' && isOperator(token, '_ ^') && isOperator(token2, '_ ^') && token.o !== token2.o) {
// Special handling for subsup operator.
const c = tokens[i + 3];
if (c instanceof ExprOperator)
throw ExprError.consecutiveOperators(token2.o, c.o);
const args = [removeBrackets(a), removeBrackets(b), removeBrackets(c)];
if (token.o === '^')
[args[1], args[2]] = [args[2], args[1]];
tokens.splice(i - 1, 5, new ExprFunction('subsup', args));
i -= 4;
}
else {
const fn = FUNCTION_NAMES[token.o] || token.o;
const args = [removeBrackets(a), removeBrackets(b)];
tokens.splice(i - 1, 3, new ExprFunction(fn, args));
i -= 2;
}
}

@@ -1181,5 +1274,3 @@ }

function prepareTerm(tokens) {
// TODO Combine sup and sub calls into a single supsub function.
findBinaryFunction(tokens, '^', 'sup');
findBinaryFunction(tokens, '_', 'sub');
findBinaryFunction(tokens, '^ _');
findBinaryFunction(tokens, '/');

@@ -1276,3 +1367,3 @@ return makeTerm(tokens);

findBinaryFunction(tokens, '= < > ≤ ≥');
findBinaryFunction(tokens, '// ÷', '/');
findBinaryFunction(tokens, '// ÷');
// Match multiplication operators.

@@ -1279,0 +1370,0 @@ tokens = findAssociativeFunction(tokens, '× * ·', true);

6

package.json
{
"name": "@mathigon/hilbert",
"version": "0.3.5",
"version": "0.3.6",
"description": "JavaScript expression parsing, MathML rendering and CAS.",

@@ -27,4 +27,4 @@ "keywords": [

"dependencies": {
"@mathigon/fermat": "^0.3.5",
"@mathigon/core": "^0.3.5"
"@mathigon/fermat": "^0.3.6",
"@mathigon/core": "^0.3.6"
},

@@ -31,0 +31,0 @@ "devDependencies": {

@@ -14,5 +14,4 @@ # Hilbert.ts

* [ ] Support for functions with subscripts (e.g. `log_a(b)`).
* [ ] Support for super+subscripts (e.g. `a_n^2` or `a^2_n`).
* [ ] Support for large operators (sum, product and integral).
* [ ] Parse ^ operator from right to left (e.g. `2^2^2 == 2^(2^2)`).
* [ ] Parse ^ and _ operator from right to left (e.g. `2^2^2 == 2^(2^2)`).
* [ ] Add `evaluate()`, `toString()` and `toMathML()` methods for many more

@@ -19,0 +18,0 @@ special functions.

@@ -8,3 +8,3 @@ // =============================================================================

import {Obj} from '@mathigon/core';
import {CONSTANTS, escape, isSpecialFunction} from './symbols';
import {CONSTANTS, escape, isSpecialFunction, VOICE_STRINGS} from './symbols';
import {ExprError} from './errors';

@@ -51,2 +51,5 @@

/** Converts the expression to a MathML string. */
toVoice(custom: Obj<string> = {}) { return ''; }
/** Converts the expression to a MathML string. */
toMathML(custom: MathMLMap = {}) { return ''; }

@@ -67,2 +70,4 @@ }

toVoice() { return '' + this.n; }
toMathML() { return `<mn>${this.n}</mn>`; }

@@ -93,2 +98,6 @@ }

toString() { return this.i; }
toVoice(custom: Obj<string> = {}) {
return (this.i in custom) ? custom[this.i] : VOICE_STRINGS[this.i] || this.i;
}
}

@@ -109,2 +118,4 @@

toVoice() { return this.s; }
toMathML() { return `<mtext>${this.s}</mtext>`; }

@@ -128,2 +139,6 @@ }

toVoice(custom: Obj<string> = {}) {
return (this.o in custom) ? custom[this.o] : VOICE_STRINGS[this.o] || this.o;
}
get functions() { return [this.o]; }

@@ -130,0 +145,0 @@

@@ -7,5 +7,5 @@ // =============================================================================

import {unique, flatten, words, isOneOf, join} from '@mathigon/core';
import {unique, flatten, words, isOneOf, join, Obj} from '@mathigon/core';
import {collapseTerm} from './parser';
import {BRACKETS, escape, isSpecialFunction} from './symbols';
import {BRACKETS, escape, isSpecialFunction, VOICE_STRINGS} from './symbols';
import {ExprElement, ExprNumber, CustomFunction, MathMLMap, VarMap, ExprMap} from './elements';

@@ -15,3 +15,4 @@ import {ExprError} from './errors';

const PRECEDENCE = words('+ − * × · / ÷ // sup sub');
const PRECEDENCE = words('+ − * × · / ÷ // sup sub subsup');
const SUBSUP = words('sub sup subsup');
const COMMA = '<mo value="," lspace="0">,</mo>';

@@ -24,2 +25,3 @@

if (!PRECEDENCE.includes(expr.fn)) return false;
if (SUBSUP.includes(expr.fn) && SUBSUP.includes(parentFn)) return true;
return PRECEDENCE.indexOf(parentFn) > PRECEDENCE.indexOf(expr.fn);

@@ -112,2 +114,3 @@ }

if (this.fn === 'sub') return args.join('_');
if (this.fn === 'subsup') return `${args[0]}_${args[1]}^${args[2]}`;

@@ -175,2 +178,8 @@ if (words('+ * × · / = < > ≤ ≥ ≈').includes(this.fn))

if (this.fn === 'subsup') {
const args1 = [addMRow(this.args[0], argsF[0]),
addMRow(this.args[1], args[1]), addMRow(this.args[2], args[2])];
return `<msubsup>${args1.join('')}</msubsup>`;
}
if (isOneOf(this.fn, '(', '[', '{'))

@@ -199,2 +208,26 @@ return `<mfenced open="${this.fn}" close="${BRACKETS[this.fn]}">${argsF.join(

}
toVoice(custom: Obj<string> = {}) {
const args = this.args.map(a => a.toVoice(custom));
const joined = args.join(' ');
if (this.fn in custom && !custom[this.fn]) return joined;
if (isOneOf(this.fn, '(', '[', '{')) return `open bracket ${joined} close bracket`;
if (this.fn === 'sqrt') return `square root of ${joined}`;
if (this.fn === '%') return `${joined} percent`;
if (this.fn === '!') return `${joined} factorial`;
if (this.fn === '/') return `${args[0]} over ${args[1]}`;
if (this.fn === '//') return `${args[0]} divided by ${args[1]}`;
if (this.fn === 'sup') return `${args[0]} to the power of ${args[1]}`;
if (this.fn === 'sub') return joined;
if (this.fn === 'subsup') return `${args[0]} ${args[1]} to the power of ${args[2]}`;
if (VOICE_STRINGS[this.fn]) return args.join(` ${VOICE_STRINGS[this.fn]} `);
// TODO Implement other cases
if (isSpecialFunction(this.fn)) return `${this.fn} ${joined}`;
return `${this.fn} of ${joined}`;
}
}

@@ -226,3 +259,7 @@

toVoice(custom: Obj<string> = {}) {
return this.items.map(i => i.toVoice(custom)).join(' ');
}
collapse() { return collapseTerm(this.items).collapse(); }
}

@@ -8,3 +8,3 @@ // =============================================================================

import {last, words} from '@mathigon/core';
import {SPECIAL_OPERATORS, SPECIAL_IDENTIFIERS, IDENTIFIER_SYMBOLS, OPERATOR_SYMBOLS, BRACKETS} from './symbols';
import {SPECIAL_OPERATORS, SPECIAL_IDENTIFIERS, IDENTIFIER_SYMBOLS, OPERATOR_SYMBOLS, BRACKETS, FUNCTION_NAMES} from './symbols';
import {ExprNumber, ExprIdentifier, ExprOperator, ExprSpace, ExprString, ExprElement} from './elements';

@@ -22,6 +22,8 @@ import {ExprFunction, ExprTerm} from './functions';

function createToken(buffer: string, type: TokenType) {
if (type === TokenType.STR) return new ExprString(buffer);
// Strings can be empty, but other types cannot.
if (!buffer || !type) return undefined;
if (type === TokenType.SPACE && buffer.length > 1) return new ExprSpace();
if (type === TokenType.STR) return new ExprString(buffer);

@@ -122,3 +124,3 @@ if (type === TokenType.NUM) {

function isOperator(expr: ExprElement, fns: string) {
function isOperator(expr: ExprElement, fns: string): expr is ExprOperator {
return expr instanceof ExprOperator && words(fns).includes(expr.o);

@@ -132,3 +134,3 @@ }

function findBinaryFunction(tokens: ExprElement[], fn: string, toFn?: string) {
function findBinaryFunction(tokens: ExprElement[], fn: string) {
if (isOperator(tokens[0], fn)) throw ExprError.startOperator(tokens[0]);

@@ -148,5 +150,18 @@ if (isOperator(last(tokens), fn)) throw ExprError.endOperator(last(tokens));

const args = [removeBrackets(a), removeBrackets(b)];
tokens.splice(i - 1, 3, new ExprFunction(toFn || token.o, args));
i -= 2;
const token2 = tokens[i + 2];
if (fn === '^ _' && isOperator(token, '_ ^') && isOperator(token2, '_ ^') && token.o !== token2.o) {
// Special handling for subsup operator.
const c = tokens[i + 3];
if (c instanceof ExprOperator) throw ExprError.consecutiveOperators(token2.o, c.o);
const args = [removeBrackets(a), removeBrackets(b), removeBrackets(c)];
if (token.o === '^') [args[1], args[2]] = [args[2], args[1]];
tokens.splice(i - 1, 5, new ExprFunction('subsup', args));
i -= 4;
} else {
const fn = FUNCTION_NAMES[token.o] || token.o;
const args = [removeBrackets(a), removeBrackets(b)];
tokens.splice(i - 1, 3, new ExprFunction(fn, args));
i -= 2;
}
}

@@ -160,5 +175,3 @@ }

function prepareTerm(tokens: ExprElement[]) {
// TODO Combine sup and sub calls into a single supsub function.
findBinaryFunction(tokens, '^', 'sup');
findBinaryFunction(tokens, '_', 'sub');
findBinaryFunction(tokens, '^ _');
findBinaryFunction(tokens, '/');

@@ -266,3 +279,3 @@ return makeTerm(tokens);

findBinaryFunction(tokens, '= < > ≤ ≥');
findBinaryFunction(tokens, '// ÷', '/');
findBinaryFunction(tokens, '// ÷');

@@ -269,0 +282,0 @@ // Match multiplication operators.

@@ -63,8 +63,2 @@ // =============================================================================

lArr: '⇐',
CC: 'ℂ',
NN: 'ℕ',
QQ: 'ℚ',
RR: 'ℝ',
ZZ: 'ℤ'
};

@@ -83,2 +77,3 @@

Omega: 'Ω',
alpha: 'α',

@@ -106,3 +101,9 @@ beta: 'β',

psi: 'ψ',
omega: 'ω'
omega: 'ω',
CC: 'ℂ',
NN: 'ℕ',
QQ: 'ℚ',
RR: 'ℝ',
ZZ: 'ℤ'
};

@@ -120,2 +121,9 @@

export const FUNCTION_NAMES: Obj<string> = {
'_': 'sub',
'^': 'sup',
'//': '/',
'÷': '/'
};
const ESCAPES: Obj<string> = {

@@ -138,1 +146,20 @@ '<': '&lt;',

}
export const VOICE_STRINGS: Obj<string> = {
'+': 'plus',
'−': 'minus',
'·': 'times',
'×': 'times',
'/': 'over',
'//': 'divided by',
'%': 'percent',
'!': 'factorial',
'±': 'plus-minus',
'=': 'equals',
'≠': 'does not equal',
'<': 'is less than',
'>': 'is greater than',
'≤': 'is less than or equal to',
'≥': 'is greater than or equal to',
'π': 'pi'
};

@@ -39,2 +39,18 @@ // =============================================================================

tape('SupSub', (test) => {
test.equal(mathML('a^2+1'), '<msup><mi>a</mi><mn>2</mn></msup><mo value="+">+</mo><mn>1</mn>');
test.equal(mathML('a^(2+1)'), '<msup><mi>a</mi><mrow><mn>2</mn><mo value="+">+</mo><mn>1</mn></mrow></msup>');
test.equal(mathML('a_2+1'), '<msub><mi>a</mi><mn>2</mn></msub><mo value="+">+</mo><mn>1</mn>');
test.equal(mathML('a_(2+1)'), '<msub><mi>a</mi><mrow><mn>2</mn><mo value="+">+</mo><mn>1</mn></mrow></msub>');
test.equal(mathML('a^2_1'), '<msubsup><mi>a</mi><mn>1</mn><mn>2</mn></msubsup>');
test.equal(mathML('a_1^2'), '<msubsup><mi>a</mi><mn>1</mn><mn>2</mn></msubsup>');
test.equal(mathML('(a_1)^2'), '<msup><mrow><mfenced><msub><mi>a</mi><mn>1</mn></msub></mfenced></mrow><mn>2</mn></msup>');
test.equal(mathML('(a^2)_1'), '<msub><mrow><mfenced><msup><mi>a</mi><mn>2</mn></msup></mfenced></mrow><mn>1</mn></msub>');
test.end();
});
tape('Custom Functions', (test) => {

@@ -54,3 +70,2 @@ const options = {

tape('Whitespace', (test) => {

@@ -57,0 +72,0 @@ test.equal(mathML('a b'), '<mi>a</mi><mspace/><mi>b</mi>');

@@ -46,7 +46,8 @@ // =============================================================================

tape('super and subscripts', (test) => {
test.equal(str('x^2_n'), '(x^2)_n');
test.equal(str('x^(2_n)'), 'x^2_n');
test.equal(str('x_n^2'), 'x_(n^2)');
test.equal(str('x_1^2 + 2^3_(n^2)'), 'x_(1^2) + (2^3)_(n^2)');
test.equal(str('x^(2_n)'), 'x^(2_n)');
test.equal(str('(x^2)_n'), '(x^2)_n');
test.equal(str('x_1^2 + 2^3_(n^2)'), 'x_1^2 + 2_(n^2)^3');
test.equal(str('x_(n+1) = x_n / 2'), 'x_(n + 1) = x_n / 2');
test.equal(str('x_n^2'), 'x_n^2');
test.equal(str('x^2_n'), 'x_n^2');
test.end();

@@ -53,0 +54,0 @@ });

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