mathjs/src/utils/latex.js
Jos de Jong 6f00715754
Specify import require paths (continuation of #1941) (#1962)
* Add `.js` extension to source file imports

* Specify package `exports` in `package.json`

Specify package type as `commonjs` (It's good to be specific)

* Move all compiled scripts into `lib` directory

Remove ./number.js (You can use the compiled ones in `./lib/*`)

Tell node that the `esm` directory is type `module` and enable tree shaking.

Remove unused files from packages `files` property

* Allow importing of package.json

* Make library ESM first

* - Fix merge conflicts
- Refactor `bundleAny` into `defaultInstance.js` and `browserBundle.cjs`
- Refactor unit tests to be able to run with plain nodejs (no transpiling)
- Fix browser examples

* Fix browser and browserstack tests

* Fix running unit tests on Node 10 (which has no support for modules)

* Fix node.js examples (those are still commonjs)

* Remove the need for `browserBundle.cjs`

* Generate minified bundle only

* [Security] Bump node-fetch from 2.6.0 to 2.6.1 (#1963)

Bumps [node-fetch](https://github.com/bitinn/node-fetch) from 2.6.0 to 2.6.1. **This update includes a security fix.**
- [Release notes](https://github.com/bitinn/node-fetch/releases)
- [Changelog](https://github.com/node-fetch/node-fetch/blob/master/docs/CHANGELOG.md)
- [Commits](https://github.com/bitinn/node-fetch/compare/v2.6.0...v2.6.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>

* Cleanup console.log

* Add integration tests to test the entry points (commonjs/esm, full/number only)

* Create backward compatibility error messages in the files moved/removed since v8

* Describe breaking changes in HISTORY.md

* Bump karma from 5.2.1 to 5.2.2 (#1965)

Bumps [karma](https://github.com/karma-runner/karma) from 5.2.1 to 5.2.2.
- [Release notes](https://github.com/karma-runner/karma/releases)
- [Changelog](https://github.com/karma-runner/karma/blob/master/CHANGELOG.md)
- [Commits](https://github.com/karma-runner/karma/compare/v5.2.1...v5.2.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>

Co-authored-by: Lee Langley-Rees <lee@greenimp.co.uk>
Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-09-20 18:01:29 +02:00

317 lines
10 KiB
JavaScript

/* eslint no-template-curly-in-string: "off" */
import escapeLatexLib from 'escape-latex'
import { hasOwnProperty } from './object.js'
export const latexSymbols = {
// GREEK LETTERS
Alpha: 'A',
alpha: '\\alpha',
Beta: 'B',
beta: '\\beta',
Gamma: '\\Gamma',
gamma: '\\gamma',
Delta: '\\Delta',
delta: '\\delta',
Epsilon: 'E',
epsilon: '\\epsilon',
varepsilon: '\\varepsilon',
Zeta: 'Z',
zeta: '\\zeta',
Eta: 'H',
eta: '\\eta',
Theta: '\\Theta',
theta: '\\theta',
vartheta: '\\vartheta',
Iota: 'I',
iota: '\\iota',
Kappa: 'K',
kappa: '\\kappa',
varkappa: '\\varkappa',
Lambda: '\\Lambda',
lambda: '\\lambda',
Mu: 'M',
mu: '\\mu',
Nu: 'N',
nu: '\\nu',
Xi: '\\Xi',
xi: '\\xi',
Omicron: 'O',
omicron: 'o',
Pi: '\\Pi',
pi: '\\pi',
varpi: '\\varpi',
Rho: 'P',
rho: '\\rho',
varrho: '\\varrho',
Sigma: '\\Sigma',
sigma: '\\sigma',
varsigma: '\\varsigma',
Tau: 'T',
tau: '\\tau',
Upsilon: '\\Upsilon',
upsilon: '\\upsilon',
Phi: '\\Phi',
phi: '\\phi',
varphi: '\\varphi',
Chi: 'X',
chi: '\\chi',
Psi: '\\Psi',
psi: '\\psi',
Omega: '\\Omega',
omega: '\\omega',
// logic
true: '\\mathrm{True}',
false: '\\mathrm{False}',
// other
i: 'i', // TODO use \i ??
inf: '\\infty',
Inf: '\\infty',
infinity: '\\infty',
Infinity: '\\infty',
oo: '\\infty',
lim: '\\lim',
undefined: '\\mathbf{?}'
}
export const latexOperators = {
transpose: '^\\top',
ctranspose: '^H',
factorial: '!',
pow: '^',
dotPow: '.^\\wedge', // TODO find ideal solution
unaryPlus: '+',
unaryMinus: '-',
bitNot: '\\~', // TODO find ideal solution
not: '\\neg',
multiply: '\\cdot',
divide: '\\frac', // TODO how to handle that properly?
dotMultiply: '.\\cdot', // TODO find ideal solution
dotDivide: '.:', // TODO find ideal solution
mod: '\\mod',
add: '+',
subtract: '-',
to: '\\rightarrow',
leftShift: '<<',
rightArithShift: '>>',
rightLogShift: '>>>',
equal: '=',
unequal: '\\neq',
smaller: '<',
larger: '>',
smallerEq: '\\leq',
largerEq: '\\geq',
bitAnd: '\\&',
bitXor: '\\underline{|}',
bitOr: '|',
and: '\\wedge',
xor: '\\veebar',
or: '\\vee'
}
export const latexFunctions = {
// arithmetic
abs: { 1: '\\left|${args[0]}\\right|' },
add: { 2: `\\left(\${args[0]}${latexOperators.add}\${args[1]}\\right)` },
cbrt: { 1: '\\sqrt[3]{${args[0]}}' },
ceil: { 1: '\\left\\lceil${args[0]}\\right\\rceil' },
cube: { 1: '\\left(${args[0]}\\right)^3' },
divide: { 2: '\\frac{${args[0]}}{${args[1]}}' },
dotDivide: { 2: `\\left(\${args[0]}${latexOperators.dotDivide}\${args[1]}\\right)` },
dotMultiply: { 2: `\\left(\${args[0]}${latexOperators.dotMultiply}\${args[1]}\\right)` },
dotPow: { 2: `\\left(\${args[0]}${latexOperators.dotPow}\${args[1]}\\right)` },
exp: { 1: '\\exp\\left(${args[0]}\\right)' },
expm1: `\\left(e${latexOperators.pow}{\${args[0]}}-1\\right)`,
fix: { 1: '\\mathrm{${name}}\\left(${args[0]}\\right)' },
floor: { 1: '\\left\\lfloor${args[0]}\\right\\rfloor' },
gcd: '\\gcd\\left(${args}\\right)',
hypot: '\\hypot\\left(${args}\\right)',
log: {
1: '\\ln\\left(${args[0]}\\right)',
2: '\\log_{${args[1]}}\\left(${args[0]}\\right)'
},
log10: { 1: '\\log_{10}\\left(${args[0]}\\right)' },
log1p: {
1: '\\ln\\left(${args[0]}+1\\right)',
2: '\\log_{${args[1]}}\\left(${args[0]}+1\\right)'
},
log2: '\\log_{2}\\left(${args[0]}\\right)',
mod: { 2: `\\left(\${args[0]}${latexOperators.mod}\${args[1]}\\right)` },
multiply: { 2: `\\left(\${args[0]}${latexOperators.multiply}\${args[1]}\\right)` },
norm: {
1: '\\left\\|${args[0]}\\right\\|',
2: undefined // use default template
},
nthRoot: { 2: '\\sqrt[${args[1]}]{${args[0]}}' },
nthRoots: { 2: '\\{y : $y^{args[1]} = {${args[0]}}\\}' },
pow: { 2: `\\left(\${args[0]}\\right)${latexOperators.pow}{\${args[1]}}` },
round: {
1: '\\left\\lfloor${args[0]}\\right\\rceil',
2: undefined // use default template
},
sign: { 1: '\\mathrm{${name}}\\left(${args[0]}\\right)' },
sqrt: { 1: '\\sqrt{${args[0]}}' },
square: { 1: '\\left(${args[0]}\\right)^2' },
subtract: { 2: `\\left(\${args[0]}${latexOperators.subtract}\${args[1]}\\right)` },
unaryMinus: { 1: `${latexOperators.unaryMinus}\\left(\${args[0]}\\right)` },
unaryPlus: { 1: `${latexOperators.unaryPlus}\\left(\${args[0]}\\right)` },
// bitwise
bitAnd: { 2: `\\left(\${args[0]}${latexOperators.bitAnd}\${args[1]}\\right)` },
bitNot: { 1: latexOperators.bitNot + '\\left(${args[0]}\\right)' },
bitOr: { 2: `\\left(\${args[0]}${latexOperators.bitOr}\${args[1]}\\right)` },
bitXor: { 2: `\\left(\${args[0]}${latexOperators.bitXor}\${args[1]}\\right)` },
leftShift: { 2: `\\left(\${args[0]}${latexOperators.leftShift}\${args[1]}\\right)` },
rightArithShift: { 2: `\\left(\${args[0]}${latexOperators.rightArithShift}\${args[1]}\\right)` },
rightLogShift: { 2: `\\left(\${args[0]}${latexOperators.rightLogShift}\${args[1]}\\right)` },
// combinatorics
bellNumbers: { 1: '\\mathrm{B}_{${args[0]}}' },
catalan: { 1: '\\mathrm{C}_{${args[0]}}' },
stirlingS2: { 2: '\\mathrm{S}\\left(${args}\\right)' },
// complex
arg: { 1: '\\arg\\left(${args[0]}\\right)' },
conj: { 1: '\\left(${args[0]}\\right)^*' },
im: { 1: '\\Im\\left\\lbrace${args[0]}\\right\\rbrace' },
re: { 1: '\\Re\\left\\lbrace${args[0]}\\right\\rbrace' },
// logical
and: { 2: `\\left(\${args[0]}${latexOperators.and}\${args[1]}\\right)` },
not: { 1: latexOperators.not + '\\left(${args[0]}\\right)' },
or: { 2: `\\left(\${args[0]}${latexOperators.or}\${args[1]}\\right)` },
xor: { 2: `\\left(\${args[0]}${latexOperators.xor}\${args[1]}\\right)` },
// matrix
cross: { 2: '\\left(${args[0]}\\right)\\times\\left(${args[1]}\\right)' },
ctranspose: { 1: `\\left(\${args[0]}\\right)${latexOperators.ctranspose}` },
det: { 1: '\\det\\left(${args[0]}\\right)' },
dot: { 2: '\\left(${args[0]}\\cdot${args[1]}\\right)' },
expm: { 1: '\\exp\\left(${args[0]}\\right)' },
inv: { 1: '\\left(${args[0]}\\right)^{-1}' },
sqrtm: { 1: `{\${args[0]}}${latexOperators.pow}{\\frac{1}{2}}` },
trace: { 1: '\\mathrm{tr}\\left(${args[0]}\\right)' },
transpose: { 1: `\\left(\${args[0]}\\right)${latexOperators.transpose}` },
// probability
combinations: { 2: '\\binom{${args[0]}}{${args[1]}}' },
combinationsWithRep: { 2: '\\left(\\!\\!{\\binom{${args[0]}}{${args[1]}}}\\!\\!\\right)' },
factorial: { 1: `\\left(\${args[0]}\\right)${latexOperators.factorial}` },
gamma: { 1: '\\Gamma\\left(${args[0]}\\right)' },
// relational
equal: { 2: `\\left(\${args[0]}${latexOperators.equal}\${args[1]}\\right)` },
larger: { 2: `\\left(\${args[0]}${latexOperators.larger}\${args[1]}\\right)` },
largerEq: { 2: `\\left(\${args[0]}${latexOperators.largerEq}\${args[1]}\\right)` },
smaller: { 2: `\\left(\${args[0]}${latexOperators.smaller}\${args[1]}\\right)` },
smallerEq: { 2: `\\left(\${args[0]}${latexOperators.smallerEq}\${args[1]}\\right)` },
unequal: { 2: `\\left(\${args[0]}${latexOperators.unequal}\${args[1]}\\right)` },
// special
erf: { 1: 'erf\\left(${args[0]}\\right)' },
// statistics
max: '\\max\\left(${args}\\right)',
min: '\\min\\left(${args}\\right)',
variance: '\\mathrm{Var}\\left(${args}\\right)',
// trigonometry
acos: { 1: '\\cos^{-1}\\left(${args[0]}\\right)' },
acosh: { 1: '\\cosh^{-1}\\left(${args[0]}\\right)' },
acot: { 1: '\\cot^{-1}\\left(${args[0]}\\right)' },
acoth: { 1: '\\coth^{-1}\\left(${args[0]}\\right)' },
acsc: { 1: '\\csc^{-1}\\left(${args[0]}\\right)' },
acsch: { 1: '\\mathrm{csch}^{-1}\\left(${args[0]}\\right)' },
asec: { 1: '\\sec^{-1}\\left(${args[0]}\\right)' },
asech: { 1: '\\mathrm{sech}^{-1}\\left(${args[0]}\\right)' },
asin: { 1: '\\sin^{-1}\\left(${args[0]}\\right)' },
asinh: { 1: '\\sinh^{-1}\\left(${args[0]}\\right)' },
atan: { 1: '\\tan^{-1}\\left(${args[0]}\\right)' },
atan2: { 2: '\\mathrm{atan2}\\left(${args}\\right)' },
atanh: { 1: '\\tanh^{-1}\\left(${args[0]}\\right)' },
cos: { 1: '\\cos\\left(${args[0]}\\right)' },
cosh: { 1: '\\cosh\\left(${args[0]}\\right)' },
cot: { 1: '\\cot\\left(${args[0]}\\right)' },
coth: { 1: '\\coth\\left(${args[0]}\\right)' },
csc: { 1: '\\csc\\left(${args[0]}\\right)' },
csch: { 1: '\\mathrm{csch}\\left(${args[0]}\\right)' },
sec: { 1: '\\sec\\left(${args[0]}\\right)' },
sech: { 1: '\\mathrm{sech}\\left(${args[0]}\\right)' },
sin: { 1: '\\sin\\left(${args[0]}\\right)' },
sinh: { 1: '\\sinh\\left(${args[0]}\\right)' },
tan: { 1: '\\tan\\left(${args[0]}\\right)' },
tanh: { 1: '\\tanh\\left(${args[0]}\\right)' },
// unit
to: { 2: `\\left(\${args[0]}${latexOperators.to}\${args[1]}\\right)` },
// utils
numeric: function (node, options) {
// Not sure if this is strictly right but should work correctly for the vast majority of use cases.
return node.args[0].toTex()
},
// type
number: {
0: '0',
1: '\\left(${args[0]}\\right)',
2: '\\left(\\left(${args[0]}\\right)${args[1]}\\right)'
},
string: {
0: '\\mathtt{""}',
1: '\\mathrm{string}\\left(${args[0]}\\right)'
},
bignumber: {
0: '0',
1: '\\left(${args[0]}\\right)'
},
complex: {
0: '0',
1: '\\left(${args[0]}\\right)',
2: `\\left(\\left(\${args[0]}\\right)+${latexSymbols.i}\\cdot\\left(\${args[1]}\\right)\\right)`
},
matrix: {
0: '\\begin{bmatrix}\\end{bmatrix}',
1: '\\left(${args[0]}\\right)',
2: '\\left(${args[0]}\\right)'
},
sparse: {
0: '\\begin{bsparse}\\end{bsparse}',
1: '\\left(${args[0]}\\right)'
},
unit: {
1: '\\left(${args[0]}\\right)',
2: '\\left(\\left(${args[0]}\\right)${args[1]}\\right)'
}
}
export const defaultTemplate = '\\mathrm{${name}}\\left(${args}\\right)'
const latexUnits = {
deg: '^\\circ'
}
export function escapeLatex (string) {
return escapeLatexLib(string, { preserveFormatting: true })
}
// @param {string} name
// @param {boolean} isUnit
export function toSymbol (name, isUnit) {
isUnit = typeof isUnit === 'undefined' ? false : isUnit
if (isUnit) {
if (hasOwnProperty(latexUnits, name)) {
return latexUnits[name]
}
return '\\mathrm{' + escapeLatex(name) + '}'
}
if (hasOwnProperty(latexSymbols, name)) {
return latexSymbols[name]
}
return escapeLatex(name)
}