1
0

add initial marp implementation with sample content and build configuration

This commit is contained in:
2025-09-13 18:13:22 +02:00
parent dcacc9b409
commit e5f219507f
10319 changed files with 1402023 additions and 0 deletions

85
node_modules/mathjax-full/ts/input/asciimath.ts generated vendored Normal file
View File

@@ -0,0 +1,85 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the AsciiMath InputJax object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AbstractInputJax} from '../core/InputJax.js';
import {LegacyAsciiMath} from './asciimath/mathjax2/input/AsciiMath.js';
import {separateOptions, OptionList} from '../util/Options.js';
import {MathDocument} from '../core/MathDocument.js';
import {MathItem} from '../core/MathItem.js';
import {FindAsciiMath} from './asciimath/FindAsciiMath.js';
/*****************************************************************/
/**
* Implements the AsciiMath class (extends AbstractInputJax)
*
* @template N The HTMLElement node class
* @template T The Text node class
* @template D The Document class
*/
export class AsciiMath<N, T, D> extends AbstractInputJax<N, T, D> {
/**
* The name of the input jax
*/
public static NAME: string = 'AsciiMath';
/**
* @override
*/
public static OPTIONS: OptionList = {
...AbstractInputJax.OPTIONS,
FindAsciiMath: null
};
/**
* The FindMath object used to search for AsciiMath in the document
*/
protected findAsciiMath: FindAsciiMath<N, T, D>;
/**
* @override
*/
constructor(options: OptionList) {
let [ , find, am] = separateOptions(options, FindAsciiMath.OPTIONS, AsciiMath.OPTIONS);
super(am);
this.findAsciiMath = this.options['FindAsciiMath'] || new FindAsciiMath(find);
}
/**
* Use legacy AsciiMath input jax for now
*
* @override
*/
public compile(math: MathItem<N, T, D>, _document: MathDocument<N, T, D>) {
return LegacyAsciiMath.Compile(math.math, math.display);
}
/**
* @override
*/
public findMath(strings: string[]) {
return this.findAsciiMath.findMath(strings);
}
}

View File

@@ -0,0 +1,154 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the AsciiMath version of the FindMath object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AbstractFindMath} from '../../core/FindMath.js';
import {OptionList} from '../../util/Options.js';
import {quotePattern} from '../../util/string.js';
import {ProtoItem, protoItem} from '../../core/MathItem.js';
/**
* Shorthand types for data about end delimiters and delimiter pairs
*/
export type EndItem = [string, boolean, RegExp];
export type Delims = [string, string];
/*****************************************************************/
/**
* Implements the FindAsciiMath class (extends AbstractFindMath)
*
* Locates AsciiMath expressions within strings
*
* @template N The HTMLElement node class
* @template T The Text node class
* @template D The Document class
*/
export class FindAsciiMath<N, T, D> extends AbstractFindMath<N, T, D> {
/**
* @override
*/
public static OPTIONS: OptionList = {
delimiters: [['`', '`']], // The start/end delimiter pairs for asciimath code
};
/**
* The regular expression for any starting delimiter
*/
protected start: RegExp;
/**
* The end-delimiter data keyed to the opening delimiter string
*/
protected end: {[name: string]: EndItem};
/**
* False if the configuration has no delimiters (so search can be skipped), true otherwise
*/
protected hasPatterns: boolean;
/**
* @override
*/
constructor(options: OptionList) {
super(options);
this.getPatterns();
}
/**
* Create the patterns needed for searching the strings for AsciiMath
* based on the configuration options
*/
protected getPatterns() {
let options = this.options;
let starts: string[] = [];
this.end = {};
options['delimiters'].forEach((delims: Delims) => this.addPattern(starts, delims, false));
this.start = new RegExp(starts.join('|'), 'g');
this.hasPatterns = (starts.length > 0);
}
/**
* Add the needed patterns for a pair of delimiters
*
* @param {string[]} starts Array of starting delimiter strings
* @param {Delims} delims Array of delimiter strings, as [start, end]
* @param {boolean} display True if the delimiters are for display mode
*/
protected addPattern(starts: string[], delims: Delims, display: boolean) {
let [open, close] = delims;
starts.push(quotePattern(open));
this.end[open] = [close, display, new RegExp(quotePattern(close), 'g')];
}
/**
* Search for the end delimiter given the start delimiter.
*
* @param {string} text The string being searched for the end delimiter
* @param {number} n The index of the string being searched
* @param {RegExpExecArray} start The result array from the start-delimiter search
* @param {EndItem} end The end-delimiter data corresponding to the start delimiter
* @return {ProtoItem} The proto math item for the math, if found
*/
protected findEnd(text: string, n: number, start: RegExpExecArray, end: EndItem): ProtoItem<N, T> {
let [ , display, pattern] = end;
let i = pattern.lastIndex = start.index + start[0].length;
let match = pattern.exec(text);
return (!match ? null : protoItem<N, T>(start[0], text.substr(i, match.index - i), match[0],
n, start.index, match.index + match[0].length, display));
}
/**
* Search a string for math delimited by one of the delimiter pairs.
*
* @param {ProtoItem[]} math The array of proto math items located so far
* @param {number} n The index of the string being searched
* @param {string} text The string being searched
*/
protected findMathInString(math: ProtoItem<N, T>[], n: number, text: string) {
let start, match;
this.start.lastIndex = 0;
while ((start = this.start.exec(text))) {
match = this.findEnd(text, n, start, this.end[start[0]]);
if (match) {
math.push(match);
this.start.lastIndex = match.end.n;
}
}
}
/**
* Search for math in an array of strings and return an array of matches.
*
* @override
*/
public findMath(strings: string[]) {
let math: ProtoItem<N, T>[] = [];
if (this.hasPatterns) {
for (let i = 0, m = strings.length; i < m; i++) {
this.findMathInString(math, i, strings[i]);
}
}
return math;
}
}

View File

@@ -0,0 +1 @@
export var LegacyAsciiMath: any;

View File

@@ -0,0 +1,39 @@
MathJax = Object.assign(global.MathJax || {}, require("../legacy/MathJax.js").MathJax);
//
// Load component-based configuration, if any
//
if (MathJax.config && MathJax.config.asciimath) {
MathJax.Hub.Config({AsciiMath: MathJax.config.asciimath});
}
MathJax.Ajax.Preloading(
"[MathJax]/jax/input/AsciiMath/config.js",
"[MathJax]/jax/input/AsciiMath/jax.js",
"[MathJax]/jax/element/mml/jax.js"
);
require("../legacy/jax/element/mml/jax.js");
require("../legacy/jax/input/AsciiMath/config.js");
require("../legacy/jax/input/AsciiMath/jax.js");
require("../legacy/jax/element/MmlNode.js");
var MmlFactory = require("../../../../core/MmlTree/MmlFactory.js").MmlFactory;
var factory = new MmlFactory();
exports.LegacyAsciiMath = {
Compile: function (am,display) {
var script = {
type: "math/asciimath",
innerText: am,
MathJax: {}
};
var node = MathJax.InputJax.AsciiMath.Translate(script).root.toMmlNode(factory);
node.setInheritedAttributes({}, display, 0, false);
return node;
},
Translate: function (am,display) {
return this.Compile(am,display);
}
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,103 @@
(function () {
var MML = MathJax.ElementJax.mml;
MML.mbase.Augment({
toJSON: function () {
var m = this.data.length;
var json = {type: this.type};
if (this.inferred) json.inferred = true;
if (this.isToken) {
json.text = this.data.join("");
} else {
json.children = new Array(m);
for (var i = 0; i < m; i++) {
var child = this.data[i];
if (child) json.children[i] = child.toJSON();
}
}
this.jsonAddAttributes(json);
return json;
},
jsonAddAttributes: function (json) {
var defaults = (this.type === "mstyle" ? MML.math.prototype.defaults : this.defaults);
var names = (this.attrNames||MML.copyAttributeNames),
skip = MML.skipAttributes,
copy = MML.copyAttributes;
var attr = {};
if (!this.attrNames) {
for (var id in defaults) {
if (!skip[id] && !copy[id] && defaults.hasOwnProperty(id)) {
if (this[id] != null && this[id] !== defaults[id]) {
if (this.Get(id,null,1) !== this[id]) attr[id] = this[id];
}
}
}
}
for (var i = 0, m = names.length; i < m; i++) {
if (copy[names[i]] === 1 && !defaults.hasOwnProperty(names[i])) continue;
value = (this.attr||{})[names[i]];
if (value == null) value = this[names[i]];
if (value != null) attr[names[i]] = value;
}
json.attributes = attr;
}
});
MML.chars.Augment({
toJSON: function () {
return this.data.join("");
}
});
MML.entity.Augment({
toJSON: function () {
return this.data.join("");
}
});
MML.msubsup.Augment({
toJSON: function () {
var json = this.SUPER(arguments).toJSON.call(this);
if (this.data[this.sub] == null) {
json.type = "msup";
json.children.splice(1,1);
}
if (this.data[this.sup] == null) {
json.type = "msub";
json.children.splice(2,1);
}
return json;
}
});
MML.munderover.Augment({
toJSON: function () {
var json = this.SUPER(arguments).toJSON.call(this);
if (this.data[this.munder] == null) {
json.type = "mover";
json.children.splice(1,1);
}
if (this.data[this.mover] == null) {
json.type = "munder";
json.children.splice(2,1);
}
return json;
}
});
MML.TeXAtom.Augment({
toJSON: function () {
var json = this.SUPER(arguments).toJSON.call(this);
json.type = "mrow";
json.TeXAtom = MML.TEXCLASSNAMES[this.Get("texClass")];
return json;
}
});
MML.xml.Augment({
toJSON: function () {
return {type:"xml", data: this.toString()};
}
});
})();

View File

@@ -0,0 +1,109 @@
(function () {
var MML = MathJax.ElementJax.mml;
var PROPERTY = [
'texWithDelims',
'movesupsub',
'subsupOK',
'primes',
'movablelimits',
'scriptlevel',
'open',
'close',
'isError',
'multiline',
'variantForm',
'autoOP',
'fnOP'
];
var RENAME = {
texWithDelims: 'withDelims'
};
MML.mbase.Augment({
toMmlNode: function (factory) {
var kind = this.type;
if (kind === 'texatom') kind = 'TeXAtom';
var node = this.nodeMake(factory, kind);
if ("texClass" in this) node.texClass = this.texClass;
return node;
},
nodeMake: function (factory,kind) {
var node = factory.MML[kind === 'TeXmathchoice' ? 'mathchoice' : kind]();
var data = (this.data[0] && this.data[0].inferred && this.inferRow ? this.data[0].data : this.data);
for (var i = 0, m = data.length; i < m; i++) {
var child = data[i];
if (child) node.appendChild(child.toMmlNode(factory));
}
this.nodeAddAttributes(node);
this.nodeAddProperties(node);
return node;
},
nodeAddAttributes: function (node) {
var defaults = (this.type === "mstyle" ? MML.math.prototype.defaults : this.defaults);
var names = (this.attrNames||MML.copyAttributeNames),
skip = MML.skipAttributes,
copy = MML.copyAttributes;
if (!this.attrNames) {
for (var id in defaults) {
if (!skip[id] && !copy[id] && defaults.hasOwnProperty(id)) {
if (this[id] != null && this[id] !== defaults[id]) {
if (this.Get(id,null,1) !== this[id]) node.attributes.set(id,this[id]);
}
}
}
if (this['class']) node.attributes.set('class',this['class']);
}
for (var i = 0, m = names.length; i < m; i++) {
if (copy[names[i]] === 1 && !defaults.hasOwnProperty(names[i])) continue;
var value = (this.attr||{})[names[i]];
if (value == null) value = this[names[i]];
if (value === 'true' || value === 'false') value = (value === 'true');
if (value != null) node.attributes.set(names[i],value);
}
},
nodeAddProperties: function (node) {
for (var i = 0, m = PROPERTY.length; i < m; i++) {
var name = PROPERTY[i];
if (this[name] != null &&
(this.defaults[name] == null || this.defaults[name] === MML.AUTO)) {
node.setProperty(RENAME[name] || name, this[name]);
}
}
}
});
MML.chars.Augment({
toMmlNode: function (factory) {
return factory.MML.text().setText(this.data.join(""));
}
});
MML.entity.Augment({
toMmlNode: function (factory) {
return factory.MML.text().setText(this.toString());
}
});
MML.msubsup.Augment({
toMmlNode: function (factory) {
var kind = (this.data[this.sub] == null ? 'msup' :
this.data[this.sup] == null ? 'msub' : 'msubsup');
return this.nodeMake(factory, kind);
}
});
MML.munderover.Augment({
toMmlNode: function (factory) {
var kind = (this.data[this.under] == null ? 'mover' :
this.data[this.over] == null ? 'munder' : 'munderover');
return this.nodeMake(factory, kind);
}
});
MML.xml.Augment({
toMmlNode: function (factory) {
return factory.MML.xml(this.data);
}
});
})();

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,122 @@
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/Arrows.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
infix: {
'\u219A': MO.RELACCENT, // leftwards arrow with stroke
'\u219B': MO.RELACCENT, // rightwards arrow with stroke
'\u219C': MO.WIDEREL, // leftwards wave arrow
'\u219D': MO.WIDEREL, // rightwards wave arrow
'\u219E': MO.WIDEREL, // leftwards two headed arrow
'\u219F': MO.WIDEREL, // upwards two headed arrow
'\u21A0': MO.WIDEREL, // rightwards two headed arrow
'\u21A1': MO.RELSTRETCH, // downwards two headed arrow
'\u21A2': MO.WIDEREL, // leftwards arrow with tail
'\u21A3': MO.WIDEREL, // rightwards arrow with tail
'\u21A4': MO.WIDEREL, // leftwards arrow from bar
'\u21A5': MO.RELSTRETCH, // upwards arrow from bar
'\u21A7': MO.RELSTRETCH, // downwards arrow from bar
'\u21A8': MO.RELSTRETCH, // up down arrow with base
'\u21AB': MO.WIDEREL, // leftwards arrow with loop
'\u21AC': MO.WIDEREL, // rightwards arrow with loop
'\u21AD': MO.WIDEREL, // left right wave arrow
'\u21AE': MO.RELACCENT, // left right arrow with stroke
'\u21AF': MO.RELSTRETCH, // downwards zigzag arrow
'\u21B0': MO.RELSTRETCH, // upwards arrow with tip leftwards
'\u21B1': MO.RELSTRETCH, // upwards arrow with tip rightwards
'\u21B2': MO.RELSTRETCH, // downwards arrow with tip leftwards
'\u21B3': MO.RELSTRETCH, // downwards arrow with tip rightwards
'\u21B4': MO.RELSTRETCH, // rightwards arrow with corner downwards
'\u21B5': MO.RELSTRETCH, // downwards arrow with corner leftwards
'\u21B6': MO.RELACCENT, // anticlockwise top semicircle arrow
'\u21B7': MO.RELACCENT, // clockwise top semicircle arrow
'\u21B8': MO.REL, // north west arrow to long bar
'\u21B9': MO.WIDEREL, // leftwards arrow to bar over rightwards arrow to bar
'\u21BA': MO.REL, // anticlockwise open circle arrow
'\u21BB': MO.REL, // clockwise open circle arrow
'\u21BE': MO.RELSTRETCH, // upwards harpoon with barb rightwards
'\u21BF': MO.RELSTRETCH, // upwards harpoon with barb leftwards
'\u21C2': MO.RELSTRETCH, // downwards harpoon with barb rightwards
'\u21C3': MO.RELSTRETCH, // downwards harpoon with barb leftwards
'\u21C4': MO.WIDEREL, // rightwards arrow over leftwards arrow
'\u21C5': MO.RELSTRETCH, // upwards arrow leftwards of downwards arrow
'\u21C6': MO.WIDEREL, // leftwards arrow over rightwards arrow
'\u21C7': MO.WIDEREL, // leftwards paired arrows
'\u21C8': MO.RELSTRETCH, // upwards paired arrows
'\u21C9': MO.WIDEREL, // rightwards paired arrows
'\u21CA': MO.RELSTRETCH, // downwards paired arrows
'\u21CB': MO.WIDEREL, // leftwards harpoon over rightwards harpoon
'\u21CD': MO.RELACCENT, // leftwards double arrow with stroke
'\u21CE': MO.RELACCENT, // left right double arrow with stroke
'\u21CF': MO.RELACCENT, // rightwards double arrow with stroke
'\u21D6': MO.RELSTRETCH, // north west double arrow
'\u21D7': MO.RELSTRETCH, // north east double arrow
'\u21D8': MO.RELSTRETCH, // south east double arrow
'\u21D9': MO.RELSTRETCH, // south west double arrow
'\u21DA': MO.WIDEREL, // leftwards triple arrow
'\u21DB': MO.WIDEREL, // rightwards triple arrow
'\u21DC': MO.WIDEREL, // leftwards squiggle arrow
'\u21DD': MO.WIDEREL, // rightwards squiggle arrow
'\u21DE': MO.REL, // upwards arrow with double stroke
'\u21DF': MO.REL, // downwards arrow with double stroke
'\u21E0': MO.WIDEREL, // leftwards dashed arrow
'\u21E1': MO.RELSTRETCH, // upwards dashed arrow
'\u21E2': MO.WIDEREL, // rightwards dashed arrow
'\u21E3': MO.RELSTRETCH, // downwards dashed arrow
'\u21E4': MO.WIDEREL, // leftwards arrow to bar
'\u21E5': MO.WIDEREL, // rightwards arrow to bar
'\u21E6': MO.WIDEREL, // leftwards white arrow
'\u21E7': MO.RELSTRETCH, // upwards white arrow
'\u21E8': MO.WIDEREL, // rightwards white arrow
'\u21E9': MO.RELSTRETCH, // downwards white arrow
'\u21EA': MO.RELSTRETCH, // upwards white arrow from bar
'\u21EB': MO.RELSTRETCH, // upwards white arrow on pedestal
'\u21EC': MO.RELSTRETCH, // upwards white arrow on pedestal with horizontal bar
'\u21ED': MO.RELSTRETCH, // upwards white arrow on pedestal with vertical bar
'\u21EE': MO.RELSTRETCH, // upwards white double arrow
'\u21EF': MO.RELSTRETCH, // upwards white double arrow on pedestal
'\u21F0': MO.WIDEREL, // rightwards white arrow from wall
'\u21F1': MO.REL, // north west arrow to corner
'\u21F2': MO.REL, // south east arrow to corner
'\u21F3': MO.RELSTRETCH, // up down white arrow
'\u21F4': MO.RELACCENT, // right arrow with small circle
'\u21F5': MO.RELSTRETCH, // downwards arrow leftwards of upwards arrow
'\u21F6': MO.WIDEREL, // three rightwards arrows
'\u21F7': MO.RELACCENT, // leftwards arrow with vertical stroke
'\u21F8': MO.RELACCENT, // rightwards arrow with vertical stroke
'\u21F9': MO.RELACCENT, // left right arrow with vertical stroke
'\u21FA': MO.RELACCENT, // leftwards arrow with double vertical stroke
'\u21FB': MO.RELACCENT, // rightwards arrow with double vertical stroke
'\u21FC': MO.RELACCENT, // left right arrow with double vertical stroke
'\u21FD': MO.WIDEREL, // leftwards open-headed arrow
'\u21FE': MO.WIDEREL, // rightwards open-headed arrow
'\u21FF': MO.WIDEREL // left right open-headed arrow
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/Arrows.js");
})(MathJax.ElementJax.mml);

View File

@@ -0,0 +1,65 @@
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/BasicLatin.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
prefix: {
'||': [0,0,TEXCLASS.BIN,{fence: true, stretchy: true, symmetric: true}], // multiple character operator: ||
'|||': [0,0,TEXCLASS.ORD,{fence: true, stretchy: true, symmetric: true}] // multiple character operator: |||
},
postfix: {
'!!': [1,0,TEXCLASS.BIN], // multiple character operator: !!
'\'': MO.ACCENT, // apostrophe
'++': [0,0,TEXCLASS.BIN], // multiple character operator: ++
'--': [0,0,TEXCLASS.BIN], // multiple character operator: --
'..': [0,0,TEXCLASS.BIN], // multiple character operator: ..
'...': MO.ORD, // multiple character operator: ...
'||': [0,0,TEXCLASS.BIN,{fence: true, stretchy: true, symmetric: true}], // multiple character operator: ||
'|||': [0,0,TEXCLASS.ORD,{fence: true, stretchy: true, symmetric: true}] // multiple character operator: |||
},
infix: {
'!=': MO.BIN4, // multiple character operator: !=
'&&': MO.BIN4, // multiple character operator: &&
'**': [1,1,TEXCLASS.BIN], // multiple character operator: **
'*=': MO.BIN4, // multiple character operator: *=
'+=': MO.BIN4, // multiple character operator: +=
'-=': MO.BIN4, // multiple character operator: -=
'->': MO.BIN5, // multiple character operator: ->
'//': [1,1,TEXCLASS.BIN], // multiple character operator: //
'/=': MO.BIN4, // multiple character operator: /=
':=': MO.BIN4, // multiple character operator: :=
'<=': MO.BIN5, // multiple character operator: <=
'<>': [1,1,TEXCLASS.BIN], // multiple character operator: <>
'==': MO.BIN4, // multiple character operator: ==
'>=': MO.BIN5, // multiple character operator: >=
'@': MO.ORD11, // commercial at
'||': [2,2,TEXCLASS.BIN,{fence: true, stretchy: true, symmetric: true}], // multiple character operator: ||
'|||': [2,2,TEXCLASS.ORD,{fence: true, stretchy: true, symmetric: true}] // multiple character operator: |||
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/BasicLatin.js");
})(MathJax.ElementJax.mml);

View File

@@ -0,0 +1,35 @@
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/CombDiacritMarks.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
postfix: {
'\u0311': MO.ACCENT // combining inverted breve
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/CombDiacritMarks.js");
})(MathJax.ElementJax.mml);

View File

@@ -0,0 +1,36 @@
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/CombDiactForSymbols.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
postfix: {
'\u20DB': MO.ACCENT, // combining three dots above
'\u20DC': MO.ACCENT // combining four dots above
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/CombDiactForSymbols.js");
})(MathJax.ElementJax.mml);

View File

@@ -0,0 +1,38 @@
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/Dingbats.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
prefix: {
'\u2772': MO.OPEN // light left tortoise shell bracket ornament
},
postfix: {
'\u2773': MO.CLOSE // light right tortoise shell bracket ornament
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/Dingbats.js");
})(MathJax.ElementJax.mml);

View File

@@ -0,0 +1,42 @@
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/GeneralPunctuation.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
prefix: {
'\u2016': [0,0,TEXCLASS.ORD,{fence: true, stretchy: true}], // double vertical line
'\u2018': [0,0,TEXCLASS.OPEN,{fence: true}], // left single quotation mark
'\u201C': [0,0,TEXCLASS.OPEN,{fence: true}] // left double quotation mark
},
postfix: {
'\u2016': [0,0,TEXCLASS.ORD,{fence: true, stretchy: true}], // double vertical line
'\u2019': [0,0,TEXCLASS.CLOSE,{fence: true}], // right single quotation mark
'\u201D': [0,0,TEXCLASS.CLOSE,{fence: true}] // right double quotation mark
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/GeneralPunctuation.js");
})(MathJax.ElementJax.mml);

View File

@@ -0,0 +1,66 @@
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/GeometricShapes.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
infix: {
'\u25A0': MO.BIN3, // black square
'\u25A1': MO.BIN3, // white square
'\u25AA': MO.BIN3, // black small square
'\u25AB': MO.BIN3, // white small square
'\u25AD': MO.BIN3, // white rectangle
'\u25AE': MO.BIN3, // black vertical rectangle
'\u25AF': MO.BIN3, // white vertical rectangle
'\u25B0': MO.BIN3, // black parallelogram
'\u25B1': MO.BIN3, // white parallelogram
'\u25B2': MO.BIN4, // black up-pointing triangle
'\u25B4': MO.BIN4, // black up-pointing small triangle
'\u25B6': MO.BIN4, // black right-pointing triangle
'\u25B7': MO.BIN4, // white right-pointing triangle
'\u25B8': MO.BIN4, // black right-pointing small triangle
'\u25BC': MO.BIN4, // black down-pointing triangle
'\u25BE': MO.BIN4, // black down-pointing small triangle
'\u25C0': MO.BIN4, // black left-pointing triangle
'\u25C1': MO.BIN4, // white left-pointing triangle
'\u25C2': MO.BIN4, // black left-pointing small triangle
'\u25C4': MO.BIN4, // black left-pointing pointer
'\u25C5': MO.BIN4, // white left-pointing pointer
'\u25C6': MO.BIN4, // black diamond
'\u25C7': MO.BIN4, // white diamond
'\u25C8': MO.BIN4, // white diamond containing black small diamond
'\u25C9': MO.BIN4, // fisheye
'\u25CC': MO.BIN4, // dotted circle
'\u25CD': MO.BIN4, // circle with vertical fill
'\u25CE': MO.BIN4, // bullseye
'\u25CF': MO.BIN4, // black circle
'\u25D6': MO.BIN4, // left half black circle
'\u25D7': MO.BIN4, // right half black circle
'\u25E6': MO.BIN4 // white bullet
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/GeometricShapes.js");
})(MathJax.ElementJax.mml);

View File

@@ -0,0 +1,35 @@
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/GreekAndCoptic.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
infix: {
'\u03F6': MO.REL // greek reversed lunate epsilon symbol
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/GreekAndCoptic.js");
})(MathJax.ElementJax.mml);

View File

@@ -0,0 +1,37 @@
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/Latin1Supplement.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
postfix: {
'\u00B0': MO.ORD, // degree sign
'\u00B4': MO.ACCENT, // acute accent
'\u00B8': MO.ACCENT // cedilla
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/Latin1Supplement.js");
})(MathJax.ElementJax.mml);

View File

@@ -0,0 +1,36 @@
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/LetterlikeSymbols.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
prefix: {
'\u2145': MO.ORD21, // double-struck italic capital d
'\u2146': [2,0,TEXCLASS.ORD] // double-struck italic small d
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/LetterlikeSymbols.js");
})(MathJax.ElementJax.mml);

View File

@@ -0,0 +1,228 @@
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/MathOperators.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
prefix: {
'\u2204': MO.ORD21, // there does not exist
'\u221B': MO.ORD11, // cube root
'\u221C': MO.ORD11, // fourth root
'\u2221': MO.ORD, // measured angle
'\u2222': MO.ORD, // spherical angle
'\u222C': MO.INTEGRAL, // double integral
'\u222D': MO.INTEGRAL, // triple integral
'\u222F': MO.INTEGRAL, // surface integral
'\u2230': MO.INTEGRAL, // volume integral
'\u2231': MO.INTEGRAL, // clockwise integral
'\u2232': MO.INTEGRAL, // clockwise contour integral
'\u2233': MO.INTEGRAL // anticlockwise contour integral
},
infix: {
'\u2201': [1,2,TEXCLASS.ORD], // complement
'\u2206': MO.BIN3, // increment
'\u220A': MO.REL, // small element of
'\u220C': MO.REL, // does not contain as member
'\u220D': MO.REL, // small contains as member
'\u220E': MO.BIN3, // end of proof
'\u2214': MO.BIN4, // dot plus
'\u221F': MO.REL, // right angle
'\u2224': MO.REL, // does not divide
'\u2226': MO.REL, // not parallel to
'\u2234': MO.REL, // therefore
'\u2235': MO.REL, // because
'\u2236': MO.REL, // ratio
'\u2237': MO.REL, // proportion
'\u2238': MO.BIN4, // dot minus
'\u2239': MO.REL, // excess
'\u223A': MO.BIN4, // geometric proportion
'\u223B': MO.REL, // homothetic
'\u223D': MO.REL, // reversed tilde
'\u223D\u0331': MO.BIN3, // reversed tilde with underline
'\u223E': MO.REL, // inverted lazy s
'\u223F': MO.BIN3, // sine wave
'\u2241': MO.REL, // not tilde
'\u2242': MO.REL, // minus tilde
'\u2242\u0338': MO.REL, // minus tilde with slash
'\u2244': MO.REL, // not asymptotically equal to
'\u2246': MO.REL, // approximately but not actually equal to
'\u2247': MO.REL, // neither approximately nor actually equal to
'\u2249': MO.REL, // not almost equal to
'\u224A': MO.REL, // almost equal or equal to
'\u224B': MO.REL, // triple tilde
'\u224C': MO.REL, // all equal to
'\u224E': MO.REL, // geometrically equivalent to
'\u224E\u0338': MO.REL, // geometrically equivalent to with slash
'\u224F': MO.REL, // difference between
'\u224F\u0338': MO.REL, // difference between with slash
'\u2251': MO.REL, // geometrically equal to
'\u2252': MO.REL, // approximately equal to or the image of
'\u2253': MO.REL, // image of or approximately equal to
'\u2254': MO.REL, // colon equals
'\u2255': MO.REL, // equals colon
'\u2256': MO.REL, // ring in equal to
'\u2257': MO.REL, // ring equal to
'\u2258': MO.REL, // corresponds to
'\u2259': MO.REL, // estimates
'\u225A': MO.REL, // equiangular to
'\u225C': MO.REL, // delta equal to
'\u225D': MO.REL, // equal to by definition
'\u225E': MO.REL, // measured by
'\u225F': MO.REL, // questioned equal to
'\u2262': MO.REL, // not identical to
'\u2263': MO.REL, // strictly equivalent to
'\u2266': MO.REL, // less-than over equal to
'\u2266\u0338': MO.REL, // less-than over equal to with slash
'\u2267': MO.REL, // greater-than over equal to
'\u2268': MO.REL, // less-than but not equal to
'\u2269': MO.REL, // greater-than but not equal to
'\u226A\u0338': MO.REL, // much less than with slash
'\u226B\u0338': MO.REL, // much greater than with slash
'\u226C': MO.REL, // between
'\u226D': MO.REL, // not equivalent to
'\u226E': MO.REL, // not less-than
'\u226F': MO.REL, // not greater-than
'\u2270': MO.REL, // neither less-than nor equal to
'\u2271': MO.REL, // neither greater-than nor equal to
'\u2272': MO.REL, // less-than or equivalent to
'\u2273': MO.REL, // greater-than or equivalent to
'\u2274': MO.REL, // neither less-than nor equivalent to
'\u2275': MO.REL, // neither greater-than nor equivalent to
'\u2276': MO.REL, // less-than or greater-than
'\u2277': MO.REL, // greater-than or less-than
'\u2278': MO.REL, // neither less-than nor greater-than
'\u2279': MO.REL, // neither greater-than nor less-than
'\u227C': MO.REL, // precedes or equal to
'\u227D': MO.REL, // succeeds or equal to
'\u227E': MO.REL, // precedes or equivalent to
'\u227F': MO.REL, // succeeds or equivalent to
'\u227F\u0338': MO.REL, // succeeds or equivalent to with slash
'\u2280': MO.REL, // does not precede
'\u2281': MO.REL, // does not succeed
'\u2282\u20D2': MO.REL, // subset of with vertical line
'\u2283\u20D2': MO.REL, // superset of with vertical line
'\u2284': MO.REL, // not a subset of
'\u2285': MO.REL, // not a superset of
'\u2288': MO.REL, // neither a subset of nor equal to
'\u2289': MO.REL, // neither a superset of nor equal to
'\u228A': MO.REL, // subset of with not equal to
'\u228B': MO.REL, // superset of with not equal to
'\u228C': MO.BIN4, // multiset
'\u228D': MO.BIN4, // multiset multiplication
'\u228F': MO.REL, // square image of
'\u228F\u0338': MO.REL, // square image of with slash
'\u2290': MO.REL, // square original of
'\u2290\u0338': MO.REL, // square original of with slash
'\u229A': MO.BIN4, // circled ring operator
'\u229B': MO.BIN4, // circled asterisk operator
'\u229C': MO.BIN4, // circled equals
'\u229D': MO.BIN4, // circled dash
'\u229E': MO.BIN4, // squared plus
'\u229F': MO.BIN4, // squared minus
'\u22A0': MO.BIN4, // squared times
'\u22A1': MO.BIN4, // squared dot operator
'\u22A6': MO.REL, // assertion
'\u22A7': MO.REL, // models
'\u22A9': MO.REL, // forces
'\u22AA': MO.REL, // triple vertical bar right turnstile
'\u22AB': MO.REL, // double vertical bar double right turnstile
'\u22AC': MO.REL, // does not prove
'\u22AD': MO.REL, // not true
'\u22AE': MO.REL, // does not force
'\u22AF': MO.REL, // negated double vertical bar double right turnstile
'\u22B0': MO.REL, // precedes under relation
'\u22B1': MO.REL, // succeeds under relation
'\u22B2': MO.REL, // normal subgroup of
'\u22B3': MO.REL, // contains as normal subgroup
'\u22B4': MO.REL, // normal subgroup of or equal to
'\u22B5': MO.REL, // contains as normal subgroup or equal to
'\u22B6': MO.REL, // original of
'\u22B7': MO.REL, // image of
'\u22B8': MO.REL, // multimap
'\u22B9': MO.REL, // hermitian conjugate matrix
'\u22BA': MO.BIN4, // intercalate
'\u22BB': MO.BIN4, // xor
'\u22BC': MO.BIN4, // nand
'\u22BD': MO.BIN4, // nor
'\u22BE': MO.BIN3, // right angle with arc
'\u22BF': MO.BIN3, // right triangle
'\u22C7': MO.BIN4, // division times
'\u22C9': MO.BIN4, // left normal factor semidirect product
'\u22CA': MO.BIN4, // right normal factor semidirect product
'\u22CB': MO.BIN4, // left semidirect product
'\u22CC': MO.BIN4, // right semidirect product
'\u22CD': MO.REL, // reversed tilde equals
'\u22CE': MO.BIN4, // curly logical or
'\u22CF': MO.BIN4, // curly logical and
'\u22D0': MO.REL, // double subset
'\u22D1': MO.REL, // double superset
'\u22D2': MO.BIN4, // double intersection
'\u22D3': MO.BIN4, // double union
'\u22D4': MO.REL, // pitchfork
'\u22D5': MO.REL, // equal and parallel to
'\u22D6': MO.REL, // less-than with dot
'\u22D7': MO.REL, // greater-than with dot
'\u22D8': MO.REL, // very much less-than
'\u22D9': MO.REL, // very much greater-than
'\u22DA': MO.REL, // less-than equal to or greater-than
'\u22DB': MO.REL, // greater-than equal to or less-than
'\u22DC': MO.REL, // equal to or less-than
'\u22DD': MO.REL, // equal to or greater-than
'\u22DE': MO.REL, // equal to or precedes
'\u22DF': MO.REL, // equal to or succeeds
'\u22E0': MO.REL, // does not precede or equal
'\u22E1': MO.REL, // does not succeed or equal
'\u22E2': MO.REL, // not square image of or equal to
'\u22E3': MO.REL, // not square original of or equal to
'\u22E4': MO.REL, // square image of or not equal to
'\u22E5': MO.REL, // square original of or not equal to
'\u22E6': MO.REL, // less-than but not equivalent to
'\u22E7': MO.REL, // greater-than but not equivalent to
'\u22E8': MO.REL, // precedes but not equivalent to
'\u22E9': MO.REL, // succeeds but not equivalent to
'\u22EA': MO.REL, // not normal subgroup of
'\u22EB': MO.REL, // does not contain as normal subgroup
'\u22EC': MO.REL, // not normal subgroup of or equal to
'\u22ED': MO.REL, // does not contain as normal subgroup or equal
'\u22F0': MO.REL, // up right diagonal ellipsis
'\u22F2': MO.REL, // element of with long horizontal stroke
'\u22F3': MO.REL, // element of with vertical bar at end of horizontal stroke
'\u22F4': MO.REL, // small element of with vertical bar at end of horizontal stroke
'\u22F5': MO.REL, // element of with dot above
'\u22F6': MO.REL, // element of with overbar
'\u22F7': MO.REL, // small element of with overbar
'\u22F8': MO.REL, // element of with underbar
'\u22F9': MO.REL, // element of with two horizontal strokes
'\u22FA': MO.REL, // contains with long horizontal stroke
'\u22FB': MO.REL, // contains with vertical bar at end of horizontal stroke
'\u22FC': MO.REL, // small contains with vertical bar at end of horizontal stroke
'\u22FD': MO.REL, // contains with overbar
'\u22FE': MO.REL, // small contains with overbar
'\u22FF': MO.REL // z notation bag membership
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/MathOperators.js");
})(MathJax.ElementJax.mml);

View File

@@ -0,0 +1,42 @@
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/MiscMathSymbolsA.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
prefix: {
'\u27E6': MO.OPEN, // mathematical left white square bracket
'\u27EA': MO.OPEN, // mathematical left double angle bracket
'\u27EC': MO.OPEN // mathematical left white tortoise shell bracket
},
postfix: {
'\u27E7': MO.CLOSE, // mathematical right white square bracket
'\u27EB': MO.CLOSE, // mathematical right double angle bracket
'\u27ED': MO.CLOSE // mathematical right white tortoise shell bracket
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/MiscMathSymbolsA.js");
})(MathJax.ElementJax.mml);

View File

@@ -0,0 +1,168 @@
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/MiscMathSymbolsB.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
prefix: {
'\u2980': [0,0,TEXCLASS.ORD,{fence: true, stretchy: true}], // triple vertical bar delimiter
'\u2983': MO.OPEN, // left white curly bracket
'\u2985': MO.OPEN, // left white parenthesis
'\u2987': MO.OPEN, // z notation left image bracket
'\u2989': MO.OPEN, // z notation left binding bracket
'\u298B': MO.OPEN, // left square bracket with underbar
'\u298D': MO.OPEN, // left square bracket with tick in top corner
'\u298F': MO.OPEN, // left square bracket with tick in bottom corner
'\u2991': MO.OPEN, // left angle bracket with dot
'\u2993': MO.OPEN, // left arc less-than bracket
'\u2995': MO.OPEN, // double left arc greater-than bracket
'\u2997': MO.OPEN, // left black tortoise shell bracket
'\u29FC': MO.OPEN // left-pointing curved angle bracket
},
postfix: {
'\u2980': [0,0,TEXCLASS.ORD,{fence: true, stretchy: true}], // triple vertical bar delimiter
'\u2984': MO.CLOSE, // right white curly bracket
'\u2986': MO.CLOSE, // right white parenthesis
'\u2988': MO.CLOSE, // z notation right image bracket
'\u298A': MO.CLOSE, // z notation right binding bracket
'\u298C': MO.CLOSE, // right square bracket with underbar
'\u298E': MO.CLOSE, // right square bracket with tick in bottom corner
'\u2990': MO.CLOSE, // right square bracket with tick in top corner
'\u2992': MO.CLOSE, // right angle bracket with dot
'\u2994': MO.CLOSE, // right arc greater-than bracket
'\u2996': MO.CLOSE, // double right arc less-than bracket
'\u2998': MO.CLOSE, // right black tortoise shell bracket
'\u29FD': MO.CLOSE // right-pointing curved angle bracket
},
infix: {
'\u2981': MO.BIN3, // z notation spot
'\u2982': MO.BIN3, // z notation type colon
'\u2999': MO.BIN3, // dotted fence
'\u299A': MO.BIN3, // vertical zigzag line
'\u299B': MO.BIN3, // measured angle opening left
'\u299C': MO.BIN3, // right angle variant with square
'\u299D': MO.BIN3, // measured right angle with dot
'\u299E': MO.BIN3, // angle with s inside
'\u299F': MO.BIN3, // acute angle
'\u29A0': MO.BIN3, // spherical angle opening left
'\u29A1': MO.BIN3, // spherical angle opening up
'\u29A2': MO.BIN3, // turned angle
'\u29A3': MO.BIN3, // reversed angle
'\u29A4': MO.BIN3, // angle with underbar
'\u29A5': MO.BIN3, // reversed angle with underbar
'\u29A6': MO.BIN3, // oblique angle opening up
'\u29A7': MO.BIN3, // oblique angle opening down
'\u29A8': MO.BIN3, // measured angle with open arm ending in arrow pointing up and right
'\u29A9': MO.BIN3, // measured angle with open arm ending in arrow pointing up and left
'\u29AA': MO.BIN3, // measured angle with open arm ending in arrow pointing down and right
'\u29AB': MO.BIN3, // measured angle with open arm ending in arrow pointing down and left
'\u29AC': MO.BIN3, // measured angle with open arm ending in arrow pointing right and up
'\u29AD': MO.BIN3, // measured angle with open arm ending in arrow pointing left and up
'\u29AE': MO.BIN3, // measured angle with open arm ending in arrow pointing right and down
'\u29AF': MO.BIN3, // measured angle with open arm ending in arrow pointing left and down
'\u29B0': MO.BIN3, // reversed empty set
'\u29B1': MO.BIN3, // empty set with overbar
'\u29B2': MO.BIN3, // empty set with small circle above
'\u29B3': MO.BIN3, // empty set with right arrow above
'\u29B4': MO.BIN3, // empty set with left arrow above
'\u29B5': MO.BIN3, // circle with horizontal bar
'\u29B6': MO.BIN4, // circled vertical bar
'\u29B7': MO.BIN4, // circled parallel
'\u29B8': MO.BIN4, // circled reverse solidus
'\u29B9': MO.BIN4, // circled perpendicular
'\u29BA': MO.BIN4, // circle divided by horizontal bar and top half divided by vertical bar
'\u29BB': MO.BIN4, // circle with superimposed x
'\u29BC': MO.BIN4, // circled anticlockwise-rotated division sign
'\u29BD': MO.BIN4, // up arrow through circle
'\u29BE': MO.BIN4, // circled white bullet
'\u29BF': MO.BIN4, // circled bullet
'\u29C0': MO.REL, // circled less-than
'\u29C1': MO.REL, // circled greater-than
'\u29C2': MO.BIN3, // circle with small circle to the right
'\u29C3': MO.BIN3, // circle with two horizontal strokes to the right
'\u29C4': MO.BIN4, // squared rising diagonal slash
'\u29C5': MO.BIN4, // squared falling diagonal slash
'\u29C6': MO.BIN4, // squared asterisk
'\u29C7': MO.BIN4, // squared small circle
'\u29C8': MO.BIN4, // squared square
'\u29C9': MO.BIN3, // two joined squares
'\u29CA': MO.BIN3, // triangle with dot above
'\u29CB': MO.BIN3, // triangle with underbar
'\u29CC': MO.BIN3, // s in triangle
'\u29CD': MO.BIN3, // triangle with serifs at bottom
'\u29CE': MO.REL, // right triangle above left triangle
'\u29CF': MO.REL, // left triangle beside vertical bar
'\u29CF\u0338': MO.REL, // left triangle beside vertical bar with slash
'\u29D0': MO.REL, // vertical bar beside right triangle
'\u29D0\u0338': MO.REL, // vertical bar beside right triangle with slash
'\u29D1': MO.REL, // bowtie with left half black
'\u29D2': MO.REL, // bowtie with right half black
'\u29D3': MO.REL, // black bowtie
'\u29D4': MO.REL, // times with left half black
'\u29D5': MO.REL, // times with right half black
'\u29D6': MO.BIN4, // white hourglass
'\u29D7': MO.BIN4, // black hourglass
'\u29D8': MO.BIN3, // left wiggly fence
'\u29D9': MO.BIN3, // right wiggly fence
'\u29DB': MO.BIN3, // right double wiggly fence
'\u29DC': MO.BIN3, // incomplete infinity
'\u29DD': MO.BIN3, // tie over infinity
'\u29DE': MO.REL, // infinity negated with vertical bar
'\u29DF': MO.BIN3, // double-ended multimap
'\u29E0': MO.BIN3, // square with contoured outline
'\u29E1': MO.REL, // increases as
'\u29E2': MO.BIN4, // shuffle product
'\u29E3': MO.REL, // equals sign and slanted parallel
'\u29E4': MO.REL, // equals sign and slanted parallel with tilde above
'\u29E5': MO.REL, // identical to and slanted parallel
'\u29E6': MO.REL, // gleich stark
'\u29E7': MO.BIN3, // thermodynamic
'\u29E8': MO.BIN3, // down-pointing triangle with left half black
'\u29E9': MO.BIN3, // down-pointing triangle with right half black
'\u29EA': MO.BIN3, // black diamond with down arrow
'\u29EB': MO.BIN3, // black lozenge
'\u29EC': MO.BIN3, // white circle with down arrow
'\u29ED': MO.BIN3, // black circle with down arrow
'\u29EE': MO.BIN3, // error-barred white square
'\u29EF': MO.BIN3, // error-barred black square
'\u29F0': MO.BIN3, // error-barred white diamond
'\u29F1': MO.BIN3, // error-barred black diamond
'\u29F2': MO.BIN3, // error-barred white circle
'\u29F3': MO.BIN3, // error-barred black circle
'\u29F4': MO.REL, // rule-delayed
'\u29F5': MO.BIN4, // reverse solidus operator
'\u29F6': MO.BIN4, // solidus with overbar
'\u29F7': MO.BIN4, // reverse solidus with horizontal stroke
'\u29F8': MO.BIN3, // big solidus
'\u29F9': MO.BIN3, // big reverse solidus
'\u29FA': MO.BIN3, // double plus
'\u29FB': MO.BIN3, // triple plus
'\u29FE': MO.BIN4, // tiny
'\u29FF': MO.BIN4 // miny
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/MiscMathSymbolsB.js");
})(MathJax.ElementJax.mml);

View File

@@ -0,0 +1,36 @@
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/MiscSymbolsAndArrows.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
infix: {
'\u2B45': MO.RELSTRETCH, // leftwards quadruple arrow
'\u2B46': MO.RELSTRETCH // rightwards quadruple arrow
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/MiscSymbolsAndArrows.js");
})(MathJax.ElementJax.mml);

View File

@@ -0,0 +1,40 @@
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/MiscTechnical.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
postfix: {
'\u23B4': MO.WIDEACCENT, // top square bracket
'\u23B5': MO.WIDEACCENT, // bottom square bracket
'\u23DC': MO.WIDEACCENT, // top parenthesis
'\u23DD': MO.WIDEACCENT, // bottom parenthesis
'\u23E0': MO.WIDEACCENT, // top tortoise shell bracket
'\u23E1': MO.WIDEACCENT // bottom tortoise shell bracket
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/MiscTechnical.js");
})(MathJax.ElementJax.mml);

View File

@@ -0,0 +1,38 @@
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/SpacingModLetters.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
postfix: {
'\u02CD': MO.WIDEACCENT, // modifier letter low macron
'\u02DA': MO.ACCENT, // ring above
'\u02DD': MO.ACCENT, // double acute accent
'\u02F7': MO.WIDEACCENT // modifier letter low tilde
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/SpacingModLetters.js");
})(MathJax.ElementJax.mml);

View File

@@ -0,0 +1,289 @@
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/SuppMathOperators.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
prefix: {
'\u2A03': MO.OP, // n-ary union operator with dot
'\u2A05': MO.OP, // n-ary square intersection operator
'\u2A07': MO.OP, // two logical and operator
'\u2A08': MO.OP, // two logical or operator
'\u2A09': MO.OP, // n-ary times operator
'\u2A0A': MO.OP, // modulo two sum
'\u2A0B': MO.INTEGRAL2, // summation with integral
'\u2A0C': MO.INTEGRAL, // quadruple integral operator
'\u2A0D': MO.INTEGRAL2, // finite part integral
'\u2A0E': MO.INTEGRAL2, // integral with double stroke
'\u2A0F': MO.INTEGRAL2, // integral average with slash
'\u2A10': MO.OP, // circulation function
'\u2A11': MO.OP, // anticlockwise integration
'\u2A12': MO.OP, // line integration with rectangular path around pole
'\u2A13': MO.OP, // line integration with semicircular path around pole
'\u2A14': MO.OP, // line integration not including the pole
'\u2A15': MO.INTEGRAL2, // integral around a point operator
'\u2A16': MO.INTEGRAL2, // quaternion integral operator
'\u2A17': MO.INTEGRAL2, // integral with leftwards arrow with hook
'\u2A18': MO.INTEGRAL2, // integral with times sign
'\u2A19': MO.INTEGRAL2, // integral with intersection
'\u2A1A': MO.INTEGRAL2, // integral with union
'\u2A1B': MO.INTEGRAL2, // integral with overbar
'\u2A1C': MO.INTEGRAL2, // integral with underbar
'\u2AFC': MO.OP, // large triple vertical bar operator
'\u2AFF': MO.OP // n-ary white vertical bar
},
infix: {
'\u2A1D': MO.BIN3, // join
'\u2A1E': MO.BIN3, // large left triangle operator
'\u2A1F': MO.BIN3, // z notation schema composition
'\u2A20': MO.BIN3, // z notation schema piping
'\u2A21': MO.BIN3, // z notation schema projection
'\u2A22': MO.BIN4, // plus sign with small circle above
'\u2A23': MO.BIN4, // plus sign with circumflex accent above
'\u2A24': MO.BIN4, // plus sign with tilde above
'\u2A25': MO.BIN4, // plus sign with dot below
'\u2A26': MO.BIN4, // plus sign with tilde below
'\u2A27': MO.BIN4, // plus sign with subscript two
'\u2A28': MO.BIN4, // plus sign with black triangle
'\u2A29': MO.BIN4, // minus sign with comma above
'\u2A2A': MO.BIN4, // minus sign with dot below
'\u2A2B': MO.BIN4, // minus sign with falling dots
'\u2A2C': MO.BIN4, // minus sign with rising dots
'\u2A2D': MO.BIN4, // plus sign in left half circle
'\u2A2E': MO.BIN4, // plus sign in right half circle
'\u2A30': MO.BIN4, // multiplication sign with dot above
'\u2A31': MO.BIN4, // multiplication sign with underbar
'\u2A32': MO.BIN4, // semidirect product with bottom closed
'\u2A33': MO.BIN4, // smash product
'\u2A34': MO.BIN4, // multiplication sign in left half circle
'\u2A35': MO.BIN4, // multiplication sign in right half circle
'\u2A36': MO.BIN4, // circled multiplication sign with circumflex accent
'\u2A37': MO.BIN4, // multiplication sign in double circle
'\u2A38': MO.BIN4, // circled division sign
'\u2A39': MO.BIN4, // plus sign in triangle
'\u2A3A': MO.BIN4, // minus sign in triangle
'\u2A3B': MO.BIN4, // multiplication sign in triangle
'\u2A3C': MO.BIN4, // interior product
'\u2A3D': MO.BIN4, // righthand interior product
'\u2A3E': MO.BIN4, // z notation relational composition
'\u2A40': MO.BIN4, // intersection with dot
'\u2A41': MO.BIN4, // union with minus sign
'\u2A42': MO.BIN4, // union with overbar
'\u2A43': MO.BIN4, // intersection with overbar
'\u2A44': MO.BIN4, // intersection with logical and
'\u2A45': MO.BIN4, // union with logical or
'\u2A46': MO.BIN4, // union above intersection
'\u2A47': MO.BIN4, // intersection above union
'\u2A48': MO.BIN4, // union above bar above intersection
'\u2A49': MO.BIN4, // intersection above bar above union
'\u2A4A': MO.BIN4, // union beside and joined with union
'\u2A4B': MO.BIN4, // intersection beside and joined with intersection
'\u2A4C': MO.BIN4, // closed union with serifs
'\u2A4D': MO.BIN4, // closed intersection with serifs
'\u2A4E': MO.BIN4, // double square intersection
'\u2A4F': MO.BIN4, // double square union
'\u2A50': MO.BIN4, // closed union with serifs and smash product
'\u2A51': MO.BIN4, // logical and with dot above
'\u2A52': MO.BIN4, // logical or with dot above
'\u2A53': MO.BIN4, // double logical and
'\u2A54': MO.BIN4, // double logical or
'\u2A55': MO.BIN4, // two intersecting logical and
'\u2A56': MO.BIN4, // two intersecting logical or
'\u2A57': MO.BIN4, // sloping large or
'\u2A58': MO.BIN4, // sloping large and
'\u2A59': MO.REL, // logical or overlapping logical and
'\u2A5A': MO.BIN4, // logical and with middle stem
'\u2A5B': MO.BIN4, // logical or with middle stem
'\u2A5C': MO.BIN4, // logical and with horizontal dash
'\u2A5D': MO.BIN4, // logical or with horizontal dash
'\u2A5E': MO.BIN4, // logical and with double overbar
'\u2A5F': MO.BIN4, // logical and with underbar
'\u2A60': MO.BIN4, // logical and with double underbar
'\u2A61': MO.BIN4, // small vee with underbar
'\u2A62': MO.BIN4, // logical or with double overbar
'\u2A63': MO.BIN4, // logical or with double underbar
'\u2A64': MO.BIN4, // z notation domain antirestriction
'\u2A65': MO.BIN4, // z notation range antirestriction
'\u2A66': MO.REL, // equals sign with dot below
'\u2A67': MO.REL, // identical with dot above
'\u2A68': MO.REL, // triple horizontal bar with double vertical stroke
'\u2A69': MO.REL, // triple horizontal bar with triple vertical stroke
'\u2A6A': MO.REL, // tilde operator with dot above
'\u2A6B': MO.REL, // tilde operator with rising dots
'\u2A6C': MO.REL, // similar minus similar
'\u2A6D': MO.REL, // congruent with dot above
'\u2A6E': MO.REL, // equals with asterisk
'\u2A6F': MO.REL, // almost equal to with circumflex accent
'\u2A70': MO.REL, // approximately equal or equal to
'\u2A71': MO.BIN4, // equals sign above plus sign
'\u2A72': MO.BIN4, // plus sign above equals sign
'\u2A73': MO.REL, // equals sign above tilde operator
'\u2A74': MO.REL, // double colon equal
'\u2A75': MO.REL, // two consecutive equals signs
'\u2A76': MO.REL, // three consecutive equals signs
'\u2A77': MO.REL, // equals sign with two dots above and two dots below
'\u2A78': MO.REL, // equivalent with four dots above
'\u2A79': MO.REL, // less-than with circle inside
'\u2A7A': MO.REL, // greater-than with circle inside
'\u2A7B': MO.REL, // less-than with question mark above
'\u2A7C': MO.REL, // greater-than with question mark above
'\u2A7D': MO.REL, // less-than or slanted equal to
'\u2A7D\u0338': MO.REL, // less-than or slanted equal to with slash
'\u2A7E': MO.REL, // greater-than or slanted equal to
'\u2A7E\u0338': MO.REL, // greater-than or slanted equal to with slash
'\u2A7F': MO.REL, // less-than or slanted equal to with dot inside
'\u2A80': MO.REL, // greater-than or slanted equal to with dot inside
'\u2A81': MO.REL, // less-than or slanted equal to with dot above
'\u2A82': MO.REL, // greater-than or slanted equal to with dot above
'\u2A83': MO.REL, // less-than or slanted equal to with dot above right
'\u2A84': MO.REL, // greater-than or slanted equal to with dot above left
'\u2A85': MO.REL, // less-than or approximate
'\u2A86': MO.REL, // greater-than or approximate
'\u2A87': MO.REL, // less-than and single-line not equal to
'\u2A88': MO.REL, // greater-than and single-line not equal to
'\u2A89': MO.REL, // less-than and not approximate
'\u2A8A': MO.REL, // greater-than and not approximate
'\u2A8B': MO.REL, // less-than above double-line equal above greater-than
'\u2A8C': MO.REL, // greater-than above double-line equal above less-than
'\u2A8D': MO.REL, // less-than above similar or equal
'\u2A8E': MO.REL, // greater-than above similar or equal
'\u2A8F': MO.REL, // less-than above similar above greater-than
'\u2A90': MO.REL, // greater-than above similar above less-than
'\u2A91': MO.REL, // less-than above greater-than above double-line equal
'\u2A92': MO.REL, // greater-than above less-than above double-line equal
'\u2A93': MO.REL, // less-than above slanted equal above greater-than above slanted equal
'\u2A94': MO.REL, // greater-than above slanted equal above less-than above slanted equal
'\u2A95': MO.REL, // slanted equal to or less-than
'\u2A96': MO.REL, // slanted equal to or greater-than
'\u2A97': MO.REL, // slanted equal to or less-than with dot inside
'\u2A98': MO.REL, // slanted equal to or greater-than with dot inside
'\u2A99': MO.REL, // double-line equal to or less-than
'\u2A9A': MO.REL, // double-line equal to or greater-than
'\u2A9B': MO.REL, // double-line slanted equal to or less-than
'\u2A9C': MO.REL, // double-line slanted equal to or greater-than
'\u2A9D': MO.REL, // similar or less-than
'\u2A9E': MO.REL, // similar or greater-than
'\u2A9F': MO.REL, // similar above less-than above equals sign
'\u2AA0': MO.REL, // similar above greater-than above equals sign
'\u2AA1': MO.REL, // double nested less-than
'\u2AA1\u0338': MO.REL, // double nested less-than with slash
'\u2AA2': MO.REL, // double nested greater-than
'\u2AA2\u0338': MO.REL, // double nested greater-than with slash
'\u2AA3': MO.REL, // double nested less-than with underbar
'\u2AA4': MO.REL, // greater-than overlapping less-than
'\u2AA5': MO.REL, // greater-than beside less-than
'\u2AA6': MO.REL, // less-than closed by curve
'\u2AA7': MO.REL, // greater-than closed by curve
'\u2AA8': MO.REL, // less-than closed by curve above slanted equal
'\u2AA9': MO.REL, // greater-than closed by curve above slanted equal
'\u2AAA': MO.REL, // smaller than
'\u2AAB': MO.REL, // larger than
'\u2AAC': MO.REL, // smaller than or equal to
'\u2AAD': MO.REL, // larger than or equal to
'\u2AAE': MO.REL, // equals sign with bumpy above
'\u2AAF\u0338': MO.REL, // precedes above single-line equals sign with slash
'\u2AB0\u0338': MO.REL, // succeeds above single-line equals sign with slash
'\u2AB1': MO.REL, // precedes above single-line not equal to
'\u2AB2': MO.REL, // succeeds above single-line not equal to
'\u2AB3': MO.REL, // precedes above equals sign
'\u2AB4': MO.REL, // succeeds above equals sign
'\u2AB5': MO.REL, // precedes above not equal to
'\u2AB6': MO.REL, // succeeds above not equal to
'\u2AB7': MO.REL, // precedes above almost equal to
'\u2AB8': MO.REL, // succeeds above almost equal to
'\u2AB9': MO.REL, // precedes above not almost equal to
'\u2ABA': MO.REL, // succeeds above not almost equal to
'\u2ABB': MO.REL, // double precedes
'\u2ABC': MO.REL, // double succeeds
'\u2ABD': MO.REL, // subset with dot
'\u2ABE': MO.REL, // superset with dot
'\u2ABF': MO.REL, // subset with plus sign below
'\u2AC0': MO.REL, // superset with plus sign below
'\u2AC1': MO.REL, // subset with multiplication sign below
'\u2AC2': MO.REL, // superset with multiplication sign below
'\u2AC3': MO.REL, // subset of or equal to with dot above
'\u2AC4': MO.REL, // superset of or equal to with dot above
'\u2AC5': MO.REL, // subset of above equals sign
'\u2AC6': MO.REL, // superset of above equals sign
'\u2AC7': MO.REL, // subset of above tilde operator
'\u2AC8': MO.REL, // superset of above tilde operator
'\u2AC9': MO.REL, // subset of above almost equal to
'\u2ACA': MO.REL, // superset of above almost equal to
'\u2ACB': MO.REL, // subset of above not equal to
'\u2ACC': MO.REL, // superset of above not equal to
'\u2ACD': MO.REL, // square left open box operator
'\u2ACE': MO.REL, // square right open box operator
'\u2ACF': MO.REL, // closed subset
'\u2AD0': MO.REL, // closed superset
'\u2AD1': MO.REL, // closed subset or equal to
'\u2AD2': MO.REL, // closed superset or equal to
'\u2AD3': MO.REL, // subset above superset
'\u2AD4': MO.REL, // superset above subset
'\u2AD5': MO.REL, // subset above subset
'\u2AD6': MO.REL, // superset above superset
'\u2AD7': MO.REL, // superset beside subset
'\u2AD8': MO.REL, // superset beside and joined by dash with subset
'\u2AD9': MO.REL, // element of opening downwards
'\u2ADA': MO.REL, // pitchfork with tee top
'\u2ADB': MO.REL, // transversal intersection
'\u2ADC': MO.REL, // forking
'\u2ADD': MO.REL, // nonforking
'\u2ADE': MO.REL, // short left tack
'\u2ADF': MO.REL, // short down tack
'\u2AE0': MO.REL, // short up tack
'\u2AE1': MO.REL, // perpendicular with s
'\u2AE2': MO.REL, // vertical bar triple right turnstile
'\u2AE3': MO.REL, // double vertical bar left turnstile
'\u2AE4': MO.REL, // vertical bar double left turnstile
'\u2AE5': MO.REL, // double vertical bar double left turnstile
'\u2AE6': MO.REL, // long dash from left member of double vertical
'\u2AE7': MO.REL, // short down tack with overbar
'\u2AE8': MO.REL, // short up tack with underbar
'\u2AE9': MO.REL, // short up tack above short down tack
'\u2AEA': MO.REL, // double down tack
'\u2AEB': MO.REL, // double up tack
'\u2AEC': MO.REL, // double stroke not sign
'\u2AED': MO.REL, // reversed double stroke not sign
'\u2AEE': MO.REL, // does not divide with reversed negation slash
'\u2AEF': MO.REL, // vertical line with circle above
'\u2AF0': MO.REL, // vertical line with circle below
'\u2AF1': MO.REL, // down tack with circle below
'\u2AF2': MO.REL, // parallel with horizontal stroke
'\u2AF3': MO.REL, // parallel with tilde operator
'\u2AF4': MO.BIN4, // triple vertical bar binary relation
'\u2AF5': MO.BIN4, // triple vertical bar with horizontal stroke
'\u2AF6': MO.BIN4, // triple colon operator
'\u2AF7': MO.REL, // triple nested less-than
'\u2AF8': MO.REL, // triple nested greater-than
'\u2AF9': MO.REL, // double-line slanted less-than or equal to
'\u2AFA': MO.REL, // double-line slanted greater-than or equal to
'\u2AFB': MO.BIN4, // triple solidus binary relation
'\u2AFD': MO.BIN4, // double solidus operator
'\u2AFE': MO.BIN3 // white vertical bar
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/SuppMathOperators.js");
})(MathJax.ElementJax.mml);

View File

@@ -0,0 +1,40 @@
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/SupplementalArrowsA.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
infix: {
'\u27F0': MO.RELSTRETCH, // upwards quadruple arrow
'\u27F1': MO.RELSTRETCH, // downwards quadruple arrow
'\u27FB': MO.WIDEREL, // long leftwards arrow from bar
'\u27FD': MO.WIDEREL, // long leftwards double arrow from bar
'\u27FE': MO.WIDEREL, // long rightwards double arrow from bar
'\u27FF': MO.WIDEREL // long rightwards squiggle arrow
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/SupplementalArrowsA.js");
})(MathJax.ElementJax.mml);

View File

@@ -0,0 +1,162 @@
/*************************************************************
*
* MathJax/jax/output/HTML-CSS/optable/SupplementalArrowsB.js
*
* Copyright (c) 2010-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
(function (MML) {
var MO = MML.mo.OPTYPES;
var TEXCLASS = MML.TEXCLASS;
MathJax.Hub.Insert(MML.mo.prototype,{
OPTABLE: {
infix: {
'\u2900': MO.RELACCENT, // rightwards two-headed arrow with vertical stroke
'\u2901': MO.RELACCENT, // rightwards two-headed arrow with double vertical stroke
'\u2902': MO.RELACCENT, // leftwards double arrow with vertical stroke
'\u2903': MO.RELACCENT, // rightwards double arrow with vertical stroke
'\u2904': MO.RELACCENT, // left right double arrow with vertical stroke
'\u2905': MO.RELACCENT, // rightwards two-headed arrow from bar
'\u2906': MO.RELACCENT, // leftwards double arrow from bar
'\u2907': MO.RELACCENT, // rightwards double arrow from bar
'\u2908': MO.REL, // downwards arrow with horizontal stroke
'\u2909': MO.REL, // upwards arrow with horizontal stroke
'\u290A': MO.RELSTRETCH, // upwards triple arrow
'\u290B': MO.RELSTRETCH, // downwards triple arrow
'\u290C': MO.WIDEREL, // leftwards double dash arrow
'\u290D': MO.WIDEREL, // rightwards double dash arrow
'\u290E': MO.WIDEREL, // leftwards triple dash arrow
'\u290F': MO.WIDEREL, // rightwards triple dash arrow
'\u2910': MO.WIDEREL, // rightwards two-headed triple dash arrow
'\u2911': MO.RELACCENT, // rightwards arrow with dotted stem
'\u2912': MO.RELSTRETCH, // upwards arrow to bar
'\u2913': MO.RELSTRETCH, // downwards arrow to bar
'\u2914': MO.RELACCENT, // rightwards arrow with tail with vertical stroke
'\u2915': MO.RELACCENT, // rightwards arrow with tail with double vertical stroke
'\u2916': MO.RELACCENT, // rightwards two-headed arrow with tail
'\u2917': MO.RELACCENT, // rightwards two-headed arrow with tail with vertical stroke
'\u2918': MO.RELACCENT, // rightwards two-headed arrow with tail with double vertical stroke
'\u2919': MO.RELACCENT, // leftwards arrow-tail
'\u291A': MO.RELACCENT, // rightwards arrow-tail
'\u291B': MO.RELACCENT, // leftwards double arrow-tail
'\u291C': MO.RELACCENT, // rightwards double arrow-tail
'\u291D': MO.RELACCENT, // leftwards arrow to black diamond
'\u291E': MO.RELACCENT, // rightwards arrow to black diamond
'\u291F': MO.RELACCENT, // leftwards arrow from bar to black diamond
'\u2920': MO.RELACCENT, // rightwards arrow from bar to black diamond
'\u2921': MO.RELSTRETCH, // north west and south east arrow
'\u2922': MO.RELSTRETCH, // north east and south west arrow
'\u2923': MO.REL, // north west arrow with hook
'\u2924': MO.REL, // north east arrow with hook
'\u2925': MO.REL, // south east arrow with hook
'\u2926': MO.REL, // south west arrow with hook
'\u2927': MO.REL, // north west arrow and north east arrow
'\u2928': MO.REL, // north east arrow and south east arrow
'\u2929': MO.REL, // south east arrow and south west arrow
'\u292A': MO.REL, // south west arrow and north west arrow
'\u292B': MO.REL, // rising diagonal crossing falling diagonal
'\u292C': MO.REL, // falling diagonal crossing rising diagonal
'\u292D': MO.REL, // south east arrow crossing north east arrow
'\u292E': MO.REL, // north east arrow crossing south east arrow
'\u292F': MO.REL, // falling diagonal crossing north east arrow
'\u2930': MO.REL, // rising diagonal crossing south east arrow
'\u2931': MO.REL, // north east arrow crossing north west arrow
'\u2932': MO.REL, // north west arrow crossing north east arrow
'\u2933': MO.RELACCENT, // wave arrow pointing directly right
'\u2934': MO.REL, // arrow pointing rightwards then curving upwards
'\u2935': MO.REL, // arrow pointing rightwards then curving downwards
'\u2936': MO.REL, // arrow pointing downwards then curving leftwards
'\u2937': MO.REL, // arrow pointing downwards then curving rightwards
'\u2938': MO.REL, // right-side arc clockwise arrow
'\u2939': MO.REL, // left-side arc anticlockwise arrow
'\u293A': MO.RELACCENT, // top arc anticlockwise arrow
'\u293B': MO.RELACCENT, // bottom arc anticlockwise arrow
'\u293C': MO.RELACCENT, // top arc clockwise arrow with minus
'\u293D': MO.RELACCENT, // top arc anticlockwise arrow with plus
'\u293E': MO.REL, // lower right semicircular clockwise arrow
'\u293F': MO.REL, // lower left semicircular anticlockwise arrow
'\u2940': MO.REL, // anticlockwise closed circle arrow
'\u2941': MO.REL, // clockwise closed circle arrow
'\u2942': MO.RELACCENT, // rightwards arrow above short leftwards arrow
'\u2943': MO.RELACCENT, // leftwards arrow above short rightwards arrow
'\u2944': MO.RELACCENT, // short rightwards arrow above leftwards arrow
'\u2945': MO.RELACCENT, // rightwards arrow with plus below
'\u2946': MO.RELACCENT, // leftwards arrow with plus below
'\u2947': MO.RELACCENT, // rightwards arrow through x
'\u2948': MO.RELACCENT, // left right arrow through small circle
'\u2949': MO.REL, // upwards two-headed arrow from small circle
'\u294A': MO.RELACCENT, // left barb up right barb down harpoon
'\u294B': MO.RELACCENT, // left barb down right barb up harpoon
'\u294C': MO.REL, // up barb right down barb left harpoon
'\u294D': MO.REL, // up barb left down barb right harpoon
'\u294E': MO.WIDEREL, // left barb up right barb up harpoon
'\u294F': MO.RELSTRETCH, // up barb right down barb right harpoon
'\u2950': MO.WIDEREL, // left barb down right barb down harpoon
'\u2951': MO.RELSTRETCH, // up barb left down barb left harpoon
'\u2952': MO.WIDEREL, // leftwards harpoon with barb up to bar
'\u2953': MO.WIDEREL, // rightwards harpoon with barb up to bar
'\u2954': MO.RELSTRETCH, // upwards harpoon with barb right to bar
'\u2955': MO.RELSTRETCH, // downwards harpoon with barb right to bar
'\u2956': MO.RELSTRETCH, // leftwards harpoon with barb down to bar
'\u2957': MO.RELSTRETCH, // rightwards harpoon with barb down to bar
'\u2958': MO.RELSTRETCH, // upwards harpoon with barb left to bar
'\u2959': MO.RELSTRETCH, // downwards harpoon with barb left to bar
'\u295A': MO.WIDEREL, // leftwards harpoon with barb up from bar
'\u295B': MO.WIDEREL, // rightwards harpoon with barb up from bar
'\u295C': MO.RELSTRETCH, // upwards harpoon with barb right from bar
'\u295D': MO.RELSTRETCH, // downwards harpoon with barb right from bar
'\u295E': MO.WIDEREL, // leftwards harpoon with barb down from bar
'\u295F': MO.WIDEREL, // rightwards harpoon with barb down from bar
'\u2960': MO.RELSTRETCH, // upwards harpoon with barb left from bar
'\u2961': MO.RELSTRETCH, // downwards harpoon with barb left from bar
'\u2962': MO.RELACCENT, // leftwards harpoon with barb up above leftwards harpoon with barb down
'\u2963': MO.REL, // upwards harpoon with barb left beside upwards harpoon with barb right
'\u2964': MO.RELACCENT, // rightwards harpoon with barb up above rightwards harpoon with barb down
'\u2965': MO.REL, // downwards harpoon with barb left beside downwards harpoon with barb right
'\u2966': MO.RELACCENT, // leftwards harpoon with barb up above rightwards harpoon with barb up
'\u2967': MO.RELACCENT, // leftwards harpoon with barb down above rightwards harpoon with barb down
'\u2968': MO.RELACCENT, // rightwards harpoon with barb up above leftwards harpoon with barb up
'\u2969': MO.RELACCENT, // rightwards harpoon with barb down above leftwards harpoon with barb down
'\u296A': MO.RELACCENT, // leftwards harpoon with barb up above long dash
'\u296B': MO.RELACCENT, // leftwards harpoon with barb down below long dash
'\u296C': MO.RELACCENT, // rightwards harpoon with barb up above long dash
'\u296D': MO.RELACCENT, // rightwards harpoon with barb down below long dash
'\u296E': MO.RELSTRETCH, // upwards harpoon with barb left beside downwards harpoon with barb right
'\u296F': MO.RELSTRETCH, // downwards harpoon with barb left beside upwards harpoon with barb right
'\u2970': MO.RELACCENT, // right double arrow with rounded head
'\u2971': MO.RELACCENT, // equals sign above rightwards arrow
'\u2972': MO.RELACCENT, // tilde operator above rightwards arrow
'\u2973': MO.RELACCENT, // leftwards arrow above tilde operator
'\u2974': MO.RELACCENT, // rightwards arrow above tilde operator
'\u2975': MO.RELACCENT, // rightwards arrow above almost equal to
'\u2976': MO.RELACCENT, // less-than above leftwards arrow
'\u2977': MO.RELACCENT, // leftwards arrow through less-than
'\u2978': MO.RELACCENT, // greater-than above rightwards arrow
'\u2979': MO.RELACCENT, // subset above rightwards arrow
'\u297A': MO.RELACCENT, // leftwards arrow through subset
'\u297B': MO.RELACCENT, // superset above leftwards arrow
'\u297C': MO.RELACCENT, // left fish tail
'\u297D': MO.RELACCENT, // right fish tail
'\u297E': MO.REL, // up fish tail
'\u297F': MO.REL // down fish tail
}
}
});
MathJax.Ajax.loadComplete(MML.optableDir+"/SupplementalArrowsB.js");
})(MathJax.ElementJax.mml);

View File

@@ -0,0 +1,46 @@
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax/jax/input/AsciiMath/config.js
*
* Initializes the AsciiMath InputJax (the main definition is in
* MathJax/jax/input/AsciiMath/jax.js, which is loaded when needed).
*
* Originally adapted for MathJax by David Lippman.
* Additional work done by Davide P. Cervone.
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2012-2017 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
MathJax.InputJax.AsciiMath = MathJax.InputJax({
id: "AsciiMath",
version: "2.7.2",
directory: MathJax.InputJax.directory + "/AsciiMath",
extensionDir: MathJax.InputJax.extensionDir + "/AsciiMath",
config: {
fixphi: true, // switch phi and varphi unicode values
useMathMLspacing: true, // use MathML spacing rather than TeX spacing?
displaystyle: true, // put limits above and below operators
decimalsign: "." // can change to "," but watch out for "(1,2)"
}
});
MathJax.InputJax.AsciiMath.Register("math/asciimath");
MathJax.InputJax.AsciiMath.loadComplete("config.js");

File diff suppressed because it is too large Load Diff

187
node_modules/mathjax-full/ts/input/mathml.ts generated vendored Normal file
View File

@@ -0,0 +1,187 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the MathML InputJax object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AbstractInputJax} from '../core/InputJax.js';
import {defaultOptions, separateOptions, OptionList} from '../util/Options.js';
import {FunctionList} from '../util/FunctionList.js';
import {MathDocument} from '../core/MathDocument.js';
import {MathItem} from '../core/MathItem.js';
import {DOMAdaptor} from '../core/DOMAdaptor.js';
import {MmlFactory} from '../core/MmlTree/MmlFactory.js';
import {FindMathML} from './mathml/FindMathML.js';
import {MathMLCompile} from './mathml/MathMLCompile.js';
/*****************************************************************/
/**
* Implements the MathML class (extends AbstractInputJax)
*
* @template N The HTMLElement node class
* @template T The Text node class
* @template D The Document class
*/
export class MathML<N, T, D> extends AbstractInputJax<N, T, D> {
/**
* The name of this input jax
*/
public static NAME: string = 'MathML';
/**
* @override
*/
public static OPTIONS: OptionList = defaultOptions({
parseAs: 'html', // Whether to use HTML or XML parsing for the MathML string
forceReparse: false, // Whether to force the string to be reparsed, or use the one from the document DOM
FindMathML: null, // The FindMathML instance to override the default one
MathMLCompile: null, // The MathMLCompile instance to override the default one
/*
* The function to use to handle a parsing error (throw an error by default)
*/
parseError: function (node: Node) {
this.error(this.adaptor.textContent(node).replace(/\n.*/g, ''));
}
}, AbstractInputJax.OPTIONS);
/**
* The FindMathML instance used to locate MathML in the document
*/
protected findMathML: FindMathML<N, T, D>;
/**
* The MathMLCompile instance used to convert the MathML tree to internal format
*/
protected mathml: MathMLCompile<N, T, D>;
/**
* A list of functions to call on the parsed MathML DOM before conversion to internal structure
*/
public mmlFilters: FunctionList;
/**
* @override
*/
constructor(options: OptionList = {}) {
let [mml, find, compile] = separateOptions(options, FindMathML.OPTIONS, MathMLCompile.OPTIONS);
super(mml);
this.findMathML = this.options['FindMathML'] || new FindMathML<N, T, D>(find);
this.mathml = this.options['MathMLCompile'] || new MathMLCompile<N, T, D>(compile);
this.mmlFilters = new FunctionList();
}
/**
* Set the adaptor in any of the objects that need it
*
* @override
*/
public setAdaptor(adaptor: DOMAdaptor<N, T, D>) {
super.setAdaptor(adaptor);
this.findMathML.adaptor = adaptor;
this.mathml.adaptor = adaptor;
}
/**
* @param {MmlFactory} mmlFactory The MmlFactory to use for this MathML input jax
*/
public setMmlFactory(mmlFactory: MmlFactory) {
super.setMmlFactory(mmlFactory);
this.mathml.setMmlFactory(mmlFactory);
}
/**
* Don't process strings (process nodes)
*
* @override
*/
public get processStrings() {
return false;
}
/**
* Convert a MathItem to internal format:
* If there is no existing MathML node, or we are asked to reparse everything
* Execute the preFilters on the math
* Parse the MathML string in the desired format, and check the result for errors
* If we got an HTML document:
* Check that it has only one child (the <math> element), and use it
* Otherwise
* Use the root element from the XML document
* If the node is not a <math> node, report the error.
* Execute the mmlFilters on the parsed MathML
* Compile the MathML to internal format, and execute the postFilters
* Return the resulting internal format
*
* @override
*/
public compile(math: MathItem<N, T, D>, document: MathDocument<N, T, D>) {
let mml = math.start.node;
if (!mml || !math.end.node || this.options['forceReparse'] || this.adaptor.kind(mml) === '#text') {
let mathml = this.executeFilters(this.preFilters, math, document, (math.math || '<math></math>').trim());
let doc = this.checkForErrors(this.adaptor.parse(mathml, 'text/' + this.options['parseAs']));
let body = this.adaptor.body(doc);
if (this.adaptor.childNodes(body).length !== 1) {
this.error('MathML must consist of a single element');
}
mml = this.adaptor.remove(this.adaptor.firstChild(body)) as N;
if (this.adaptor.kind(mml).replace(/^[a-z]+:/, '') !== 'math') {
this.error('MathML must be formed by a <math> element, not <' + this.adaptor.kind(mml) + '>');
}
}
mml = this.executeFilters(this.mmlFilters, math, document, mml);
return this.executeFilters(this.postFilters, math, document, this.mathml.compile(mml as N));
}
/**
* Check a parsed MathML string for errors.
*
* @param {D} doc The document returns from the DOMParser
* @return {D} The document
*/
protected checkForErrors(doc: D): D {
let err = this.adaptor.tags(this.adaptor.body(doc), 'parsererror')[0];
if (err) {
if (this.adaptor.textContent(err) === '') {
this.error('Error processing MathML');
}
this.options['parseError'].call(this, err);
}
return doc;
}
/**
* Throw an error
*
* @param {string} message The error message to produce
*/
protected error(message: string) {
throw new Error(message);
}
/**
* @override
*/
public findMath(node: N) {
return this.findMathML.findMath(node);
}
}

130
node_modules/mathjax-full/ts/input/mathml/FindMathML.ts generated vendored Normal file
View File

@@ -0,0 +1,130 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the MathML version of the FindMath object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AbstractFindMath} from '../../core/FindMath.js';
import {DOMAdaptor} from '../../core/DOMAdaptor.js';
import {OptionList} from '../../util/Options.js';
import {ProtoItem} from '../../core/MathItem.js';
/**
* The MathML namespace
*/
const NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
/*****************************************************************/
/**
* Implements the FindMathML object (extends AbstractFindMath)
*
* @template N The HTMLElement node class
* @template T The Text node class
* @template D The Document class
*/
export class FindMathML<N, T, D> extends AbstractFindMath<N, T, D> {
/**
* @override
*/
public static OPTIONS: OptionList = {};
/**
* The DOMAdaptor for the document being processed
*/
public adaptor: DOMAdaptor<N, T, D>;
/**
* Locates math nodes, possibly with namespace prefixes.
* Store them in a set so that if found more than once, they will only
* appear in the list once.
*
* @override
*/
public findMath(node: N) {
let set = new Set<N>();
this.findMathNodes(node, set);
this.findMathPrefixed(node, set);
const html = this.adaptor.root(this.adaptor.document);
if (this.adaptor.kind(html) === 'html' && set.size === 0) {
this.findMathNS(node, set);
}
return this.processMath(set);
}
/**
* Find plain <math> tags
*
* @param {N} node The container to seaerch for math
* @param {Set<N>} set The set in which to store the math nodes
*/
protected findMathNodes(node: N, set: Set<N>) {
for (const math of this.adaptor.tags(node, 'math')) {
set.add(math);
}
}
/**
* Find <m:math> tags (or whatever prefixes there are)
*
* @param {N} node The container to seaerch for math
* @param {NodeSet} set The set in which to store the math nodes
*/
protected findMathPrefixed(node: N, set: Set<N>) {
let html = this.adaptor.root(this.adaptor.document);
for (const attr of this.adaptor.allAttributes(html)) {
if (attr.name.substr(0, 6) === 'xmlns:' && attr.value === NAMESPACE) {
let prefix = attr.name.substr(6);
for (const math of this.adaptor.tags(node, prefix + ':math')) {
set.add(math);
}
}
}
}
/**
* Find namespaced math in XHTML documents (is this really needed?)
*
* @param {N} node The container to seaerch for math
* @param {NodeSet} set The set in which to store the math nodes
*/
protected findMathNS(node: N, set: Set<N>) {
for (const math of this.adaptor.tags(node, 'math', NAMESPACE)) {
set.add(math);
}
}
/**
* Produce the array of proto math items from the node set
*/
protected processMath(set: Set<N>) {
let math: ProtoItem<N, T>[] = [];
for (const mml of Array.from(set)) {
let display = (this.adaptor.getAttribute(mml, 'display') === 'block' ||
this.adaptor.getAttribute(mml, 'mode') === 'display');
let start = {node: mml, n: 0, delim: ''};
let end = {node: mml, n: 0, delim: ''};
math.push({math: this.adaptor.outerHTML(mml), start, end, display});
}
return math;
}
}

View File

@@ -0,0 +1,336 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implementation of the Compile function for the MathML input jax
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {MmlFactory} from '../../core/MmlTree/MmlFactory.js';
import {MmlNode, TextNode, XMLNode, AbstractMmlNode, AbstractMmlTokenNode, TEXCLASS}
from '../../core/MmlTree/MmlNode.js';
import {userOptions, defaultOptions, OptionList} from '../../util/Options.js';
import * as Entities from '../../util/Entities.js';
import {DOMAdaptor} from '../../core/DOMAdaptor.js';
/********************************************************************/
/**
* The class for performing the MathML DOM node to
* internal MmlNode conversion.
*
* @template N The HTMLElement node class
* @template T The Text node class
* @template D The Document class
*/
export class MathMLCompile<N, T, D> {
/**
* The default options for this object
*/
public static OPTIONS: OptionList = {
MmlFactory: null, // The MmlFactory to use (defaults to a new MmlFactory)
fixMisplacedChildren: true, // True if we want to use heuristics to try to fix
// problems with the tree based on HTML not handling
// self-closing tags properly
verify: { // Options to pass to verifyTree() controlling MathML verification
...AbstractMmlNode.verifyDefaults
},
translateEntities: true // True means translate entities in text nodes
};
/**
* The DOMAdaptor for the document being processed
*/
public adaptor: DOMAdaptor<N, T, D>;
/**
* The instance of the MmlFactory object and
*/
protected factory: MmlFactory;
/**
* The options (the defaults with the user options merged in)
*/
protected options: OptionList;
/**
* Merge the user options into the defaults, and save them
* Create the MmlFactory object
*
* @param {OptionList} options The options controlling the conversion
*/
constructor(options: OptionList = {}) {
const Class = this.constructor as typeof MathMLCompile;
this.options = userOptions(defaultOptions({}, Class.OPTIONS), options);
}
/**
* @param{MmlFactory} mmlFactory The MathML factory to use for new nodes
*/
public setMmlFactory(mmlFactory: MmlFactory) {
this.factory = mmlFactory;
}
/**
* Convert a MathML DOM tree to internal MmlNodes
*
* @param {N} node The <math> node to convert to MmlNodes
* @return {MmlNode} The MmlNode at the root of the converted tree
*/
public compile(node: N): MmlNode {
let mml = this.makeNode(node);
mml.verifyTree(this.options['verify']);
mml.setInheritedAttributes({}, false, 0, false);
mml.walkTree(this.markMrows);
return mml;
}
/**
* Recursively convert nodes and their children, taking MathJax classes
* into account.
*
* FIXME: we should use data-* attributes rather than classes for these
*
* @param {N} node The node to convert to an MmlNode
* @return {MmlNode} The converted MmlNode
*/
public makeNode(node: N): MmlNode {
const adaptor = this.adaptor;
let limits = false;
let kind = adaptor.kind(node).replace(/^.*:/, '');
let texClass = adaptor.getAttribute(node, 'data-mjx-texclass') || '';
if (texClass) {
texClass = this.filterAttribute('data-mjx-texclass', texClass) || '';
}
let type = texClass && kind === 'mrow' ? 'TeXAtom' : kind;
for (const name of this.filterClassList(adaptor.allClasses(node))) {
if (name.match(/^MJX-TeXAtom-/) && kind === 'mrow') {
texClass = name.substr(12);
type = 'TeXAtom';
} else if (name === 'MJX-fixedlimits') {
limits = true;
}
}
this.factory.getNodeClass(type) || this.error('Unknown node type "' + type + '"');
let mml = this.factory.create(type);
if (type === 'TeXAtom' && texClass === 'OP' && !limits) {
mml.setProperty('movesupsub', true);
mml.attributes.setInherited('movablelimits', true);
}
if (texClass) {
mml.texClass = (TEXCLASS as {[name: string]: number})[texClass];
mml.setProperty('texClass', mml.texClass);
}
this.addAttributes(mml, node);
this.checkClass(mml, node);
this.addChildren(mml, node);
return mml;
}
/**
* Copy the attributes from a MathML node to an MmlNode.
*
* @param {MmlNode} mml The MmlNode to which attributes will be added
* @param {N} node The MathML node whose attributes to copy
*/
protected addAttributes(mml: MmlNode, node: N) {
let ignoreVariant = false;
for (const attr of this.adaptor.allAttributes(node)) {
let name = attr.name;
let value = this.filterAttribute(name, attr.value);
if (value === null || name === 'xmlns') {
continue;
}
if (name.substr(0, 9) === 'data-mjx-') {
switch (name.substr(9)) {
case 'alternate':
mml.setProperty('variantForm', true);
break;
case 'variant':
mml.attributes.set('mathvariant', value);
ignoreVariant = true;
break;
case 'smallmatrix':
mml.setProperty('scriptlevel', 1);
mml.setProperty('useHeight', false);
break;
case 'accent':
mml.setProperty('mathaccent', value === 'true');
break;
case 'auto-op':
mml.setProperty('autoOP', value === 'true');
break;
case 'script-align':
mml.setProperty('scriptalign', value);
break;
}
} else if (name !== 'class') {
let val = value.toLowerCase();
if (val === 'true' || val === 'false') {
mml.attributes.set(name, val === 'true');
} else if (!ignoreVariant || name !== 'mathvariant') {
mml.attributes.set(name, value);
}
}
}
}
/**
* Provide a hook for the Safe extension to filter attribute values.
*
* @param {string} name The name of an attribute to filter
* @param {string} value The value to filter
*/
protected filterAttribute(_name: string, value: string) {
return value;
}
/**
* Provide a hook for the Safe extension to filter class names.
*
* @param {string[]} list The list of class names to filter
*/
protected filterClassList(list: string[]) {
return list;
}
/**
* Convert the children of the MathML node and add them to the MmlNode
*
* @param {MmlNode} mml The MmlNode to which children will be added
* @param {N} node The MathML node whose children are to be copied
*/
protected addChildren(mml: MmlNode, node: N) {
if (mml.arity === 0) {
return;
}
const adaptor = this.adaptor;
for (const child of adaptor.childNodes(node) as N[]) {
const name = adaptor.kind(child);
if (name === '#comment') {
continue;
}
if (name === '#text') {
this.addText(mml, child);
} else if (mml.isKind('annotation-xml')) {
mml.appendChild((this.factory.create('XML') as XMLNode).setXML(child, adaptor));
} else {
let childMml = mml.appendChild(this.makeNode(child)) as MmlNode;
if (childMml.arity === 0 && adaptor.childNodes(child).length) {
if (this.options['fixMisplacedChildren']) {
this.addChildren(mml, child);
} else {
childMml.mError('There should not be children for ' + childMml.kind + ' nodes',
this.options['verify'], true);
}
}
}
}
}
/**
* Add text to a token node
*
* @param {MmlNode} mml The MmlNode to which text will be added
* @param {N} child The text node whose contents is to be copied
*/
protected addText(mml: MmlNode, child: N) {
let text = this.adaptor.value(child);
if ((mml.isToken || mml.getProperty('isChars')) && mml.arity) {
if (mml.isToken) {
text = Entities.translate(text);
text = this.trimSpace(text);
}
mml.appendChild((this.factory.create('text') as TextNode).setText(text));
} else if (text.match(/\S/)) {
this.error('Unexpected text node "' + text + '"');
}
}
/**
* Check for special MJX values in the class and process them
*
* @param {MmlNode} mml The MmlNode to be modified according to the class markers
* @param {N} node The MathML node whose class is to be processed
*/
protected checkClass(mml: MmlNode, node: N) {
let classList = [];
for (const name of this.filterClassList(this.adaptor.allClasses(node))) {
if (name.substr(0, 4) === 'MJX-') {
if (name === 'MJX-variant') {
mml.setProperty('variantForm', true);
} else if (name.substr(0, 11) !== 'MJX-TeXAtom') {
mml.attributes.set('mathvariant', this.fixCalligraphic(name.substr(3)));
}
} else {
classList.push(name);
}
}
if (classList.length) {
mml.attributes.set('class', classList.join(' '));
}
}
/**
* Fix the old incorrect spelling of calligraphic.
*
* @param {string} variant The mathvariant name
* @return {string} The corrected variant
*/
protected fixCalligraphic(variant: string): string {
return variant.replace(/caligraphic/, 'calligraphic');
}
/**
* Check to see if an mrow has delimiters at both ends (so looks like an mfenced structure).
*
* @param {MmlNode} mml The node to check for mfenced structure
*/
protected markMrows(mml: MmlNode) {
if (mml.isKind('mrow') && !mml.isInferred && mml.childNodes.length >= 2) {
let first = mml.childNodes[0] as MmlNode;
let last = mml.childNodes[mml.childNodes.length - 1] as MmlNode;
if (first.isKind('mo') && first.attributes.get('fence') && first.attributes.get('stretchy') &&
last.isKind('mo') && last.attributes.get('fence') && last.attributes.get('stretchy')) {
if (first.childNodes.length) {
mml.setProperty('open', (first as AbstractMmlTokenNode).getText());
}
if (last.childNodes.length) {
mml.setProperty('close', (last as AbstractMmlTokenNode).getText());
}
}
}
}
/**
* @param {string} text The text to have leading/trailing spaced removed
* @return {string} The trimmed text
*/
protected trimSpace(text: string): string {
return text.replace(/[\t\n\r]/g, ' ') // whitespace to spaces
.replace(/^ +/, '') // initial whitespace
.replace(/ +$/, '') // trailing whitespace
.replace(/ +/g, ' '); // internal multiple whitespace
}
/**
* @param {string} message The error message to produce
*/
protected error(message: string) {
throw new Error(message);
}
}

View File

@@ -0,0 +1,76 @@
/*************************************************************
*
* Copyright (c) 2021-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Auxiliary function for elementary MathML3 support (experimental)
* using David Carlisle's XLST transform.
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {MathDocument} from '../../../core/MathDocument.js';
/**
* Create the transform function that uses Saxon-js to perform the
* xslt transformation.
*
* @template N The HTMLElement node class
* @template T The Text node class
* @template D The Document class
*
* @return {(node: N, doc: MathDocument<N,T,D>) => N)} The transformation function
*/
export function createTransform<N, T, D>(): (node: N, doc: MathDocument<N, T, D>) => N {
/* tslint:disable-next-line:no-eval */
const nodeRequire = eval('require'); // get the actual require from node.
/* tslint:disable-next-line:no-eval */
const dirname = eval('__dirname'); // get the actual __dirname
try {
nodeRequire.resolve('saxon-js'); // check if saxon-js is installed.
} catch (err) {
throw Error('Saxon-js not found. Run the command:\n npm install saxon-js\nand try again.');
}
const Saxon = nodeRequire('saxon-js'); // dynamically load Saxon-JS.
const path = nodeRequire('path'); // use the real version from node.
const fs = nodeRequire('fs'); // use the real version from node.
const xsltFile = path.resolve(dirname, 'mml3.sef.json'); // load the preprocessed stylesheet.
const xslt = JSON.parse(fs.readFileSync(xsltFile)); // and parse it.
return (node: N, doc: MathDocument<N, T, D>) => {
const adaptor = doc.adaptor;
let mml = adaptor.outerHTML(node);
//
// Make sure the namespace is present
//
if (!mml.match(/ xmlns[=:]/)) {
mml = mml.replace(/<(?:(\w+)(:))?math/, '<$1$2math xmlns$2$1="http://www.w3.org/1998/Math/MathML"');
}
//
// Try to run the transform, and if it fails, return the original MathML
//
let result;
try {
result = adaptor.firstChild(adaptor.body(adaptor.parse(Saxon.transform({
stylesheetInternal: xslt,
sourceText: mml,
destination: 'serialized'
}).principalResult))) as N;
} catch (err) {
result = node;
}
return result;
};
}

File diff suppressed because one or more lines are too long

807
node_modules/mathjax-full/ts/input/mathml/mml3/mml3.ts generated vendored Normal file
View File

@@ -0,0 +1,807 @@
/*************************************************************
*
* Copyright (c) 2021-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the elementary MathML3 support (experimental)
* using David Carlisle's XLST transform.
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {MathItem} from '../../../core/MathItem.js';
import {MathDocument} from '../../../core/MathDocument.js';
import {Handler} from '../../../core/Handler.js';
import {OptionList} from '../../../util/Options.js';
import {createTransform} from './mml3-node.js';
import {MathML} from '../../mathml.js';
/**
* The data for a MathML prefilter.
*
* @template N The HTMLElement node class
* @template T The Text node class
* @template D The Document class
*/
export type FILTERDATA<N, T, D> = {math: MathItem<N, T, D>, document: MathDocument<N, T, D>, data: N};
/**
* Class that handles XSLT transform for MathML3 elementary math tags.
*/
export class Mml3<N, T, D> {
/**
* The XSLT transform as a string;
*/
public static XSLT: string; // added below (it is huge)
/**
* The function to convert serialized MathML using the XSLT.
* (Different for browser and node environments.)
*/
protected transform: (node: N, doc: MathDocument<N, T, D>) => N;
/**
* @param {MathDocument} document The MathDocument for the transformation
* @constructor
*/
constructor(document: MathDocument<N, T, D>) {
if (typeof XSLTProcessor === 'undefined') {
//
// For Node, get the trasnform from the external module
//
this.transform = createTransform();
} else {
//
// For in-browser use, use the browser's XSLTProcessor
//
const processor = new XSLTProcessor();
const parsed = document.adaptor.parse(Mml3.XSLT, 'text/xml') as any as Node;
processor.importStylesheet(parsed);
this.transform = (node: N) => {
const adaptor = document.adaptor;
const div = adaptor.node('div', {}, [adaptor.clone(node)]);
const mml = processor.transformToDocument(div as any as Node) as any as N;
return adaptor.tags(mml, 'math')[0];
};
}
}
/**
* The mathml filter for the MathML input jax
*
* @param {FILTERDATA} args The data from the pre-filter chain.
*/
public mmlFilter(args: FILTERDATA<N, T, D>) {
if (args.document.options.enableMml3) {
args.data = this.transform(args.data, args.document);
}
}
}
/**
* Add Mml3 support into the handler.
*/
export function Mml3Handler<N, T, D>(handler: Handler<N, T, D>): Handler<N, T, D> {
handler.documentClass = class extends handler.documentClass {
/**
* @override
*/
public static OPTIONS: OptionList = {
...handler.documentClass.OPTIONS,
enableMml3: true,
};
/**
* Add a prefilter to the MathML input jax, if there is one.
*
* @override
* @constructor
*/
constructor(...args: any[]) {
super(...args);
for (const jax of this.inputJax || []) {
if (jax.name === 'MathML') {
if (!jax.options._mml3) { // prevent filter being added twice (e.g., when a11y tools load)
const mml3 = new Mml3(this);
(jax as MathML<N, T, D>).mmlFilters.add(mml3.mmlFilter.bind(mml3));
jax.options._mml3 = true;
}
break;
}
}
}
};
return handler;
}
//
// The actual XSLT transform
//
Mml3.XSLT = `
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:m="http://www.w3.org/1998/Math/MathML"
xmlns:c="http://exslt.org/common"
exclude-result-prefixes="m c">
<xsl:output indent="yes" omit-xml-declaration="yes"/>
<xsl:output indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="m:*[@dir='rtl']" priority="10">
<xsl:apply-templates mode="rtl" select="."/>
</xsl:template>
<xsl:template match="@*" mode="rtl">
<xsl:copy-of select="."/>
<xsl:attribute name="dir">ltr</xsl:attribute>
</xsl:template>
<xsl:template match="*" mode="rtl">
<xsl:copy>
<xsl:apply-templates select="@*" mode="rtl"/>
<xsl:for-each select="node()">
<xsl:sort data-type="number" order="descending" select="position()"/>
<xsl:text> </xsl:text>
<xsl:apply-templates mode="rtl" select="."/>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="@open" mode="rtl">
<xsl:attribute name="close"><xsl:value-of select="."/></xsl:attribute>
</xsl:template>
<xsl:template match="@open[.='(']" mode="rtl">
<xsl:attribute name="close">)</xsl:attribute>
</xsl:template>
<xsl:template match="@open[.=')']" mode="rtl">
<xsl:attribute name="close">(</xsl:attribute>
</xsl:template>
<xsl:template match="@open[.='[']" mode="rtl">
<xsl:attribute name="close">]</xsl:attribute>
</xsl:template>
<xsl:template match="@open[.=']']" mode="rtl">
<xsl:attribute name="close">[</xsl:attribute>
</xsl:template>
<xsl:template match="@open[.='{']" mode="rtl">
<xsl:attribute name="close">}</xsl:attribute>
</xsl:template>
<xsl:template match="@open[.='}']" mode="rtl">
<xsl:attribute name="close">{</xsl:attribute>
</xsl:template>
<xsl:template match="@close" mode="rtl">
<xsl:attribute name="open"><xsl:value-of select="."/></xsl:attribute>
</xsl:template>
<xsl:template match="@close[.='(']" mode="rtl">
<xsl:attribute name="open">)</xsl:attribute>
</xsl:template>
<xsl:template match="@close[.=')']" mode="rtl">
<xsl:attribute name="open">(</xsl:attribute>
</xsl:template>
<xsl:template match="@close[.='[']" mode="rtl">
<xsl:attribute name="open">]</xsl:attribute>
</xsl:template>
<xsl:template match="@close[.=']']" mode="rtl">
<xsl:attribute name="open">[</xsl:attribute>
</xsl:template>
<xsl:template match="@close[.='{']" mode="rtl">
<xsl:attribute name="open">}</xsl:attribute>
</xsl:template>
<xsl:template match="@close[.='}']" mode="rtl">
<xsl:attribute name="open">{</xsl:attribute>
</xsl:template>
<xsl:template match="m:mfrac[@bevelled='true']" mode="rtl">
<m:mrow>
<m:msub><m:mi></m:mi><xsl:apply-templates select="*[2]" mode="rtl"/></m:msub>
<m:mo>&#x5c;</m:mo>
<m:msup><m:mi></m:mi><xsl:apply-templates select="*[1]" mode="rtl"/></m:msup>
</m:mrow>
</xsl:template>
<xsl:template match="m:mfrac" mode="rtl">
<xsl:copy>
<xsl:apply-templates mode="rtl" select="@*|*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="m:mroot" mode="rtl">
<m:msup>
<m:menclose notation="top right">
<xsl:apply-templates mode="rtl" select="@*|*[1]"/>
</m:menclose>
<xsl:apply-templates mode="rtl" select="*[2]"/>
</m:msup>
</xsl:template>
<xsl:template match="m:msqrt" mode="rtl">
<m:menclose notation="top right">
<xsl:apply-templates mode="rtl" select="@*|*[1]"/>
</m:menclose>
</xsl:template>
<xsl:template match="m:mtable|m:munder|m:mover|m:munderover" mode="rtl" priority="2">
<xsl:copy>
<xsl:apply-templates select="@*" mode="rtl"/>
<xsl:apply-templates mode="rtl">
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="m:msup" mode="rtl" priority="2">
<m:mmultiscripts>
<xsl:apply-templates select="*[1]" mode="rtl"/>
<m:mprescripts/>
<m:none/>
<xsl:apply-templates select="*[2]" mode="rtl"/>
</m:mmultiscripts>
</xsl:template>
<xsl:template match="m:msub" mode="rtl" priority="2">
<m:mmultiscripts>
<xsl:apply-templates select="*[1]" mode="rtl"/>
<m:mprescripts/>
<xsl:apply-templates select="*[2]" mode="rtl"/>
<m:none/>
</m:mmultiscripts>
</xsl:template>
<xsl:template match="m:msubsup" mode="rtl" priority="2">
<m:mmultiscripts>
<xsl:apply-templates select="*[1]" mode="rtl"/>
<m:mprescripts/>
<xsl:apply-templates select="*[2]" mode="rtl"/>
<xsl:apply-templates select="*[3]" mode="rtl"/>
</m:mmultiscripts>
</xsl:template>
<xsl:template match="m:mmultiscripts" mode="rtl" priority="2">
<m:mmultiscripts>
<xsl:apply-templates select="*[1]" mode="rtl"/>
<xsl:for-each select="m:mprescripts/following-sibling::*[position() mod 2 = 1]">
<xsl:sort data-type="number" order="descending" select="position()"/>
<xsl:apply-templates select="." mode="rtl"/>
<xsl:apply-templates select="following-sibling::*[1]" mode="rtl"/>
</xsl:for-each>
<m:mprescripts/>
<xsl:for-each select="m:mprescripts/preceding-sibling::*[position()!=last()][position() mod 2 = 0]">
<xsl:sort data-type="number" order="descending" select="position()"/>
<xsl:apply-templates select="." mode="rtl"/>
<xsl:apply-templates select="following-sibling::*[1]" mode="rtl"/>
</xsl:for-each>
</m:mmultiscripts>
</xsl:template>
<xsl:template match="m:mmultiscripts[not(m:mprescripts)]" mode="rtl" priority="3">
<m:mmultiscripts>
<xsl:apply-templates select="*[1]" mode="rtl"/>
<m:mprescripts/>
<xsl:for-each select="*[position() mod 2 = 0]">
<xsl:sort data-type="number" order="descending" select="position()"/>
<xsl:apply-templates select="." mode="rtl"/>
<xsl:apply-templates select="following-sibling::*[1]" mode="rtl"/>
</xsl:for-each>
</m:mmultiscripts>
</xsl:template>
<xsl:template match="text()[.='(']" mode="rtl">)</xsl:template>
<xsl:template match="text()[.=')']" mode="rtl">(</xsl:template>
<xsl:template match="text()[.='{']" mode="rtl">}</xsl:template>
<xsl:template match="text()[.='}']" mode="rtl">{</xsl:template>
<xsl:template match="text()[.='&lt;']" mode="rtl">&gt;</xsl:template>
<xsl:template match="text()[.='&gt;']" mode="rtl">&lt;</xsl:template>
<xsl:template match="text()[.='&#x2208;']" mode="rtl">&#x220b;</xsl:template>
<xsl:template match="text()[.='&#x220b;']" mode="rtl">&#x2208;</xsl:template>
<xsl:template match="@notation[.='radical']" mode="rtl">
<xsl:attribute name="notation">top right</xsl:attribute>
</xsl:template>
<xsl:template match="m:mlongdiv|m:mstack" mode="rtl">
<m:mrow dir="ltr">
<xsl:apply-templates select="."/>
</m:mrow>
</xsl:template>
<xsl:template match="m:mstack" priority="11">
<xsl:variable name="m">
<m:mtable columnspacing="0em" rowspacing="0em">
<xsl:copy-of select="@align"/>
<xsl:variable name="t">
<xsl:apply-templates select="*" mode="mstack1">
<xsl:with-param name="p" select="0"/>
</xsl:apply-templates>
</xsl:variable>
<xsl:variable name="maxl">
<xsl:for-each select="c:node-set($t)/*/@l">
<xsl:sort data-type="number" order="descending"/>
<xsl:if test="position()=1">
<xsl:value-of select="."/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:for-each select="c:node-set($t)/*[not(@class='mscarries') or following-sibling::*[1]/@class='mscarries']">
<xsl:variable name="c" select="preceding-sibling::*[1][@class='mscarries']"/>
<xsl:text>&#10;</xsl:text>
<m:mtr>
<xsl:copy-of select="@class[.='msline']"/>
<xsl:variable name="offset" select="$maxl - @l"/>
<xsl:choose>
<xsl:when test="@class='msline' and @l='*'">
<xsl:variable name="msl" select="*[1]"/>
<xsl:for-each select="(//node())[position()&lt;=$maxl]">
<xsl:copy-of select="$msl"/>
</xsl:for-each>
</xsl:when>
<xsl:when test="$c">
<xsl:variable name="ldiff" select="$c/@l - @l"/>
<xsl:variable name="loffset" select="$maxl - $c/@l"/>
<xsl:for-each select="(//*)[position()&lt;= $offset]">
<xsl:variable name="pn" select="position()"/>
<xsl:variable name="cy" select="$c/*[position()=$pn - $loffset]"/>
<m:mtd>
<xsl:if test="$cy/*">
<m:mover><m:mphantom><m:mn>0</m:mn></m:mphantom><m:mpadded width="0em" lspace="-0.5width">
<xsl:copy-of select="$cy/*"/></m:mpadded></m:mover>
</xsl:if>
</m:mtd>
</xsl:for-each>
<xsl:for-each select="*">
<xsl:variable name="pn" select="position()"/>
<xsl:variable name="cy" select="$c/*[position()=$pn + $ldiff]"/>
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:variable name="b">
<xsl:choose>
<xsl:when test="not(string($cy/@crossout) or $cy/@crossout='none')"><xsl:copy-of select="*"/></xsl:when>
<xsl:otherwise>
<m:menclose notation="{$cy/@crossout}"><xsl:copy-of select="*"/></m:menclose>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<xsl:when test="$cy/m:none or not($cy/*)"><xsl:copy-of select="$b"/></xsl:when>
<xsl:when test="not(string($cy/@location)) or $cy/@location='n'">
<m:mover>
<xsl:copy-of select="$b"/><m:mpadded width="0em" lspace="-0.5width">
<xsl:copy-of select="$cy/*"/>
</m:mpadded>
</m:mover>
</xsl:when>
<xsl:when test="$cy/@location='nw'">
<m:mmultiscripts><xsl:copy-of select="$b"/><m:mprescripts/><m:none/><m:mpadded lspace="-1width" width="0em"><xsl:copy-of select="$cy/*"/></m:mpadded></m:mmultiscripts>
</xsl:when>
<xsl:when test="$cy/@location='s'">
<m:munder><xsl:copy-of select="$b"/><m:mpadded width="0em" lspace="-0.5width"><xsl:copy-of select="$cy/*"/></m:mpadded></m:munder>
</xsl:when>
<xsl:when test="$cy/@location='sw'">
<m:mmultiscripts><xsl:copy-of select="$b"/><m:mprescripts/><m:mpadded lspace="-1width" width="0em"><xsl:copy-of select="$cy/*"/></m:mpadded><m:none/></m:mmultiscripts>
</xsl:when>
<xsl:when test="$cy/@location='ne'">
<m:msup><xsl:copy-of select="$b"/><m:mpadded width="0em"><xsl:copy-of select="$cy/*"/></m:mpadded></m:msup>
</xsl:when>
<xsl:when test="$cy/@location='se'">
<m:msub><xsl:copy-of select="$b"/><m:mpadded width="0em"><xsl:copy-of select="$cy/*"/></m:mpadded></m:msub>
</xsl:when>
<xsl:when test="$cy/@location='w'">
<m:msup><m:mrow/><m:mpadded lspace="-1width" width="0em"><xsl:copy-of select="$cy/*"/></m:mpadded></m:msup>
<xsl:copy-of select="$b"/>
</xsl:when>
<xsl:when test="$cy/@location='e'">
<xsl:copy-of select="$b"/>
<m:msup><m:mrow/><m:mpadded width="0em"><xsl:copy-of select="$cy/*"/></m:mpadded></m:msup>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$b"/>
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:for-each select="(//*)[position()&lt;= $offset]"><m:mtd/></xsl:for-each>
<xsl:copy-of select="*"/>
</xsl:otherwise>
</xsl:choose>
</m:mtr>
</xsl:for-each>
</m:mtable>
</xsl:variable>
<xsl:apply-templates mode="ml" select="c:node-set($m)"/>
</xsl:template>
<xsl:template match="m:none" mode="ml">
<m:mrow/>
</xsl:template>
<xsl:template match="*" mode="ml">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates mode="ml"/>
</xsl:copy>
</xsl:template>
<xsl:template mode="ml" match="m:mtr[following-sibling::*[1][@class='msline']]">
<m:mtr>
<xsl:copy-of select="@*"/>
<xsl:variable name="m" select="following-sibling::*[1]/m:mtd"/>
<xsl:for-each select="m:mtd">
<xsl:variable name="p" select="position()"/>
<m:mtd>
<xsl:copy-of select="@*"/>
<xsl:choose>
<xsl:when test="$m[$p]/m:mpadded">
<m:mpadded depth="+.2em">
<m:menclose notation="bottom">
<m:mpadded depth=".1em" height=".8em" width=".8em">
<m:mspace width=".15em"/>
<xsl:copy-of select="*"/>
</m:mpadded>
</m:menclose>
</m:mpadded>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="*"/>
</xsl:otherwise>
</xsl:choose>
</m:mtd>
</xsl:for-each>
</m:mtr>
</xsl:template>
<xsl:template mode="ml" match="m:mtr[not(preceding-sibling::*)][@class='msline']" priority="3">
<m:mtr>
<xsl:copy-of select="@*"/>
<xsl:for-each select="m:mtd">
<m:mtd>
<xsl:copy-of select="@*"/>
<xsl:if test="m:mpadded">
<m:menclose notation="bottom">
<m:mpadded depth=".1em" height="1em" width=".5em">
<m:mspace width=".2em"/>
</m:mpadded>
</m:menclose>
</xsl:if>
</m:mtd>
</xsl:for-each>
</m:mtr>
</xsl:template>
<xsl:template mode="ml" match="m:mtr[@class='msline']" priority="2"/>
<xsl:template mode="mstack1" match="*">
<xsl:param name="p"/>
<xsl:param name="maxl" select="0"/>
<m:mtr l="{1 + $p}">
<xsl:if test="ancestor::mstack[1]/@stackalign='left'">
<xsl:attribute name="l"><xsl:value-of select="$p"/></xsl:attribute>
</xsl:if>
<m:mtd><xsl:apply-templates select="."/></m:mtd>
</m:mtr>
</xsl:template>
<xsl:template mode="mstack1" match="m:msrow">
<xsl:param name="p"/>
<xsl:param name="maxl" select="0"/>
<xsl:variable name="align1" select="ancestor::m:mstack[1]/@stackalign"/>
<xsl:variable name="align">
<xsl:choose>
<xsl:when test="string($align1)=''">decimalpoint</xsl:when>
<xsl:otherwise><xsl:value-of select="$align1"/></xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="row">
<xsl:apply-templates mode="mstack1" select="*">
<xsl:with-param name="p" select="0"/>
</xsl:apply-templates>
</xsl:variable>
<xsl:text>&#10;</xsl:text>
<xsl:variable name="l1">
<xsl:choose>
<xsl:when test="$align='decimalpoint' and m:mn">
<xsl:for-each select="c:node-set($row)/m:mtr[m:mtd/m:mn][1]">
<xsl:value-of select="number(sum(@l))+count(preceding-sibling::*/@l)"/>
</xsl:for-each>
</xsl:when>
<xsl:when test="$align='right' or $align='decimalpoint'">
<xsl:value-of select="count(c:node-set($row)/m:mtr/m:mtd)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="0"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<m:mtr class="msrow" l="{number($l1) + number(sum(@position)) +$p}">
<xsl:copy-of select="c:node-set($row)/m:mtr/*"/>
</m:mtr>
</xsl:template>
<xsl:template mode="mstack1" match="m:mn">
<xsl:param name="p"/>
<xsl:variable name="align1" select="ancestor::m:mstack[1]/@stackalign"/>
<xsl:variable name="dp1" select="ancestor::*[@decimalpoint][1]/@decimalpoint"/>
<xsl:variable name="align">
<xsl:choose>
<xsl:when test="string($align1)=''">decimalpoint</xsl:when>
<xsl:otherwise><xsl:value-of select="$align1"/></xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="dp">
<xsl:choose>
<xsl:when test="string($dp1)=''">.</xsl:when>
<xsl:otherwise><xsl:value-of select="$dp1"/></xsl:otherwise>
</xsl:choose>
</xsl:variable>
<m:mtr l="$p">
<xsl:variable name="mn" select="normalize-space(.)"/>
<xsl:variable name="len" select="string-length($mn)"/>
<xsl:choose>
<xsl:when test="$align='right' or ($align='decimalpoint' and not(contains($mn,$dp)))">
<xsl:attribute name="l"><xsl:value-of select="$p + $len"/></xsl:attribute>
</xsl:when>
<xsl:when test="$align='center'">
<xsl:attribute name="l"><xsl:value-of select="round(($p + $len) div 2)"/></xsl:attribute>
</xsl:when>
<xsl:when test="$align='decimalpoint'">
<xsl:attribute name="l"><xsl:value-of select="$p + string-length(substring-before($mn,$dp))"/></xsl:attribute>
</xsl:when>
</xsl:choose>
<xsl:for-each select="(//node())[position() &lt;=$len]">
<xsl:variable name="pos" select="position()"/>
<xsl:variable name="digit" select="substring($mn,$pos,1)"/>
<m:mtd>
<xsl:if test="$digit='.' or $digit=','">
<m:mspace width=".15em"/>
</xsl:if>
<m:mn><xsl:value-of select="$digit"/></m:mn>
</m:mtd>
</xsl:for-each>
</m:mtr>
</xsl:template>
<xsl:template match="m:msgroup" mode="mstack1">
<xsl:param name="p"/>
<xsl:variable name="s" select="number(sum(@shift))"/>
<xsl:variable name="thisp" select="number(sum(@position))"/>
<xsl:for-each select="*">
<xsl:apply-templates mode="mstack1" select=".">
<xsl:with-param name="p" select="number($p)+$thisp+(position()-1)*$s"/>
</xsl:apply-templates>
</xsl:for-each>
</xsl:template>
<xsl:template match="m:msline" mode="mstack1">
<xsl:param name="p"/>
<xsl:variable name="align1" select="ancestor::m:mstack[1]/@stackalign"/>
<xsl:variable name="align">
<xsl:choose>
<xsl:when test="string($align1)=''">decimalpoint</xsl:when>
<xsl:otherwise><xsl:value-of select="$align1"/></xsl:otherwise>
</xsl:choose>
</xsl:variable>
<m:mtr class="msline">
<xsl:attribute name="l">
<xsl:choose>
<xsl:when test="not(string(@length)) or @length=0">*</xsl:when>
<xsl:when test="string($align)='right' or string($align)='decimalpoint' "><xsl:value-of select="$p+ @length"/></xsl:when>
<xsl:otherwise><xsl:value-of select="$p"/></xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:variable name="w">
<xsl:choose>
<xsl:when test="@mslinethickness='thin'">0.1em</xsl:when>
<xsl:when test="@mslinethickness='medium'">0.15em</xsl:when>
<xsl:when test="@mslinethickness='thick'">0.2em</xsl:when>
<xsl:when test="@mslinethickness"><xsl:value-of select="@mslinethickness"/></xsl:when>
<xsl:otherwise>0.15em</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<xsl:when test="not(string(@length)) or @length=0">
<m:mtd class="mslinemax">
<m:mpadded lspace="-0.2em" width="0em" height="0em">
<m:mfrac linethickness="{$w}">
<m:mspace width=".5em"/>
<m:mrow/>
</m:mfrac>
</m:mpadded>
</m:mtd>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="l" select="@length"/>
<xsl:for-each select="(//node())[position()&lt;=$l]">
<m:mtd class="msline">
<m:mpadded lspace="-0.2em" width="0em" height="0em">
<m:mfrac linethickness="{$w}">
<m:mspace width=".5em"/>
<m:mrow/>
</m:mfrac>
</m:mpadded>
</m:mtd>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</m:mtr>
</xsl:template>
<xsl:template match="m:mscarries" mode="mstack1">
<xsl:param name="p"/>
<xsl:variable name="align1" select="ancestor::m:mstack[1]/@stackalign"/>
<xsl:variable name="l1">
<xsl:choose>
<xsl:when test="string($align1)='left'">0</xsl:when>
<xsl:otherwise><xsl:value-of select="count(*)"/></xsl:otherwise>
</xsl:choose>
</xsl:variable>
<m:mtr class="mscarries" l="{$p + $l1 + sum(@position)}">
<xsl:apply-templates select="*" mode="msc"/>
</m:mtr>
</xsl:template>
<xsl:template match="*" mode="msc">
<m:mtd>
<xsl:copy-of select="../@location|../@crossout"/>
<xsl:choose>
<xsl:when test="../@scriptsizemultiplier">
<m:mstyle mathsize="{round(../@scriptsizemultiplier div .007)}%">
<xsl:apply-templates select="."/>
</m:mstyle>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="."/>
</xsl:otherwise>
</xsl:choose>
</m:mtd>
</xsl:template>
<xsl:template match="m:mscarry" mode="msc">
<m:mtd>
<xsl:copy-of select="@location|@crossout"/>
<xsl:choose>
<xsl:when test="../@scriptsizemultiplier">
<m:mstyle mathsize="{round(../@scriptsizemultiplier div .007)}%">
<xsl:apply-templates/>
</m:mstyle>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates/>
</xsl:otherwise>
</xsl:choose>
</m:mtd>
</xsl:template>
<xsl:template match="m:mlongdiv" priority="11">
<xsl:variable name="ms">
<m:mstack>
<xsl:copy-of select="(ancestor-or-self::*/@decimalpoint)[last()]"/>
<xsl:choose>
<xsl:when test="@longdivstyle='left)(right'">
<m:msrow>
<m:mrow><xsl:copy-of select="*[1]"/></m:mrow>
<m:mo>)</m:mo>
<xsl:copy-of select="*[3]"/>
<m:mo>(</m:mo>
<xsl:copy-of select="*[2]"/>
</m:msrow>
</xsl:when>
<xsl:when test="@longdivstyle='left/\right'">
<m:msrow>
<m:mrow><xsl:copy-of select="*[1]"/></m:mrow>
<m:mo>/</m:mo>
<xsl:copy-of select="*[3]"/>
<m:mo>\</m:mo>
<xsl:copy-of select="*[2]"/>
</m:msrow>
</xsl:when>
<xsl:when test="@longdivstyle=':right=right'">
<m:msrow>
<xsl:copy-of select="*[3]"/>
<m:mo>:</m:mo>
<xsl:copy-of select="*[1]"/>
<m:mo>=</m:mo>
<xsl:copy-of select="*[2]"/>
</m:msrow>
</xsl:when>
<xsl:when test="@longdivstyle='stackedrightright'
or @longdivstyle='mediumstackedrightright'
or @longdivstyle='shortstackedrightright'
or @longdivstyle='stackedleftleft'
">
<xsl:attribute name="align">top</xsl:attribute>
<xsl:copy-of select="*[3]"/>
</xsl:when>
<xsl:when test="@longdivstyle='stackedleftlinetop'">
<xsl:copy-of select="*[2]"/>
<m:msline length="{string-length(*[3])}"/>
<m:msrow>
<m:mrow>
<m:menclose notation="bottom right">
<xsl:copy-of select="*[1]"/>
</m:menclose>
</m:mrow>
<xsl:copy-of select="*[3]"/>
</m:msrow>
</xsl:when>
<xsl:when test="@longdivstyle='righttop'">
<xsl:copy-of select="*[2]"/>
<m:msline length="{string-length(*[3])}"/>
<m:msrow>
<xsl:copy-of select="*[3]"/>
<m:menclose notation="top left bottom">
<xsl:copy-of select="*[1]"/></m:menclose>
</m:msrow>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="*[2]"/>
<m:msline length="{string-length(*[3])+1}"/>
<m:msrow>
<m:mrow><xsl:copy-of select="*[1]"/><m:mspace width=".2em"/></m:mrow>
<m:mpadded voffset=".1em" lspace="-.15em" depth="-.2em" height="-.2em">
<m:mo minsize="1.2em">)</m:mo>
</m:mpadded>
<xsl:copy-of select="*[3]"/>
</m:msrow>
</xsl:otherwise>
</xsl:choose>
<xsl:copy-of select="*[position()&gt;3]"/>
</m:mstack>
</xsl:variable>
<xsl:choose>
<xsl:when test="@longdivstyle='stackedrightright'">
<m:menclose notation="right">
<xsl:apply-templates select="c:node-set($ms)"/>
</m:menclose>
<m:mtable align="top">
<m:mtr>
<m:menclose notation="bottom">
<xsl:copy-of select="*[1]"/>
</m:menclose>
</m:mtr>
<m:mtr>
<mtd><xsl:copy-of select="*[2]"/></mtd>
</m:mtr>
</m:mtable>
</xsl:when>
<xsl:when test="@longdivstyle='mediumstackedrightright'">
<xsl:apply-templates select="c:node-set($ms)"/>
<m:menclose notation="left">
<m:mtable align="top">
<m:mtr>
<m:menclose notation="bottom">
<xsl:copy-of select="*[1]"/>
</m:menclose>
</m:mtr>
<m:mtr>
<mtd><xsl:copy-of select="*[2]"/></mtd>
</m:mtr>
</m:mtable>
</m:menclose>
</xsl:when>
<xsl:when test="@longdivstyle='shortstackedrightright'">
<xsl:apply-templates select="c:node-set($ms)"/>
<m:mtable align="top">
<m:mtr>
<m:menclose notation="left bottom">
<xsl:copy-of select="*[1]"/>
</m:menclose>
</m:mtr>
<m:mtr>
<mtd><xsl:copy-of select="*[2]"/></mtd>
</m:mtr>
</m:mtable>
</xsl:when>
<xsl:when test="@longdivstyle='stackedleftleft'">
<m:mtable align="top">
<m:mtr>
<m:menclose notation="bottom">
<xsl:copy-of select="*[1]"/>
</m:menclose>
</m:mtr>
<m:mtr>
<mtd><xsl:copy-of select="*[2]"/></mtd>
</m:mtr>
</m:mtable>
<m:menclose notation="left">
<xsl:apply-templates select="c:node-set($ms)"/>
</m:menclose>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="c:node-set($ms)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="m:menclose[@notation='madruwb']" mode="rtl">
<m:menclose notation="bottom right">
<xsl:apply-templates mode="rtl"/>
</m:menclose>
</xsl:template>
</xsl:stylesheet>
`;

232
node_modules/mathjax-full/ts/input/tex.ts generated vendored Normal file
View File

@@ -0,0 +1,232 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the TeX InputJax object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AbstractInputJax} from '../core/InputJax.js';
import {userOptions, separateOptions, OptionList} from '../util/Options.js';
import {MathDocument} from '../core/MathDocument.js';
import {MathItem} from '../core/MathItem.js';
import {MmlNode} from '../core/MmlTree/MmlNode.js';
import {MmlFactory} from '../core/MmlTree/MmlFactory.js';
import {FindTeX} from './tex/FindTeX.js';
import FilterUtil from './tex/FilterUtil.js';
import NodeUtil from './tex/NodeUtil.js';
import TexParser from './tex/TexParser.js';
import TexError from './tex/TexError.js';
import ParseOptions from './tex/ParseOptions.js';
import {TagsFactory} from './tex/Tags.js';
import {ParserConfiguration} from './tex/Configuration.js';
// Import base as it is the default package loaded.
import './tex/base/BaseConfiguration.js';
/*****************************************************************/
/*
* Implements the TeX class (extends AbstractInputJax)
*/
/**
* @template N The HTMLElement node class
* @template T The Text node class
* @template D The Document class
*/
export class TeX<N, T, D> extends AbstractInputJax<N, T, D> {
/**
* Name of input jax.
* @type {string}
*/
public static NAME: string = 'TeX';
/**
* Default options for the jax.
* @type {OptionList}
*/
public static OPTIONS: OptionList = {
...AbstractInputJax.OPTIONS,
FindTeX: null,
packages: ['base'],
// Digit pattern to match numbers.
digits: /^(?:[0-9]+(?:\{,\}[0-9]{3})*(?:\.[0-9]*)?|\.[0-9]+)/,
// Maximum size of TeX string to process.
maxBuffer: 5 * 1024,
formatError: (jax: TeX<any, any, any>, err: TexError) => jax.formatError(err)
};
/**
* The FindTeX instance used for locating TeX in strings
*/
protected findTeX: FindTeX<N, T, D>;
/**
* The configuration of the TeX jax.
* @type {ParserConfiguration}
*/
protected configuration: ParserConfiguration;
/**
* The LaTeX code that is parsed.
* @type {string}
*/
protected latex: string;
/**
* The Math node that results from parsing.
* @type {MmlNode}
*/
protected mathNode: MmlNode;
private _parseOptions: ParseOptions;
/**
* Initialises the configurations.
* @param {string[]} packages Names of packages.
* @return {Configuration} The configuration object.
*/
protected static configure(packages: (string | [string, number])[]): ParserConfiguration {
let configuration = new ParserConfiguration(packages, ['tex']);
configuration.init();
return configuration;
}
/**
* Initialises the Tags factory. Add tagging structures from packages and set
* tagging to given default.
* @param {ParseOptions} options The parse options.
* @param {Configuration} configuration The configuration.
*/
protected static tags(options: ParseOptions, configuration: ParserConfiguration) {
TagsFactory.addTags(configuration.tags);
TagsFactory.setDefault(options.options.tags);
options.tags = TagsFactory.getDefault();
options.tags.configuration = options;
}
/**
* @override
*/
constructor(options: OptionList = {}) {
const [rest, tex, find] = separateOptions(options, TeX.OPTIONS, FindTeX.OPTIONS);
super(tex);
this.findTeX = this.options['FindTeX'] || new FindTeX(find);
const packages = this.options.packages;
const configuration = this.configuration = TeX.configure(packages);
const parseOptions = this._parseOptions =
new ParseOptions(configuration, [this.options, TagsFactory.OPTIONS]);
userOptions(parseOptions.options, rest);
configuration.config(this);
TeX.tags(parseOptions, configuration);
this.postFilters.add(FilterUtil.cleanSubSup, -6);
this.postFilters.add(FilterUtil.setInherited, -5);
this.postFilters.add(FilterUtil.moveLimits, -4);
this.postFilters.add(FilterUtil.cleanStretchy, -3);
this.postFilters.add(FilterUtil.cleanAttributes, -2);
this.postFilters.add(FilterUtil.combineRelations, -1);
}
/**
* @override
*/
public setMmlFactory(mmlFactory: MmlFactory) {
super.setMmlFactory(mmlFactory);
this._parseOptions.nodeFactory.setMmlFactory(mmlFactory);
}
/**
* @return {ParseOptions} The parse options that configure this JaX instance.
*/
public get parseOptions(): ParseOptions {
return this._parseOptions;
}
/**
* @override
*/
public reset(tag: number = 0) {
this.parseOptions.tags.reset(tag);
}
/**
* @override
*/
public compile(math: MathItem<N, T, D>, document: MathDocument<N, T, D>): MmlNode {
this.parseOptions.clear();
this.executeFilters(this.preFilters, math, document, this.parseOptions);
let display = math.display;
this.latex = math.math;
let node: MmlNode;
this.parseOptions.tags.startEquation(math);
let globalEnv;
try {
let parser = new TexParser(this.latex,
{display: display, isInner: false},
this.parseOptions);
node = parser.mml();
globalEnv = parser.stack.global;
} catch (err) {
if (!(err instanceof TexError)) {
throw err;
}
this.parseOptions.error = true;
node = this.options.formatError(this, err);
}
node = this.parseOptions.nodeFactory.create('node', 'math', [node]);
if (globalEnv?.indentalign) {
NodeUtil.setAttribute(node, 'indentalign', globalEnv.indentalign);
}
if (display) {
NodeUtil.setAttribute(node, 'display', 'block');
}
this.parseOptions.tags.finishEquation(math);
this.parseOptions.root = node;
this.executeFilters(this.postFilters, math, document, this.parseOptions);
this.mathNode = this.parseOptions.root;
return this.mathNode;
}
/**
* @override
*/
public findMath(strings: string[]) {
return this.findTeX.findMath(strings);
}
/**
* Default formatter for error messages:
* wrap an error into a node for output.
* @param {TeXError} err The TexError.
* @return {Node} The merror node.
*/
public formatError(err: TexError): MmlNode {
let message = err.message.replace(/\n.*/, '');
return this.parseOptions.nodeFactory.create(
'error', message, err.id, this.latex);
}
}

127
node_modules/mathjax-full/ts/input/tex/AllPackages.ts generated vendored Normal file
View File

@@ -0,0 +1,127 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Loads all the TeX extensions
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import './base/BaseConfiguration.js';
import './action/ActionConfiguration.js';
import './ams/AmsConfiguration.js';
import './amscd/AmsCdConfiguration.js';
import './bbox/BboxConfiguration.js';
import './boldsymbol/BoldsymbolConfiguration.js';
import './braket/BraketConfiguration.js';
import './bussproofs/BussproofsConfiguration.js';
import './cancel/CancelConfiguration.js';
import './cases/CasesConfiguration.js';
import './centernot/CenternotConfiguration.js';
import './color/ColorConfiguration.js';
import './colorv2/ColorV2Configuration.js';
import './colortbl/ColortblConfiguration.js';
import './configmacros/ConfigMacrosConfiguration.js';
import './empheq/EmpheqConfiguration.js';
import './enclose/EncloseConfiguration.js';
import './extpfeil/ExtpfeilConfiguration.js';
import './gensymb/GensymbConfiguration.js';
import './html/HtmlConfiguration.js';
import './mathtools/MathtoolsConfiguration.js';
import './mhchem/MhchemConfiguration.js';
import './newcommand/NewcommandConfiguration.js';
import './noerrors/NoErrorsConfiguration.js';
import './noundefined/NoUndefinedConfiguration.js';
import './physics/PhysicsConfiguration.js';
import './setoptions/SetOptionsConfiguration.js';
import './tagformat/TagFormatConfiguration.js';
import './textcomp/TextcompConfiguration.js';
import './textmacros/TextMacrosConfiguration.js';
import './upgreek/UpgreekConfiguration.js';
import './unicode/UnicodeConfiguration.js';
import './verb/VerbConfiguration.js';
declare const MathJax: any;
if (typeof MathJax !== 'undefined' && MathJax.loader) {
MathJax.loader.preLoad(
'[tex]/action',
'[tex]/ams',
'[tex]/amscd',
'[tex]/bbox',
'[tex]/boldsymbol',
'[tex]/braket',
'[tex]/bussproofs',
'[tex]/cancel',
'[tex]/cases',
'[tex]/centernot',
'[tex]/color',
'[tex]/colorv2',
'[tex]/colortbl',
'[tex]/empheq',
'[tex]/enclose',
'[tex]/extpfeil',
'[tex]/gensymb',
'[tex]/html',
'[tex]/mathtools',
'[tex]/mhchem',
'[tex]/newcommand',
'[tex]/noerrors',
'[tex]/noundefined',
'[tex]/physics',
'[tex]/upgreek',
'[tex]/unicode',
'[tex]/verb',
'[tex]/configmacros',
'[tex]/tagformat',
'[tex]/textcomp',
'[tex]/textmacros',
'[tex]/setoptions',
);
}
export const AllPackages: string[] = [
'base',
'action',
'ams',
'amscd',
'bbox',
'boldsymbol',
'braket',
'bussproofs',
'cancel',
'cases',
'centernot',
'color',
'colortbl',
'empheq',
'enclose',
'extpfeil',
'gensymb',
'html',
'mathtools',
'mhchem',
'newcommand',
'noerrors',
'noundefined',
'upgreek',
'unicode',
'verb',
'configmacros',
'tagformat',
'textcomp',
'textmacros'
];

418
node_modules/mathjax-full/ts/input/tex/Configuration.ts generated vendored Normal file
View File

@@ -0,0 +1,418 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Configuration options for the TexParser.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {HandlerConfig, FallbackConfig} from './MapHandler.js';
import {StackItemClass} from './StackItem.js';
import {TagsClass} from './Tags.js';
import {userOptions, defaultOptions, OptionList} from '../../util/Options.js';
import {SubHandlers} from './MapHandler.js';
import {FunctionList} from '../../util/FunctionList.js';
import {TeX} from '../tex.js';
import {PrioritizedList} from '../../util/PrioritizedList.js';
import {TagsFactory} from './Tags.js';
export type StackItemConfig = {[kind: string]: StackItemClass};
export type TagsConfig = {[kind: string]: TagsClass};
export type Processor<T> = [T, number];
export type ProtoProcessor<T> = Processor<T> | T;
export type ProcessorList = Processor<Function>[];
export type ConfigMethod = (c: ParserConfiguration, j: TeX<any, any, any>) => void;
export type InitMethod = (c: ParserConfiguration) => void;
export class Configuration {
/**
* Creates a function priority pair.
* @param {ProtoProcessor<T>} func The function or processor.
* @param {number} priority The default priority.
* @return {Processor} The processor pair.
* @template T
*/
private static makeProcessor<T>(func: ProtoProcessor<T>, priority: number): Processor<T> {
return Array.isArray(func) ? func : [func, priority];
}
/**
* Creates a configuration for a package.
* @param {string} name The package name or empty string.
* @param {Object} config See `create` method.
* @return {Configuration} The newly generated configuration.
*/
private static _create(name: string,
config: {handler?: HandlerConfig,
fallback?: FallbackConfig,
items?: StackItemConfig,
tags?: TagsConfig,
options?: OptionList,
nodes?: {[key: string]: any},
preprocessors?: ProtoProcessor<Function>[],
postprocessors?: ProtoProcessor<Function>[],
init?: ProtoProcessor<InitMethod>,
config?: ProtoProcessor<ConfigMethod>,
priority?: number,
parser?: string,
} = {}): Configuration {
let priority = config.priority || PrioritizedList.DEFAULTPRIORITY;
let init = config.init ? this.makeProcessor(config.init, priority) : null;
let conf = config.config ? this.makeProcessor(config.config, priority) : null;
let preprocessors = (config.preprocessors || []).map(
pre => this.makeProcessor(pre, priority));
let postprocessors = (config.postprocessors || []).map(
post => this.makeProcessor(post, priority));
let parser = config.parser || 'tex';
return new Configuration(
name,
config.handler || {},
config.fallback || {},
config.items || {},
config.tags || {},
config.options || {},
config.nodes || {},
preprocessors, postprocessors, init, conf, priority,
parser
);
}
/**
* Creator pattern for creating a named package configuration. This will be
* administered in the configuration handler and can be retrieved again.
* @param {string} name The package name.
* @param {Object} config The configuration parameters:
* Configuration for the TexParser consist of the following:
* * _handler_ configuration mapping handler types to lists of symbol mappings.
* * _fallback_ configuration mapping handler types to fallback methods.
* * _items_ for the StackItem factory.
* * _tags_ mapping tagging configurations to tagging objects.
* * _options_ parse options for the packages.
* * _nodes_ for the Node factory.
* * _preprocessors_ list of functions for preprocessing the LaTeX
* string wrt. to given parse options. Can contain a priority.
* * _postprocessors_ list of functions for postprocessing the MmlNode
* wrt. to given parse options. Can contain a priority.
* * _init_ init method and optionally its priority.
* * _config_ config method and optionally its priority.
* * _priority_ default priority of the configuration.
* * _parser_ the name of the parser that this configuration targets.
* @return {Configuration} The newly generated configuration.
*/
public static create(name: string,
config: {handler?: HandlerConfig,
fallback?: FallbackConfig,
items?: StackItemConfig,
tags?: TagsConfig,
options?: OptionList,
nodes?: {[key: string]: any},
preprocessors?: ProtoProcessor<Function>[],
postprocessors?: ProtoProcessor<Function>[],
init?: ProtoProcessor<InitMethod>,
config?: ProtoProcessor<ConfigMethod>,
priority?: number,
parser?: string,
} = {}): Configuration {
let configuration = Configuration._create(name, config);
ConfigurationHandler.set(name, configuration);
return configuration;
}
/**
* Creates an unnamed, ephemeral package configuration. It will not added to
* the configuration handler.
* @param {Object} config See `create` method.
* @return {Configuration} The ephemeral package configuration.
*/
public static local(config: {handler?: HandlerConfig,
fallback?: FallbackConfig,
items?: StackItemConfig,
tags?: TagsConfig,
options?: OptionList,
nodes?: {[key: string]: any},
preprocessors?: ProtoProcessor<Function>[],
postprocessors?: ProtoProcessor<Function>[],
init?: ProtoProcessor<InitMethod>,
config?: ProtoProcessor<ConfigMethod>,
priority?: number,
parser?: string,
} = {}): Configuration {
return Configuration._create('', config);
}
/**
* @constructor
*/
private constructor(readonly name: string,
readonly handler: HandlerConfig = {},
readonly fallback: FallbackConfig = {},
readonly items: StackItemConfig = {},
readonly tags: TagsConfig = {},
readonly options: OptionList = {},
readonly nodes: {[key: string]: any} = {},
readonly preprocessors: ProcessorList = [],
readonly postprocessors: ProcessorList = [],
readonly initMethod: Processor<InitMethod> = null,
readonly configMethod: Processor<ConfigMethod> = null,
public priority: number,
readonly parser: string
) {
this.handler = Object.assign(
{character: [], delimiter: [], macro: [], environment: []}, handler);
}
/**
* The init method.
* @type {Function}
*/
public get init(): InitMethod {
return this.initMethod ? this.initMethod[0] : null;
}
/**
* The config method to call once jax is ready.
* @type {FunctionList}
*/
public get config(): ConfigMethod {
return this.configMethod ? this.configMethod[0] : null;
}
}
export namespace ConfigurationHandler {
let maps: Map<string, Configuration> = new Map();
/**
* Adds a new configuration to the handler overwriting old ones.
*
* @param {string} name The name of the configuration.
* @param {Configuration} map The configuration mapping.
*/
export let set = function(name: string, map: Configuration): void {
maps.set(name, map);
};
/**
* Looks up a configuration.
*
* @param {string} name The name of the configuration.
* @return {Configuration} The configuration with the given name or null.
*/
export let get = function(name: string): Configuration {
return maps.get(name);
};
/**
* @return {string[]} All configurations in the handler.
*/
export let keys = function(): IterableIterator<string> {
return maps.keys();
};
}
/**
* Parser configuration combines the configurations of the currently selected
* packages.
* @constructor
*/
export class ParserConfiguration {
/**
* Priority list of init methods.
* @type {FunctionList}
*/
protected initMethod: FunctionList = new FunctionList();
/**
* Priority list of init methods to call once jax is ready.
* @type {FunctionList}
*/
protected configMethod: FunctionList = new FunctionList();
/**
* An ordered list of cofigurations.
* @type {PrioritizedList<Configuration>}
*/
protected configurations: PrioritizedList<Configuration> = new PrioritizedList();
/**
* The list of parsers this configuration targets
*/
protected parsers: string[] = [];
/**
* The subhandlers for this configuration.
* @type {SubHandlers}
*/
public handlers: SubHandlers = new SubHandlers();
/**
* The collated stack items.
* @type {StackItemConfig}
*/
public items: StackItemConfig = {};
/**
* The collated tag configurations.
* @type {TagsConfig}
*/
public tags: TagsConfig = {};
/**
* The collated options.
* @type {OptionList}
*/
public options: OptionList = {};
/**
* The collated node creators.
* @type {{[key: string]: any}}
*/
public nodes: {[key: string]: any} = {};
/**
* @constructor
* @param {(string|[string,number])[]} packages A list of packages with
* optional priorities.
* @parm {string[]} parsers The names of the parsers this package targets
*/
constructor(packages: (string | [string, number])[], parsers: string[] = ['tex']) {
this.parsers = parsers;
for (const pkg of packages.slice().reverse()) {
this.addPackage(pkg);
}
for (let {item: config, priority: priority} of this.configurations) {
this.append(config, priority);
}
}
/**
* Init method for the configuration;
*/
public init() {
this.initMethod.execute(this);
}
/**
* Init method for when the jax is ready
* @param {TeX} jax The TeX jax for this configuration
*/
public config(jax: TeX<any, any, any>) {
this.configMethod.execute(this, jax);
for (const config of this.configurations) {
this.addFilters(jax, config.item);
}
}
/**
* Retrieves and adds configuration for a package with priority.
* @param {(string | [string, number]} pkg Package with priority.
*/
public addPackage(pkg: (string | [string, number])) {
const name = typeof pkg === 'string' ? pkg : pkg[0];
const conf = this.getPackage(name);
conf && this.configurations.add(conf, typeof pkg === 'string' ? conf.priority : pkg[1]);
}
/**
* Adds a configuration after the input jax is created. (Used by \require.)
* Sets items, nodes and runs configuration method explicitly.
*
* @param {string} name The name of the package to add
* @param {TeX} jax The TeX jax where it is being registered
* @param {OptionList=} options The options for the configuration.
*/
public add(name: string, jax: TeX<any, any, any>, options: OptionList = {}) {
const config = this.getPackage(name);
this.append(config);
this.configurations.add(config, config.priority);
this.init();
const parser = jax.parseOptions;
parser.nodeFactory.setCreators(config.nodes);
for (const kind of Object.keys(config.items)) {
parser.itemFactory.setNodeClass(kind, config.items[kind]);
}
TagsFactory.addTags(config.tags);
defaultOptions(parser.options, config.options);
userOptions(parser.options, options);
this.addFilters(jax, config);
if (config.config) {
config.config(this, jax);
}
}
/**
* Find a package and check that it is for the targeted parser
*
* @param {string} name The name of the package to check
* @return {Configuration} The configuration for the package
*/
protected getPackage(name: string): Configuration {
const config = ConfigurationHandler.get(name);
if (config && this.parsers.indexOf(config.parser) < 0) {
throw Error(`Package ${name} doesn't target the proper parser`);
}
return config;
}
/**
* Appends a configuration to the overall configuration object.
* @param {Configuration} config A configuration.
* @param {number} priority The configurations optional priority.
*/
public append(config: Configuration, priority?: number) {
priority = priority || config.priority;
if (config.initMethod) {
this.initMethod.add(config.initMethod[0], config.initMethod[1]);
}
if (config.configMethod) {
this.configMethod.add(config.configMethod[0], config.configMethod[1]);
}
this.handlers.add(config.handler, config.fallback, priority);
Object.assign(this.items, config.items);
Object.assign(this.tags, config.tags);
defaultOptions(this.options, config.options);
Object.assign(this.nodes, config.nodes);
}
/**
* Adds pre- and postprocessor as filters to the jax.
* @param {TeX<any} jax The TeX Jax.
* @param {Configuration} config The configuration whose processors are added.
*/
private addFilters(jax: TeX<any, any, any>, config: Configuration) {
for (const [pre, priority] of config.preprocessors) {
jax.preFilters.add(pre, priority);
}
for (const [post, priority] of config.postprocessors) {
jax.postFilters.add(post, priority);
}
}
}

295
node_modules/mathjax-full/ts/input/tex/FilterUtil.ts generated vendored Normal file
View File

@@ -0,0 +1,295 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Utility functions for standard pre and post filters.
*
* @author sorge@mathjax.org (Volker Sorge)
*/
import {TEXCLASS, MMLNODE, MmlNode} from '../../core/MmlTree/MmlNode.js';
import NodeUtil from './NodeUtil.js';
import ParseOptions from './ParseOptions.js';
import {MmlMo} from '../../core/MmlTree/MmlNodes/mo.js';
import {Attributes} from '../../core/MmlTree/Attributes.js';
namespace FilterUtil {
/**
* Visitor to set stretchy attributes to false on <mo> elements, if they are
* not used as delimiters. Also wraps non-stretchy infix delimiters into a
* TeXAtom.
* @param {MmlNode} math The node to rewrite.
* @param {ParseOptions} data The parse options.
*/
export let cleanStretchy = function(arg: {math: any, data: ParseOptions}) {
let options = arg.data;
for (let mo of options.getList('fixStretchy')) {
if (NodeUtil.getProperty(mo, 'fixStretchy')) {
let symbol = NodeUtil.getForm(mo);
if (symbol && symbol[3] && symbol[3]['stretchy']) {
NodeUtil.setAttribute(mo, 'stretchy', false);
}
const parent = mo.parent;
if (!NodeUtil.getTexClass(mo) && (!symbol || !symbol[2])) {
const texAtom = options.nodeFactory.create('node', 'TeXAtom', [mo]);
parent.replaceChild(texAtom, mo);
texAtom.inheritAttributesFrom(mo);
}
NodeUtil.removeProperties(mo, 'fixStretchy');
}
}
};
/**
* Visitor that removes superfluous attributes from nodes. I.e., if a node has
* an attribute, which is also an inherited attribute it will be removed. This
* is necessary as attributes are set bottom up in the parser.
* @param {ParseOptions} data The parse options.
*/
export let cleanAttributes = function(arg: {data: ParseOptions}) {
let node = arg.data.root as MmlNode;
node.walkTree((mml: MmlNode, _d: any) => {
let attribs = mml.attributes as any;
if (!attribs) {
return;
}
const keep = new Set((attribs.get('mjx-keep-attrs') || '').split(/ /));
delete (attribs.getAllAttributes())['mjx-keep-attrs'];
for (const key of attribs.getExplicitNames()) {
if (!keep.has(key) && attribs.attributes[key] === mml.attributes.getInherited(key)) {
delete attribs.attributes[key];
}
}
}, {});
};
/**
* Combine adjacent <mo> elements that are relations (since MathML treats the
* spacing very differently)
* @param {ParseOptions} data The parse options.
*/
export let combineRelations = function(arg: {data: ParseOptions}) {
const remove: MmlNode[] = [];
for (let mo of arg.data.getList('mo')) {
if (mo.getProperty('relationsCombined') || !mo.parent ||
(mo.parent && !NodeUtil.isType(mo.parent, 'mrow')) ||
NodeUtil.getTexClass(mo) !== TEXCLASS.REL) {
// @test Prime, PrimeSup, Named Function
continue;
}
let mml = mo.parent;
let m2: MmlNode;
let children = mml.childNodes as MMLNODE[];
let next = children.indexOf(mo) + 1;
let variantForm = NodeUtil.getProperty(mo, 'variantForm');
while (next < children.length && (m2 = children[next]) &&
NodeUtil.isType(m2, 'mo') &&
NodeUtil.getTexClass(m2) === TEXCLASS.REL) {
if (variantForm === NodeUtil.getProperty(m2, 'variantForm') &&
_compareExplicit(mo, m2)) {
// @test Shift Left, Less Equal,
// Multirel Font X, Multirel Mathvariant X
NodeUtil.appendChildren(mo, NodeUtil.getChildren(m2));
// This treatment means we might loose some inheritance structure, but
// no properties.
_copyExplicit(['stretchy', 'rspace'], mo, m2);
for (const name of m2.getPropertyNames()) {
mo.setProperty(name, m2.getProperty(name));
}
children.splice(next, 1);
remove.push(m2);
m2.parent = null;
m2.setProperty('relationsCombined', true);
} else {
// @test Preset Rspace Lspace
if (mo.attributes.getExplicit('rspace') == null) {
// @test Mulitrel Mathvariant 3, Mulitrel Mathvariant 4
NodeUtil.setAttribute(mo, 'rspace', '0pt');
}
if (m2.attributes.getExplicit('lspace') == null) {
// @test Mulitrel Mathvariant 3, Mulitrel Mathvariant 4
NodeUtil.setAttribute(m2, 'lspace', '0pt');
}
break;
}
}
mo.attributes.setInherited('form', (mo as MmlMo).getForms()[0]);
}
arg.data.removeFromList('mo', remove);
};
/**
* Copies the specified explicit attributes from node2 to node1.
* @param {string[]} attrs List of explicit attribute names.
* @param {MmlNode} node1 The goal node.
* @param {MmlNode} node2 The source node.
*/
let _copyExplicit = function(attrs: string[],
node1: MmlNode, node2: MmlNode) {
let attr1 = node1.attributes;
let attr2 = node2.attributes;
attrs.forEach(x => {
let attr = attr2.getExplicit(x);
if (attr != null) {
// @test Infix Stretchy Right, Preset Lspace Rspace
attr1.set(x, attr);
}
});
};
/**
* Compares the explicit attributes of two nodes. Returns true if they
* coincide, with the following exceptions:
* - lspace attribute of node1 is ignored.
* - rspace attribute of node2 is ignored.
* - stretchy=false attributes are ignored.
* @param {MmlNode} node1 The first node.
* @param {MmlNode} node2 Its next sibling.
*/
let _compareExplicit = function(node1: MmlNode, node2: MmlNode) {
let filter = (attr: Attributes, space: string): string[] => {
let exp = attr.getExplicitNames();
return exp.filter(x => {
return x !== space &&
(x !== 'stretchy' ||
attr.getExplicit('stretchy'));
});
};
let attr1 = node1.attributes;
let attr2 = node2.attributes;
let exp1 = filter(attr1, 'lspace');
let exp2 = filter(attr2, 'rspace');
if (exp1.length !== exp2.length) {
return false;
}
for (let name of exp1) {
if (attr1.getExplicit(name) !== attr2.getExplicit(name)) {
return false;
}
}
return true;
};
/**
* Cleans msubsup and munderover elements.
* @param {ParseOptions} options The parse options.
* @param {string} low String representing the lower part of the expression.
* @param {string} up String representing the upper part.
*/
let _cleanSubSup = function(options: ParseOptions, low: string, up: string) {
const remove: MmlNode[] = [];
for (let mml of options.getList('m' + low + up) as any[]) {
const children = mml.childNodes;
if (children[mml[low]] && children[mml[up]]) {
continue;
}
const parent = mml.parent;
let newNode = (children[mml[low]] ?
options.nodeFactory.create('node', 'm' + low, [children[mml.base], children[mml[low]]]) :
options.nodeFactory.create('node', 'm' + up, [children[mml.base], children[mml[up]]]));
NodeUtil.copyAttributes(mml, newNode);
if (parent) {
parent.replaceChild(newNode, mml);
} else {
options.root = newNode;
}
remove.push(mml);
}
options.removeFromList('m' + low + up, remove);
};
/**
* Visitor that rewrites incomplete msubsup/munderover elements in the given
* node into corresponding msub/sup/under/over nodes.
* @param {MmlNode} math The node to rewrite.
* @param {ParseOptions} data The parse options.
*/
export let cleanSubSup = function(arg: {math: any, data: ParseOptions}) {
let options = arg.data;
if (options.error) {
return;
}
_cleanSubSup(options, 'sub', 'sup');
_cleanSubSup(options, 'under', 'over');
};
/**
* Looks through the list of munderover elements for ones that have
* movablelimits and bases that are not mo's, and creates new msubsup
* elements to replace them if they aren't in displaystyle.
*
* @param {MmlNode} ath The node to rewrite.
* @param {ParseOptions} data The parse options.
*/
let _moveLimits = function (options: ParseOptions, underover: string, subsup: string) {
const remove: MmlNode[] = [];
for (const mml of options.getList(underover)) {
if (mml.attributes.get('displaystyle')) {
continue;
}
const base = mml.childNodes[(mml as any).base] as MmlNode;
const mo = base.coreMO();
if (base.getProperty('movablelimits') && !mo.attributes.getExplicit('movablelimits')) {
let node = options.nodeFactory.create('node', subsup, mml.childNodes);
NodeUtil.copyAttributes(mml, node);
if (mml.parent) {
mml.parent.replaceChild(node, mml);
} else {
options.root = node;
}
remove.push(mml);
}
}
options.removeFromList(underover, remove);
};
/**
* Visitor that rewrites in-line munderover elements with movablelimits but bases
* that are not mo's into explicit msubsup elements.
*
* @param {ParseOptions} data The parse options to use
*/
export let moveLimits = function (arg: {data: ParseOptions}) {
const options = arg.data;
_moveLimits(options, 'munderover', 'msubsup');
_moveLimits(options, 'munder', 'msub');
_moveLimits(options, 'mover', 'msup');
};
/**
* Recursively sets the inherited attributes on the math tree.
* @param {MmlNode} math The node to rewrite.
* @param {ParseOptions} data The parse options.
*/
export let setInherited = function(arg: {math: any, data: ParseOptions}) {
arg.data.root.setInheritedAttributes({}, arg.math['display'], 0, false);
};
}
export default FilterUtil;

241
node_modules/mathjax-full/ts/input/tex/FindTeX.ts generated vendored Normal file
View File

@@ -0,0 +1,241 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implements the TeX version of the FindMath object
*
* @author dpvc@mathjax.org (Davide Cervone)
*/
import {AbstractFindMath} from '../../core/FindMath.js';
import {OptionList} from '../../util/Options.js';
import {sortLength, quotePattern} from '../../util/string.js';
import {ProtoItem, protoItem} from '../../core/MathItem.js';
/**
* Shorthand types for data about end delimiters and delimiter pairs
*/
export type EndItem = [string, boolean, RegExp];
export type Delims = [string, string];
/*****************************************************************/
/*
* Implements the FindTeX class (extends AbstractFindMath)
*
* Locates TeX expressions within strings
*/
/*
* @template N The HTMLElement node class
* @template T The Text node class
* @template D The Document class
*/
export class FindTeX<N, T, D> extends AbstractFindMath<N, T, D> {
/**
* @type {OptionList}
*/
public static OPTIONS: OptionList = {
inlineMath: [ // The start/end delimiter pairs for in-line math
// ['$', '$'], // (comment out any you don't want, or add your own, but
['\\(', '\\)'] // be sure that you don't have an extra comma at the end)
],
displayMath: [ // The start/end delimiter pairs for display math
['$$', '$$'], // (comment out any you don't want, or add your own, but
['\\[', '\\]'] // be sure that you don't have an extra comma at the end)
],
processEscapes: true, // set to true to allow \$ to produce a dollar without
// starting in-line math mode
processEnvironments: true, // set to true to process \begin{xxx}...\end{xxx} outside
// of math mode, false to prevent that
processRefs: true, // set to true to process \ref{...} outside of math mode
};
/**
* The regular expression for any starting delimiter
*/
protected start: RegExp;
/**
* The end-delimiter data keyed to the opening delimiter string
*/
protected end: {[name: string]: EndItem};
/**
* False if the configuration has no delimiters (so search can be skipped), true otherwise
*/
protected hasPatterns: boolean;
/**
* The index of the \begin...\end pattern in the regex match array
*/
protected env: number;
/**
* The index of the \ref and escaped character patters in the regex match array
*/
protected sub: number;
/**
* @override
*/
constructor(options: OptionList) {
super(options);
this.getPatterns();
}
/**
* Create the patterns needed for searching the strings for TeX
* based on the configuration options
*/
protected getPatterns() {
let options = this.options;
let starts: string[] = [], parts: string[] = [], subparts: string[] = [];
this.end = {};
this.env = this.sub = 0;
let i = 1;
options['inlineMath'].forEach((delims: Delims) => this.addPattern(starts, delims, false));
options['displayMath'].forEach((delims: Delims) => this.addPattern(starts, delims, true));
if (starts.length) {
parts.push(starts.sort(sortLength).join('|'));
}
if (options['processEnvironments']) {
parts.push('\\\\begin\\s*\\{([^}]*)\\}');
this.env = i;
i++;
}
if (options['processEscapes']) {
subparts.push('\\\\([\\\\$])');
}
if (options['processRefs']) {
subparts.push('(\\\\(?:eq)?ref\\s*\\{[^}]*\\})');
}
if (subparts.length) {
parts.push('(' + subparts.join('|') + ')');
this.sub = i;
}
this.start = new RegExp(parts.join('|'), 'g');
this.hasPatterns = (parts.length > 0);
}
/**
* Add the needed patterns for a pair of delimiters
*
* @param {string[]} starts Array of starting delimiter strings
* @param {Delims} delims Array of delimiter strings, as [start, end]
* @param {boolean} display True if the delimiters are for display mode
*/
protected addPattern(starts: string[], delims: Delims, display: boolean) {
let [open, close] = delims;
starts.push(quotePattern(open));
this.end[open] = [close, display, this.endPattern(close)];
}
/**
* Create the pattern for a close delimiter
*
* @param {string} end The end delimiter text
* @param {string} endp The end delimiter pattern (overrides the literal end pattern)
* @return {RegExp} The regular expression for the end delimiter
*/
protected endPattern(end: string, endp?: string): RegExp {
return new RegExp((endp || quotePattern(end)) + '|\\\\(?:[a-zA-Z]|.)|[{}]', 'g');
}
/**
* Search for the end delimiter given the start delimiter,
* skipping braced groups, and control sequences that aren't
* the close delimiter.
*
* @param {string} text The string being searched for the end delimiter
* @param {number} n The index of the string being searched
* @param {RegExpExecArray} start The result array from the start-delimiter search
* @param {EndItem} end The end-delimiter data corresponding to the start delimiter
* @return {ProtoItem<N,T>} The proto math item for the math, if found
*/
protected findEnd(text: string, n: number, start: RegExpExecArray, end: EndItem): ProtoItem<N, T> {
let [close, display, pattern] = end;
let i = pattern.lastIndex = start.index + start[0].length;
let match: RegExpExecArray, braces: number = 0;
while ((match = pattern.exec(text))) {
if ((match[1] || match[0]) === close && braces === 0) {
return protoItem<N, T>(start[0], text.substr(i, match.index - i), match[0],
n, start.index, match.index + match[0].length, display);
} else if (match[0] === '{') {
braces++;
} else if (match[0] === '}' && braces) {
braces--;
}
}
return null;
}
/**
* Search a string for math delimited by one of the delimiter pairs,
* or by \begin{env}...\end{env}, or \eqref{...}, \ref{...}, \\, or \$.
*
* @param {ProtoItem[]} math The array of proto math items located so far
* @param {number} n The index of the string being searched
* @param {string} text The string being searched
*/
protected findMathInString(math: ProtoItem<N, T>[], n: number, text: string) {
let start, match;
this.start.lastIndex = 0;
while ((start = this.start.exec(text))) {
if (start[this.env] !== undefined && this.env) {
let end = '\\\\end\\s*(\\{' + quotePattern(start[this.env]) + '\\})';
match = this.findEnd(text, n, start, ['{' + start[this.env] + '}', true, this.endPattern(null, end)]);
if (match) {
match.math = match.open + match.math + match.close;
match.open = match.close = '';
}
} else if (start[this.sub] !== undefined && this.sub) {
let math = start[this.sub];
let end = start.index + start[this.sub].length;
if (math.length === 2) {
match = protoItem<N, T>('', math.substr(1), '', n, start.index, end);
} else {
match = protoItem<N, T>('', math, '', n, start.index, end, false);
}
} else {
match = this.findEnd(text, n, start, this.end[start[0]]);
}
if (match) {
math.push(match);
this.start.lastIndex = match.end.n;
}
}
}
/**
* Search for math in an array of strings and return an array of matches.
*
* @override
*/
public findMath(strings: string[]) {
let math: ProtoItem<N, T>[] = [];
if (this.hasPatterns) {
for (let i = 0, m = strings.length; i < m; i++) {
this.findMathInString(math, i, strings[i]);
}
}
return math;
}
}

255
node_modules/mathjax-full/ts/input/tex/MapHandler.ts generated vendored Normal file
View File

@@ -0,0 +1,255 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Singleton class for handling symbol maps.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {AbstractSymbolMap, SymbolMap} from './SymbolMap.js';
import {ParseInput, ParseResult, ParseMethod} from './Types.js';
// import {ParserConfiguration} from './Configuration.js';
import {PrioritizedList} from '../../util/PrioritizedList.js';
import {FunctionList} from '../../util/FunctionList.js';
export type HandlerType = 'delimiter' | 'macro' | 'character' | 'environment';
export type HandlerConfig = {[P in HandlerType]?: string[]};
export type FallbackConfig = {[P in HandlerType]?: ParseMethod};
export namespace MapHandler {
let maps: Map<string, SymbolMap> = new Map();
/**
* Adds a new symbol map to the map handler. Might overwrite an existing
* symbol map of the same name.
*
* @param {SymbolMap} map Registers a new symbol map.
*/
export let register = function(map: SymbolMap): void {
maps.set(map.name, map);
};
/**
* Looks up a symbol map if it exists.
*
* @param {string} name The name of the symbol map.
* @return {SymbolMap} The symbol map with the given name or null.
*/
export let getMap = function(name: string): SymbolMap {
return maps.get(name);
};
}
/**
* Class of symbol mappings that are active in a configuration.
*/
export class SubHandler {
private _configuration: PrioritizedList<SymbolMap> = new PrioritizedList<SymbolMap>();
private _fallback: FunctionList = new FunctionList();
/**
* Adds a list of symbol maps to the handler.
* @param {string[]} maps The names of the symbol maps to add.
* @param {ParseMethod} fallback A fallback method.
* @param {number} priority Optionally a priority.
*/
public add(maps: string[], fallback: ParseMethod,
priority: number = PrioritizedList.DEFAULTPRIORITY) {
for (const name of maps.slice().reverse()) {
let map = MapHandler.getMap(name);
if (!map) {
this.warn('Configuration ' + name + ' not found! Omitted.');
return;
}
this._configuration.add(map, priority);
}
if (fallback) {
this._fallback.add(fallback, priority);
}
}
/**
* Parses the given input with the first applicable symbol map.
* @param {ParseInput} input The input for the parser.
* @return {ParseResult} The output of the parsing function.
*/
public parse(input: ParseInput): ParseResult {
for (let {item: map} of this._configuration) {
const result = map.parse(input);
if (result) {
return result;
}
}
let [env, symbol] = input;
Array.from(this._fallback)[0].item(env, symbol);
}
/**
* Maps a symbol to its "parse value" if it exists.
*
* @param {string} symbol The symbol to parse.
* @return {T} A boolean, Character, or Macro.
*/
public lookup<T>(symbol: string): T {
let map = this.applicable(symbol) as AbstractSymbolMap<T>;
return map ? map.lookup(symbol) : null;
}
/**
* Checks if a symbol is contained in one of the symbol mappings of this
* configuration.
*
* @param {string} symbol The symbol to parse.
* @return {boolean} True if the symbol is contained in the mapping.
*/
public contains(symbol: string): boolean {
return this.applicable(symbol) ? true : false;
}
/**
* @override
*/
public toString(): string {
let names = [];
for (let {item: map} of this._configuration) {
names.push(map.name);
}
return names.join(', ');
}
/**
* Retrieves the first applicable symbol map in the configuration.
* @param {string} symbol The symbol to parse.
* @return {SymbolMap} A map that can parse the symbol.
*/
public applicable(symbol: string): SymbolMap {
for (let {item: map} of this._configuration) {
if (map.contains(symbol)) {
return map;
}
}
return null;
}
/**
* Retrieves the map of the given name.
* @param {string} name Name of the symbol map.
* @return {SymbolMap} The map if it exists.
*/
public retrieve(name: string): SymbolMap {
for (let {item: map} of this._configuration) {
if (map.name === name) {
return map;
}
}
return null;
}
/**
* Prints a warning message.
* @param {string} message The warning.
*/
private warn(message: string) {
console.log('TexParser Warning: ' + message);
}
}
export class SubHandlers {
private map = new Map<HandlerType, SubHandler>();
/**
* Adds a symbol map to the configuration if it exists.
* @param {string} name of the symbol map.
*/
public add(handlers: HandlerConfig, fallbacks: FallbackConfig,
priority: number = PrioritizedList.DEFAULTPRIORITY): void {
for (const key of Object.keys(handlers)) {
let name = key as HandlerType;
let subHandler = this.get(name);
if (!subHandler) {
subHandler = new SubHandler();
this.set(name, subHandler);
}
subHandler.add(handlers[name], fallbacks[name], priority);
}
}
/**
* Setter for subhandlers.
* @param {HandlerType} name The name of the subhandler.
* @param {SubHandler} subHandler The subhandler.
*/
public set(name: HandlerType, subHandler: SubHandler) {
this.map.set(name, subHandler);
}
/**
* Getter for subhandler.
* @param {HandlerType} name Name of the subhandler.
* @return {SubHandler} The subhandler by that name if it exists.
*/
public get(name: HandlerType): SubHandler {
return this.map.get(name);
}
/**
* Retrieves a symbol map of the given name.
* @param {string} name Name of the symbol map.
* @return {SymbolMap} The map if it exists. O/w null.
*/
public retrieve(name: string): SymbolMap {
for (const handler of this.map.values()) {
let map = handler.retrieve(name);
if (map) {
return map;
}
}
return null;
}
/**
* All names of registered subhandlers.
* @return {IterableIterator<string>} Iterable list of keys.
*/
public keys(): IterableIterator<string> {
return this.map.keys();
}
}

176
node_modules/mathjax-full/ts/input/tex/NodeFactory.ts generated vendored Normal file
View File

@@ -0,0 +1,176 @@
/*************************************************************
*
* Copyright (c) 2009-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Node factory for creating MmlNodes. This allows extension
* packages to add node constructors or overwrite existing ones.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {TextNode, MmlNode} from '../../core/MmlTree/MmlNode.js';
import {MmlFactory} from '../../core/MmlTree/MmlFactory.js';
import ParseOptions from './ParseOptions.js';
import NodeUtil from './NodeUtil.js';
export type NodeFactoryMethod = (factory: NodeFactory, kind: string, ...rest: any[]) => MmlNode;
export class NodeFactory {
/**
* Parser configuration that can be used to pass information between node methods.
* @type {ParseOption}
*/
public configuration: ParseOptions;
/**
* The external node factory.
* @type {MmlFactory}
*/
protected mmlFactory: MmlFactory = null;
/**
* The factory table populated with some default methods.
*/
private factory: {[kind: string]: NodeFactoryMethod} =
{'node': NodeFactory.createNode,
'token': NodeFactory.createToken,
'text': NodeFactory.createText,
'error': NodeFactory.createError
};
/**
* Default node generation function.
* @param {NodeFactory} factory The current node factory.
* @param {string} kind The type of node to create.
* @param {MmlNode[]} children Its children.
* @param {any=} def Its properties.
* @param {TextNode=} text An optional text node if this is a token.
* @return {MmlNode} The newly created Mml node.
*/
public static createNode(factory: NodeFactory, kind: string,
children: MmlNode[] = [], def: any = {},
text?: TextNode): MmlNode {
const node = factory.mmlFactory.create(kind);
node.setChildren(children);
if (text) {
node.appendChild(text);
}
NodeUtil.setProperties(node, def);
return node;
}
/**
* Default token generation function.
* @param {NodeFactory} factory The current node factory.
* @param {string} kind The type of node to create.
* @param {any} def Its properties.
* @param {string} text Text of the token.
* @return {MmlNode} The newly created token node.
*/
public static createToken(factory: NodeFactory, kind: string,
def: any = {}, text: string = ''): MmlNode {
const textNode = factory.create('text', text);
return factory.create('node', kind, [], def, textNode);
}
/**
* Default text node generation function.
* @param {NodeFactory} factory The current node factory.
* @param {string} text The text for the new node.
* @return {TextNode} The newly created text node.
*/
public static createText(factory: NodeFactory, text: string): TextNode {
if (text == null) {
return null;
}
return (factory.mmlFactory.create('text') as TextNode).setText(text);
}
/**
* Default error node generation function.
* @param {NodeFactory} factory The current node factory.
* @param {string} message The error message.
* @return {MmlNode} The newly created error node.
*/
public static createError(factory: NodeFactory, message: string): MmlNode {
let text = factory.create('text', message);
let mtext = factory.create('node', 'mtext', [], {}, text);
let error = factory.create('node', 'merror', [mtext], {'data-mjx-error': message});
return error;
}
/**
* @param {MmlFactory} mmlFactory The MmlFactory for the TeX jax to use
*/
public setMmlFactory(mmlFactory: MmlFactory) {
this.mmlFactory = mmlFactory;
}
/**
* Adds a method to the factory.
* @param {string} kind The type of node the method creates.
* @param {NodeFactoryMethod} func The node creator.
*/
public set(kind: string, func: NodeFactoryMethod) {
this.factory[kind] = func;
}
/**
* Adds a set of node creators to the factory.
* @param {Object.<NodeFactoryMethod>} maps The set of functions.
*/
public setCreators(maps: {[kind: string]: NodeFactoryMethod}) {
for (let kind in maps) {
this.set(kind, maps[kind]);
}
}
/**
* Creates a node for the internal data structure from the factory.
* @param {string} kind The type of node to be created.
* @param {any[]} ...rest The arguments for the node.
* @return {MmlNode} The created node.
*/
public create(kind: string, ...rest: any[]): MmlNode {
const func = this.factory[kind] || this.factory['node'];
const node = func(this, rest[0], ...rest.slice(1));
if (kind === 'node') {
this.configuration.addNode(rest[0], node);
}
return node;
}
/**
* @param {string} kind The method for generating a node of given kind.
*/
public get(kind: string) {
return this.factory[kind];
}
}

306
node_modules/mathjax-full/ts/input/tex/NodeUtil.ts generated vendored Normal file
View File

@@ -0,0 +1,306 @@
/*************************************************************
*
* Copyright (c) 2009-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Node utility methods.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {TextNode, MMLNODE, MmlNode, AbstractMmlNode, AbstractMmlEmptyNode} from '../../core/MmlTree/MmlNode.js';
import {MmlMo} from '../../core/MmlTree/MmlNodes/mo.js';
import {Property, PropertyList} from '../../core/Tree/Node.js';
import {Args} from './Types.js';
import {OperatorDef} from '../../core/MmlTree/OperatorDictionary.js';
namespace NodeUtil {
const attrs: Map<String, boolean> = new Map([
['autoOP', true],
['fnOP', true],
['movesupsub', true],
['subsupOK', true],
['texprimestyle', true],
['useHeight', true],
['variantForm', true],
['withDelims', true],
['mathaccent', true],
['open', true],
['close', true]
]);
/**
* Creates a single character from a unicode hex string.
* @param {string} code The code.
* @return {string} The newly created entity.
*/
export function createEntity(code: string): string {
return String.fromCodePoint(parseInt(code, 16));
}
/**
* Get the children of the a node.
* @param {MmlNode} node The node.
* @return {MMLNODE[]} Its children.
*/
export function getChildren(node: MmlNode): MMLNODE[] {
return (node.childNodes as MMLNODE[]);
}
/**
* Get text content of a node.
* @param {TextNode} node The node.
* @return {string} Its text content.
*/
export function getText(node: TextNode): string {
return node.getText();
}
/**
* Append children to a node.
* @param {MmlNode} node The node.
* @param {MMLNODE[]} children A list of new children.
*/
export function appendChildren(node: MmlNode, children: MMLNODE[]) {
for (let child of children) {
node.appendChild(child);
}
}
/**
* Sets an attribute of a node.
* @param {MmlNode} node The node.
* @param {string} attribute An attribute.
* @param {Args} value The attribute value.
*/
export function setAttribute(node: MmlNode, attribute: string, value: Args) {
node.attributes.set(attribute, value);
}
/**
* Sets a property of a node.
* @param {MmlNode} node The node.
* @param {string} property The property.
* @param {Args} value The property value.
*/
export function setProperty(node: MmlNode, property: string, value: Args) {
node.setProperty(property, value);
}
/**
* Sets properties and attributes of a node.
* @param {MmlNode} node The node.
* @param {PropertyList} properties A list of property/attribute value pairs.
*/
export function setProperties(node: MmlNode, properties: PropertyList) {
for (const name of Object.keys(properties)) {
let value = properties[name];
if (name === 'texClass') {
node.texClass = (value as number);
node.setProperty(name, value);
} else if (name === 'movablelimits') {
node.setProperty('movablelimits', value);
if (node.isKind('mo') || node.isKind('mstyle')) {
node.attributes.set('movablelimits', value);
}
} else if (name === 'inferred') {
// ignore
} else if (attrs.has(name)) {
node.setProperty(name, value);
} else {
node.attributes.set(name, value);
}
}
}
/**
* Returns the property of a node.
* @param {MmlNode} node The node.
* @param {string} property A property name.
* @return {Property} Value of the property.
*/
export function getProperty(node: MmlNode, property: string): Property {
return node.getProperty(property);
}
/**
* Returns the attribute of a node.
* @param {MmlNode} node The node.
* @param {string} attr A attribute name.
* @return {Property} Value of the attribute.
*/
export function getAttribute(node: MmlNode, attr: string): Property {
return node.attributes.get(attr);
}
/**
* Removes a set of properties from a node.
* @param {MmlNode} node The node.
* @param {string[]} ...properties A list of properties.
*/
export function removeProperties(node: MmlNode, ...properties: string[]) {
node.removeProperty(...properties);
}
/**
* Returns a child node at a given position.
* @param {MmlNode} node The node.
* @param {number} position The position of the child.
* @return {MMLNODE} The child node at position.
*/
export function getChildAt(node: MmlNode, position: number): MMLNODE {
return (node.childNodes[position] as MMLNODE);
}
/**
* Set node child at position.
* @param {MmlNode} node The node.
* @param {number} position The position of the new child.
* @param {MmlNode} child The new child.
*/
export function setChild(node: MmlNode, position: number, child: MmlNode) {
let children = node.childNodes;
children[position] = child;
if (child) {
child.parent = node;
}
}
/**
* Copies children between nodes.
* @param {MmlNode} oldNode The source node.
* @param {MmlNode} newNode The target node.
*/
export function copyChildren(oldNode: MmlNode, newNode: MmlNode) {
let children = oldNode.childNodes as (TextNode | MmlNode)[];
for (let i = 0; i < children.length; i++) {
setChild(newNode, i, children[i]);
}
}
/**
* Copies attributes between nodes.
* @param {MmlNode} oldNode The source node.
* @param {MmlNode} newNode The target node.
*/
export function copyAttributes(oldNode: MmlNode, newNode: MmlNode) {
newNode.attributes = oldNode.attributes;
setProperties(newNode, oldNode.getAllProperties());
}
/**
* Checks if node is of a particular type.
* @param {MmlNode} node The node.
* @param {string} kind The type to check.
* @return {boolean} True if node is of the given type.
*/
export function isType(node: MmlNode, kind: string): boolean {
return node.isKind(kind);
}
/**
* Checks if the node is embellished.
* @param {MmlNode} node The node.
* @return {boolean} True if node is embellished.
*/
export function isEmbellished(node: MmlNode): boolean {
return node.isEmbellished;
}
/**
* Gets the texclass of a node.
* @param {MmlNode} node The node.
* @return {number} Its texclass.
*/
export function getTexClass(node: MmlNode): number {
return node.texClass;
}
/**
* Gets the mo element at the core of the node.
* @param {MmlNode} node The node.
* @return {MmlNode} The MO node at the core.
*/
export function getCoreMO(node: MmlNode): MmlNode {
return node.coreMO();
}
/**
* Checks if an object is a node.
* @param {any} item The object.
* @return {boolean} True if it is a node.
*/
export function isNode(item: any): boolean {
return item instanceof AbstractMmlNode || item instanceof AbstractMmlEmptyNode;
}
/**
* Checks if the node is an inferred mrow.
* @param {MmlNode} node The node.
* @return {boolean} True if the node is an inferred mrow.
*/
export function isInferred(node: MmlNode): boolean {
return node.isInferred;
}
/**
* Gets the operator definition of a node.
* @param {MmlNode} node The node.
* @return {OperatorDef} If node is an MO returns the operator definition. O/w
* null.
*/
export function getForm(node: MmlNode): OperatorDef {
if (!isType(node, 'mo')) {
return null;
}
let mo = node as MmlMo;
let forms = mo.getForms();
for (let form of forms) {
let symbol = MmlMo.OPTABLE[form][mo.getText()];
if (symbol) {
return symbol;
}
}
return null;
}
}
export default NodeUtil;

165
node_modules/mathjax-full/ts/input/tex/ParseMethods.ts generated vendored Normal file
View File

@@ -0,0 +1,165 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Base methods for TeX Parsing.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {Symbol} from './Symbol.js';
import TexParser from './TexParser.js';
import NodeUtil from './NodeUtil.js';
import {TexConstant} from './TexConstants.js';
import {MmlNode} from '../../core/MmlTree/MmlNode.js';
import ParseUtil from './ParseUtil.js';
namespace ParseMethods {
/**
* Handle a variable (a single letter or multi-letter if allowed).
* @param {TexParser} parser The current tex parser.
* @param {string} c The letter to transform into an mi.
*/
export function variable(parser: TexParser, c: string) {
// @test Identifier Font
const def = ParseUtil.getFontDef(parser);
const env = parser.stack.env;
if (env.multiLetterIdentifiers && env.font !== '') {
c = parser.string.substr(parser.i - 1).match(env.multiLetterIdentifiers as any as RegExp)[0];
parser.i += c.length - 1;
if (def.mathvariant === TexConstant.Variant.NORMAL && env.noAutoOP && c.length > 1) {
def.autoOP = false;
}
}
// @test Identifier
const node = parser.create('token', 'mi', def, c);
parser.Push(node);
}
/**
* Handle a number (a sequence of digits, with decimal separator, etc.).
* @param {TexParser} parser The current tex parser.
* @param {string} c The first character of a number than can be parsed with
* the digits pattern.
*/
export function digit(parser: TexParser, c: string) {
let mml: MmlNode;
const pattern = parser.configuration.options['digits'];
const n = parser.string.slice(parser.i - 1).match(pattern);
// @test Integer Font
const def = ParseUtil.getFontDef(parser);
if (n) {
// @test Integer, Number, Decimal (European)
mml = parser.create('token', 'mn', def, n[0].replace(/[{}]/g, ''));
parser.i += n[0].length - 1;
} else {
// @test Decimal Point, Decimal Point European
mml = parser.create('token', 'mo', def, c);
}
parser.Push(mml);
}
/**
* Lookup a control-sequence and process it.
* @param {TexParser} parser The current tex parser.
* @param {string} c The string '\'.
*/
export function controlSequence(parser: TexParser, _c: string) {
const name = parser.GetCS();
parser.parse('macro', [parser, name]);
}
/**
* Handle normal mathchar (as an mi).
* @param {TexParser} parser The current tex parser.
* @param {Symbol} mchar The parsed symbol.
*/
export function mathchar0mi(parser: TexParser, mchar: Symbol) {
const def = mchar.attributes || {mathvariant: TexConstant.Variant.ITALIC};
// @test Greek
const node = parser.create('token', 'mi', def, mchar.char);
parser.Push(node);
}
/**
* Handle normal mathchar (as an mo).
* @param {TexParser} parser The current tex parser.
* @param {Symbol} mchar The parsed symbol.
*/
export function mathchar0mo(parser: TexParser, mchar: Symbol) {
const def = mchar.attributes || {};
def['stretchy'] = false;
// @test Large Set
const node = parser.create('token', 'mo', def, mchar.char);
NodeUtil.setProperty(node, 'fixStretchy', true);
parser.configuration.addNode('fixStretchy', node);
// PROBLEM: Attributes stop working when Char7 are explicitly set.
parser.Push(node);
}
/**
* Handle mathchar in current family.
* @param {TexParser} parser The current tex parser.
* @param {Symbol} mchar The parsed symbol.
*/
export function mathchar7(parser: TexParser, mchar: Symbol) {
const def = mchar.attributes || {mathvariant: TexConstant.Variant.NORMAL};
if (parser.stack.env['font']) {
// @test MathChar7 Single Font
def['mathvariant'] = parser.stack.env['font'];
}
// @test MathChar7 Single, MathChar7 Operator, MathChar7 Multi
const node = parser.create('token', 'mi', def, mchar.char);
parser.Push(node);
}
/**
* Handle delimiter.
* @param {TexParser} parser The current tex parser.
* @param {Symbol} delim The parsed delimiter symbol.
*/
export function delimiter(parser: TexParser, delim: Symbol) {
let def = delim.attributes || {};
// @test Fenced2, Delimiter (AMS)
def = Object.assign({fence: false, stretchy: false}, def);
const node = parser.create('token', 'mo', def, delim.char);
parser.Push(node);
}
/**
* Parse an environment.
* @param {TexParser} parser The current tex parser.
* @param {string} env The name of the environment.
* @param {Function} func The parse method for the environment.
* @param {any[]} args A list of additional arguments.
*/
export function environment(parser: TexParser, env: string, func: Function, args: any[]) {
const end = args[0];
let mml = parser.itemFactory.create('begin').setProperties({name: env, end: end});
mml = func(parser, mml, ...args.slice(1));
parser.Push(mml);
}
}
export default ParseMethods;

241
node_modules/mathjax-full/ts/input/tex/ParseOptions.ts generated vendored Normal file
View File

@@ -0,0 +1,241 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Factory generating maps to keep options for the TeX parser.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import StackItemFactory from './StackItemFactory.js';
import {Tags} from './Tags.js';
import {SubHandlers} from './MapHandler.js';
import {NodeFactory} from './NodeFactory.js';
import NodeUtil from './NodeUtil.js';
import {MmlNode} from '../../core/MmlTree/MmlNode.js';
import TexParser from './TexParser.js';
import {defaultOptions, OptionList} from '../../util/Options.js';
import {ParserConfiguration} from './Configuration.js';
/**
* @class
*/
export default class ParseOptions {
/**
* A set of sub handlers
* @type {SubHandlers}
*/
public handlers: SubHandlers;
/**
* A set of options, mapping names to string or boolean values.
* @type {OptionList}
*/
public options: OptionList = {};
/**
* The current item factory.
* @type {StackItemFactory}
*/
public itemFactory: StackItemFactory;
/**
* The current node factory.
* @type {NodeFactory}
*/
public nodeFactory: NodeFactory;
/**
* The current tagging object.
* @type {Tags}
*/
public tags: Tags;
/**
* Storage area for parser-specific package data (indexed by package name)
* @type {Map<string, any>}
*/
public packageData: Map<string, any> = new Map();
// Fields for ephemeral options, i.e., options that will be cleared for each
// run of the parser.
/**
* Stack of previous tex parsers. This is used to keep track of parser
* settings when expressions are recursively parsed.
* @type {TexParser[]}
*/
public parsers: TexParser[] = [];
/**
* The current root node.
* @type {MmlNode}
*/
public root: MmlNode = null;
/**
* List of node lists saved with respect to some property or their kind.
* @type {{[key: string]: MmlNode[]}}
*/
public nodeLists: {[key: string]: MmlNode[]} = {};
/**
* Error state of the parser.
* @type {boolean}
*/
public error: boolean = false;
/**
* @constructor
* @param {Configuration} configuration Configuration object of the current
* TeX parser.
* @param {OptionList[]} options [TeX options, Tag options, {packages}]
*/
public constructor(configuration: ParserConfiguration, options: OptionList[] = []) {
this.handlers = configuration.handlers;
// Add node factory methods from packages.
this.nodeFactory = new NodeFactory();
this.nodeFactory.configuration = this;
this.nodeFactory.setCreators(configuration.nodes);
// Add stackitems from packages.
this.itemFactory = new StackItemFactory(configuration.items);
this.itemFactory.configuration = this;
// Set default options for parser from packages and for tags.
defaultOptions(this.options, ...options);
defaultOptions(this.options, configuration.options);
}
// Methods for dealing with ephemeral fields.
/**
* Pushes a new tex parser onto the stack.
* @param {TexParser} parser The new parser.
*/
public pushParser(parser: TexParser) {
this.parsers.unshift(parser);
}
/**
* Pops a parser of the tex parser stack.
*/
public popParser() {
this.parsers.shift();
}
/**
* @return {TexParser} The currently active tex parser.
*/
public get parser(): TexParser {
return this.parsers[0];
}
/**
* Clears all the ephemeral options.
*/
public clear() {
this.parsers = [];
this.root = null;
this.nodeLists = {};
this.error = false;
this.tags.resetTag();
}
/**
* Saves a tree node to a list of nodes for post processing.
* @param {string} property The property name that will be used for
* postprocessing.
* @param {MmlNode} node The node to save.
*/
public addNode(property: string, node: MmlNode) {
let list = this.nodeLists[property];
if (!list) {
list = this.nodeLists[property] = [];
}
list.push(node);
if (node.kind !== property) {
//
// If the list is not just for its kind, record that it is in this list
// so that if it is copied, the copy can also be added to the list.
//
const inlists = (NodeUtil.getProperty(node, 'in-lists') as string || '');
const lists = (inlists ? inlists.split(/,/) : []).concat(property).join(',');
NodeUtil.setProperty(node, 'in-lists', lists);
}
}
/**
* Gets a saved node list with respect to a given property. It first ensures
* that all the nodes are "live", i.e., actually live in the current
* tree. Sometimes nodes are created, saved in the node list but discarded
* later in the parsing. These will be filtered out here.
*
* NB: Do not use this method before the root field of the options is
* set. Otherwise, your node list will always be empty!
* @param {string} property The property for which to retrieve the node list.
*/
public getList(property: string) {
let list = this.nodeLists[property] || [];
let result = [];
for (let node of list) {
if (this.inTree(node)) {
result.push(node);
}
}
this.nodeLists[property] = result;
return result;
}
/**
* Remove a list of nodes from a saved list (e.g., when a filter removes the
* node from the DOM, like for munderover => munder).
*
* @param {string} property The property from which to remove nodes.
* @param {MmlNode[]} nodes The nodes to remove.
*/
public removeFromList(property: string, nodes: MmlNode[]) {
const list = this.nodeLists[property] || [];
for (const node of nodes) {
const i = list.indexOf(node);
if (i >= 0) {
list.splice(i, 1);
}
}
}
/**
* Tests if the node is in the tree spanned by the current root node.
* @param {MmlNode} node The node to test.
*/
private inTree(node: MmlNode) {
while (node && node !== this.root) {
node = node.parent;
}
return !!node;
}
}

713
node_modules/mathjax-full/ts/input/tex/ParseUtil.ts generated vendored Normal file
View File

@@ -0,0 +1,713 @@
/*************************************************************
*
* Copyright (c) 2009-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview A namespace for utility functions for the TeX Parser.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {TEXCLASS, MmlNode} from '../../core/MmlTree/MmlNode.js';
import {EnvList} from './StackItem.js';
import {ArrayItem} from './base/BaseItems.js';
import ParseOptions from './ParseOptions.js';
import NodeUtil from './NodeUtil.js';
import TexParser from './TexParser.js';
import TexError from './TexError.js';
import {entities} from '../../util/Entities.js';
import {MmlMunderover} from '../../core/MmlTree/MmlNodes/munderover.js';
namespace ParseUtil {
// TODO (VS): Combine some of this with lengths in util.
const emPerInch = 7.2;
const pxPerInch = 72;
// Note, the following are TeX CM font values.
const UNIT_CASES: {[key: string]: ((m: number) => number)} = {
'em': m => m,
'ex': m => m * .43,
'pt': m => m / 10, // 10 pt to an em
'pc': m => m * 1.2, // 12 pt to a pc
'px': m => m * emPerInch / pxPerInch,
'in': m => m * emPerInch,
'cm': m => m * emPerInch / 2.54, // 2.54 cm to an inch
'mm': m => m * emPerInch / 25.4, // 10 mm to a cm
'mu': m => m / 18,
};
const num = '([-+]?([.,]\\d+|\\d+([.,]\\d*)?))';
const unit = '(pt|em|ex|mu|px|mm|cm|in|pc)';
const dimenEnd = RegExp('^\\s*' + num + '\\s*' + unit + '\\s*$');
const dimenRest = RegExp('^\\s*' + num + '\\s*' + unit + ' ?');
/**
* Matches for a dimension argument.
* @param {string} dim The argument.
* @param {boolean} rest Allow for trailing garbage in the dimension string.
* @return {[string, string, number]} The match result as (Anglosaxon) value,
* unit name, length of matched string. The latter is interesting in the
* case of trailing garbage.
*/
export function matchDimen(
dim: string, rest: boolean = false): [string, string, number] {
let match = dim.match(rest ? dimenRest : dimenEnd);
return match ?
muReplace([match[1].replace(/,/, '.'), match[4], match[0].length]) :
[null, null, 0];
}
/**
* Transforms mu dimension to em if necessary.
* @param {[string, string, number]} [value, unit, length] The dimension triple.
* @return {[string, string, number]} [value, unit, length] The transformed triple.
*/
function muReplace([value, unit, length]: [string, string, number]): [string, string, number] {
if (unit !== 'mu') {
return [value, unit, length];
}
let em = Em(UNIT_CASES[unit](parseFloat(value || '1')));
return [em.slice(0, -2), 'em', length];
}
/**
* Convert a dimension string into standard em dimension.
* @param {string} dim The attribute string.
* @return {number} The numerical value.
*/
export function dimen2em(dim: string): number {
let [value, unit] = matchDimen(dim);
let m = parseFloat(value || '1');
let func = UNIT_CASES[unit];
return func ? func(m) : 0;
}
/**
* Turns a number into an em value.
* @param {number} m The number.
* @return {string} The em dimension string.
*/
export function Em(m: number): string {
if (Math.abs(m) < .0006) {
return '0em';
}
return m.toFixed(3).replace(/\.?0+$/, '') + 'em';
}
/**
* Takes an array of numbers and returns a space-separated string of em values.
* @param {number[]} W The widths to be turned into em values
* @return {string} The numbers with em units, separated by spaces.
*/
export function cols(...W: number[]): string {
return W.map(n => Em(n)).join(' ');
}
/**
* Create an mrow that has stretchy delimiters at either end, as needed
* @param {ParseOptions} configuration Current parse options.
* @param {string} open The opening fence.
* @param {MmlNode} mml The enclosed node.
* @param {string} close The closing fence.
* @param {string=} big Bigg command.
*/
export function fenced(configuration: ParseOptions, open: string, mml: MmlNode,
close: string, big: string = '', color: string = '') {
// @test Fenced, Fenced3
let nf = configuration.nodeFactory;
let mrow = nf.create('node', 'mrow', [],
{open: open, close: close, texClass: TEXCLASS.INNER});
let mo;
if (big) {
mo = new TexParser('\\' + big + 'l' + open, configuration.parser.stack.env, configuration).mml();
} else {
let openNode = nf.create('text', open);
mo = nf.create('node', 'mo', [],
{fence: true, stretchy: true, symmetric: true, texClass: TEXCLASS.OPEN},
openNode);
}
NodeUtil.appendChildren(mrow, [mo, mml]);
if (big) {
mo = new TexParser('\\' + big + 'r' + close, configuration.parser.stack.env, configuration).mml();
} else {
let closeNode = nf.create('text', close);
mo = nf.create('node', 'mo', [],
{fence: true, stretchy: true, symmetric: true, texClass: TEXCLASS.CLOSE},
closeNode);
}
color && mo.attributes.set('mathcolor', color);
NodeUtil.appendChildren(mrow, [mo]);
return mrow;
}
/**
* Create an mrow that has \\mathchoice using \\bigg and \\big for the delimiters.
* @param {ParseOptions} configuration The current parse options.
* @param {string} open The opening fence.
* @param {MmlNode} mml The enclosed node.
* @param {string} close The closing fence.
* @return {MmlNode} The mrow node.
*/
export function fixedFence(configuration: ParseOptions, open: string,
mml: MmlNode, close: string): MmlNode {
// @test Choose, Over With Delims, Above with Delims
let mrow = configuration.nodeFactory.create('node',
'mrow', [], {open: open, close: close, texClass: TEXCLASS.ORD});
if (open) {
NodeUtil.appendChildren(mrow, [mathPalette(configuration, open, 'l')]);
}
if (NodeUtil.isType(mml, 'mrow')) {
NodeUtil.appendChildren(mrow, NodeUtil.getChildren(mml));
} else {
NodeUtil.appendChildren(mrow, [mml]);
}
if (close) {
NodeUtil.appendChildren(mrow, [mathPalette(configuration, close, 'r')]);
}
return mrow;
}
/**
* Generates a mathchoice element for fences. These will be resolved later,
* once the position, and therefore size, of the of the fenced expression is
* known.
* @param {ParseOptions} configuration The current parse otpions.
* @param {string} fence The fence.
* @param {string} side The side of the fence (l or r).
* @return {MmlNode} The mathchoice node.
*/
export function mathPalette(configuration: ParseOptions, fence: string,
side: string): MmlNode {
if (fence === '{' || fence === '}') {
fence = '\\' + fence;
}
let D = '{\\bigg' + side + ' ' + fence + '}';
let T = '{\\big' + side + ' ' + fence + '}';
return new TexParser('\\mathchoice' + D + T + T + T, {}, configuration).mml();
}
/**
* If the initial child, skipping any initial space or
* empty braces (TeXAtom with child being an empty inferred row),
* is an <mo>, precede it by an empty <mi> to force the <mo> to
* be infix.
* @param {ParseOptions} configuration The current parse options.
* @param {MmlNode[]} nodes The row of nodes to scan for an initial <mo>
*/
export function fixInitialMO(configuration: ParseOptions, nodes: MmlNode[]) {
for (let i = 0, m = nodes.length; i < m; i++) {
let child = nodes[i];
if (child && (!NodeUtil.isType(child, 'mspace') &&
(!NodeUtil.isType(child, 'TeXAtom') ||
(NodeUtil.getChildren(child)[0] &&
NodeUtil.getChildren(NodeUtil.getChildren(child)[0]).length)))) {
if (NodeUtil.isEmbellished(child) ||
(NodeUtil.isType(child, 'TeXAtom') && NodeUtil.getTexClass(child) === TEXCLASS.REL)) {
let mi = configuration.nodeFactory.create('node', 'mi');
nodes.unshift(mi);
}
break;
}
}
}
/**
* Break up a string into text and math blocks.
* @param {TexParser} parser The calling parser.
* @param {string} text The text in the math expression to parse.
* @param {number|string=} level The scriptlevel.
* @param {string} font The mathvariant to use
* @return {MmlNode[]} The nodes corresponding to the internal math expression.
*/
export function internalMath(parser: TexParser, text: string,
level?: number | string, font?: string): MmlNode[] {
if (parser.configuration.options.internalMath) {
return parser.configuration.options.internalMath(parser, text, level, font);
}
let mathvariant = font || parser.stack.env.font;
let def = (mathvariant ? {mathvariant} : {});
let mml: MmlNode[] = [], i = 0, k = 0, c, node, match = '', braces = 0;
if (text.match(/\\?[${}\\]|\\\(|\\(eq)?ref\s*\{/)) {
while (i < text.length) {
c = text.charAt(i++);
if (c === '$') {
if (match === '$' && braces === 0) {
// @test Interspersed Text
node = parser.create(
'node', 'TeXAtom',
[(new TexParser(text.slice(k, i - 1), {}, parser.configuration)).mml()]);
mml.push(node);
match = '';
k = i;
} else if (match === '') {
// @test Interspersed Text
if (k < i - 1) {
// @test Interspersed Text
mml.push(internalText(parser, text.slice(k, i - 1), def));
}
match = '$';
k = i;
}
} else if (c === '{' && match !== '') {
// @test Mbox Mbox, Mbox Math
braces++;
} else if (c === '}') {
// @test Mbox Mbox, Mbox Math
if (match === '}' && braces === 0) {
// @test Mbox Eqref, Mbox Math
let atom = (new TexParser(text.slice(k, i), {}, parser.configuration)).mml();
node = parser.create('node', 'TeXAtom', [atom], def);
mml.push(node);
match = '';
k = i;
} else if (match !== '') {
// @test Mbox Math, Mbox Mbox
if (braces) {
// @test Mbox Math, Mbox Mbox
braces--;
}
}
} else if (c === '\\') {
// @test Mbox Eqref, Mbox CR
if (match === '' && text.substr(i).match(/^(eq)?ref\s*\{/)) {
// @test Mbox Eqref
let len = ((RegExp as any)['$&'] as string).length;
if (k < i - 1) {
// @test Mbox Eqref
mml.push(internalText(parser, text.slice(k, i - 1), def));
}
match = '}';
k = i - 1;
i += len;
} else {
// @test Mbox CR, Mbox Mbox
c = text.charAt(i++);
if (c === '(' && match === '') {
// @test Mbox Internal Display
if (k < i - 2) {
// @test Mbox Internal Display
mml.push(internalText(parser, text.slice(k, i - 2), def));
}
match = ')'; k = i;
} else if (c === ')' && match === ')' && braces === 0) {
// @test Mbox Internal Display
node = parser.create(
'node', 'TeXAtom',
[(new TexParser(text.slice(k, i - 2), {}, parser.configuration)).mml()]);
mml.push(node);
match = '';
k = i;
} else if (c.match(/[${}\\]/) && match === '') {
// @test Mbox CR
i--;
text = text.substr(0, i - 1) + text.substr(i); // remove \ from \$, \{, \}, or \\
}
}
}
}
if (match !== '') {
// @test Internal Math Error
throw new TexError('MathNotTerminated', 'Math not terminated in text box');
}
}
if (k < text.length) {
// @test Interspersed Text, Mbox Mbox
mml.push(internalText(parser, text.slice(k), def));
}
if (level != null) {
// @test Label, Fbox, Hbox
mml = [parser.create('node', 'mstyle', mml, {displaystyle: false, scriptlevel: level})];
} else if (mml.length > 1) {
// @test Interspersed Text
mml = [parser.create('node', 'mrow', mml)];
}
return mml;
}
/**
* Parses text internal to boxes or labels.
* @param {TexParser} parser The current tex parser.
* @param {string} text The text to parse.
* @param {EnvList} def The attributes of the text node.
* @return {MmlNode} The text node.
*/
export function internalText(parser: TexParser, text: string, def: EnvList): MmlNode {
// @test Label, Fbox, Hbox
text = text.replace(/^\s+/, entities.nbsp).replace(/\s+$/, entities.nbsp);
let textNode = parser.create('text', text);
return parser.create('node', 'mtext', [], def, textNode);
}
/**
* Create an munderover node with the given script position.
* @param {TexParser} parser The current TeX parser.
* @param {MmlNode} base The base node.
* @param {MmlNode} script The under- or over-script.
* @param {string} pos Either 'over' or 'under'.
* @param {boolean} stack True if super- or sub-scripts should stack.
* @return {MmlNode} The generated node (MmlMunderover or TeXAtom)
*/
export function underOver(parser: TexParser, base: MmlNode, script: MmlNode, pos: string, stack: boolean): MmlNode {
// @test Overline
ParseUtil.checkMovableLimits(base);
if (NodeUtil.isType(base, 'munderover') && NodeUtil.isEmbellished(base)) {
// @test Overline Limits
NodeUtil.setProperties(NodeUtil.getCoreMO(base), {lspace: 0, rspace: 0});
const mo = parser.create('node', 'mo', [], {rspace: 0});
base = parser.create('node', 'mrow', [mo, base]);
// TODO? add an empty <mi> so it's not embellished any more
}
const mml = parser.create('node', 'munderover', [base]) as MmlMunderover;
NodeUtil.setChild(mml, pos === 'over' ? mml.over : mml.under, script);
let node: MmlNode = mml;
if (stack) {
// @test Overbrace 1 2 3, Underbrace, Overbrace Op 1 2
node = parser.create('node', 'TeXAtom', [mml], {texClass: TEXCLASS.OP, movesupsub: true});
}
NodeUtil.setProperty(node, 'subsupOK', true);
return node;
}
/**
* Set movablelimits to false if necessary.
* @param {MmlNode} base The base node being tested.
*/
export function checkMovableLimits(base: MmlNode) {
const symbol = (NodeUtil.isType(base, 'mo') ? NodeUtil.getForm(base) : null);
if (NodeUtil.getProperty(base, 'movablelimits') || (symbol && symbol[3] && symbol[3].movablelimits)) {
// @test Overline Sum
NodeUtil.setProperties(base, {movablelimits: false});
}
}
/**
* Trim spaces from a string.
* @param {string} text The string to clean.
* @return {string} The string with leading and trailing whitespace removed.
*/
export function trimSpaces(text: string): string {
if (typeof(text) !== 'string') {
return text;
}
let TEXT = text.trim();
if (TEXT.match(/\\$/) && text.match(/ $/)) {
TEXT += ' ';
}
return TEXT;
}
/**
* Sets alignment in array definitions.
* @param {ArrayItem} array The array item.
* @param {string} align The alignment string.
* @return {ArrayItem} The altered array item.
*/
export function setArrayAlign(array: ArrayItem, align: string): ArrayItem {
// @test Array1, Array2, Array Test
align = ParseUtil.trimSpaces(align || '');
if (align === 't') {
array.arraydef.align = 'baseline 1';
} else if (align === 'b') {
array.arraydef.align = 'baseline -1';
} else if (align === 'c') {
array.arraydef.align = 'axis';
} else if (align) {
array.arraydef.align = align;
} // FIXME: should be an error?
return array;
}
/**
* Replace macro parameters with their values.
* @param {TexParser} parser The current TeX parser.
* @param {string[]} args A list of arguments for macro parameters.
* @param {string} str The macro parameter string.
* @return {string} The string with all parameters replaced by arguments.
*/
export function substituteArgs(parser: TexParser, args: string[],
str: string): string {
let text = '';
let newstring = '';
let i = 0;
while (i < str.length) {
let c = str.charAt(i++);
if (c === '\\') {
text += c + str.charAt(i++);
}
else if (c === '#') {
c = str.charAt(i++);
if (c === '#') {
text += c;
} else {
if (!c.match(/[1-9]/) || parseInt(c, 10) > args.length) {
throw new TexError('IllegalMacroParam',
'Illegal macro parameter reference');
}
newstring = addArgs(parser, addArgs(parser, newstring, text),
args[parseInt(c, 10) - 1]);
text = '';
}
} else {
text += c;
}
}
return addArgs(parser, newstring, text);
}
/**
* Adds a new expanded argument to an already macro parameter string. Makes
* sure that macros are followed by a space if their names could accidentally
* be continued into the following text.
* @param {TexParser} parser The current TeX parser.
* @param {string} s1 The already expanded string.
* @param {string} s2 The string to add.
* @return {string} The combined string.
*/
export function addArgs(parser: TexParser, s1: string, s2: string): string {
if (s2.match(/^[a-z]/i) && s1.match(/(^|[^\\])(\\\\)*\\[a-z]+$/i)) {
s1 += ' ';
}
if (s1.length + s2.length > parser.configuration.options['maxBuffer']) {
throw new TexError('MaxBufferSize',
'MathJax internal buffer size exceeded; is there a' +
' recursive macro call?');
}
return s1 + s2;
}
/**
* Report an error if there are too many macro substitutions.
* @param {TexParser} parser The current TeX parser.
* @param {boolean} isMacro True if we are substituting a macro, false for environment.
*/
export function checkMaxMacros(parser: TexParser, isMacro: boolean = true) {
if (++parser.macroCount <= parser.configuration.options['maxMacros']) {
return;
}
if (isMacro) {
throw new TexError('MaxMacroSub1',
'MathJax maximum macro substitution count exceeded; ' +
'is here a recursive macro call?');
} else {
throw new TexError('MaxMacroSub2',
'MathJax maximum substitution count exceeded; ' +
'is there a recursive latex environment?');
}
}
/**
* Check for bad nesting of equation environments
*/
export function checkEqnEnv(parser: TexParser) {
if (parser.stack.global.eqnenv) {
// @test ErroneousNestingEq
throw new TexError('ErroneousNestingEq', 'Erroneous nesting of equation structures');
}
parser.stack.global.eqnenv = true;
}
/**
* Copy an MmlNode and add it (and its children) to the proper lists.
*
* @param {MmlNode} node The MmlNode to copy
* @param {TexParser} parser The active tex parser
* @return {MmlNode} The duplicate tree
*/
export function copyNode(node: MmlNode, parser: TexParser): MmlNode {
const tree = node.copy() as MmlNode;
const options = parser.configuration;
tree.walkTree((n: MmlNode) => {
options.addNode(n.kind, n);
const lists = (n.getProperty('in-lists') as string || '').split(/,/);
for (const list of lists) {
list && options.addNode(list, n);
}
});
return tree;
}
/**
* This is a placeholder for future security filtering of attributes.
* @param {TexParser} parser The current parser.
* @param {string} name The attribute name.
* @param {string} value The attribute value to filter.
* @return {string} The filtered value.
*/
export function MmlFilterAttribute(_parser: TexParser, _name: string, value: string): string {
// TODO: Implement in security package.
return value;
}
/**
* Initialises an stack environment with current font definition in the parser.
* @param {TexParser} parser The current tex parser.
* @return {EnvList} The initialised environment list.
*/
export function getFontDef(parser: TexParser): EnvList {
const font = parser.stack.env['font'];
return (font ? {mathvariant: font} : {});
}
/**
* Splits a package option list of the form [x=y,z=1] into an attribute list
* of the form {x: y, z: 1}.
* @param {string} attrib The attributes of the package.
* @param {{[key: string]: number}?} allowed A list of allowed options. If
* given only allowed arguments are returned.
* @param {boolean?} error If true, raises an exception if not allowed options
* are found.
* @return {EnvList} The attribute list.
*/
export function keyvalOptions(attrib: string,
allowed: {[key: string]: number} = null,
error: boolean = false): EnvList {
let def: EnvList = readKeyval(attrib);
if (allowed) {
for (let key of Object.keys(def)) {
if (!allowed.hasOwnProperty(key)) {
if (error) {
throw new TexError('InvalidOption', 'Invalid option: %1', key);
}
delete def[key];
}
}
}
return def;
}
/**
* Implementation of the keyval function from https://www.ctan.org/pkg/keyval
* @param {string} text The optional parameter string for a package or
* command.
* @return {EnvList} Set of options as key/value pairs.
*/
function readKeyval(text: string): EnvList {
let options: EnvList = {};
let rest = text;
let end, key, val;
while (rest) {
[key, end, rest] = readValue(rest, ['=', ',']);
if (end === '=') {
[val, end, rest] = readValue(rest, [',']);
val = (val === 'false' || val === 'true') ?
JSON.parse(val) : val;
options[key] = val;
} else if (key) {
options[key] = true;
}
}
return options;
}
/**
* Removes pairs of outer braces.
* @param {string} text The string to clean.
* @param {number} count The number of outer braces to slice off.
* @return {string} The cleaned string.
*/
function removeBraces(text: string, count: number): string {
while (count > 0) {
text = text.trim().slice(1, -1);
count--;
}
return text.trim();
}
/**
* Read a value from the given string until an end parameter is reached or
* string is exhausted.
* @param {string} text The string to process.
* @param {string[]} end List of possible end characters.
* @return {[string, string, string]} The collected value, the actual end
* character, and the rest of the string still to parse.
*/
function readValue(text: string, end: string[]): [string, string, string] {
let length = text.length;
let braces = 0;
let value = '';
let index = 0;
let start = 0; // Counter for the starting left braces.
let startCount = true; // Flag for counting starting left braces.
let stopCount = false; // If true right braces are found directly
// after starting braces, but no other char yet.
while (index < length) {
let c = text[index++];
switch (c) {
case ' ': // Ignore spaces.
break;
case '{':
if (startCount) { // Count start left braces at start.
start++;
} else {
stopCount = false;
if (start > braces) { // Some start left braces have been closed.
start = braces;
}
}
braces++;
break;
case '}':
if (braces) { // Closing braces.
braces--;
}
if (startCount || stopCount) { // Closing braces at the start.
start--;
stopCount = true; // Continue to close braces.
}
startCount = false; // Stop counting start left braces.
break;
default:
if (!braces && end.indexOf(c) !== -1) { // End character reached.
return [stopCount ? 'true' : // If Stop count is true we
// have balanced braces, only.
removeBraces(value, start), c, text.slice(index)];
}
startCount = false;
stopCount = false;
}
value += c;
}
if (braces) {
throw new TexError('ExtraOpenMissingClose',
'Extra open brace or missing close brace');
}
return [stopCount ? 'true' : removeBraces(value, start), '', text.slice(index)];
}
}
export default ParseUtil;

158
node_modules/mathjax-full/ts/input/tex/Stack.ts generated vendored Normal file
View File

@@ -0,0 +1,158 @@
/*************************************************************
*
* Copyright (c) 2009-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview The Stack for the TeX parser.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import NodeUtil from './NodeUtil.js';
import {MmlNode} from '../../core/MmlTree/MmlNode.js';
import {StackItem, EnvList} from './StackItem.js';
import StackItemFactory from './StackItemFactory.js';
export default class Stack {
/**
* @type {EnvList}
*/
public global: EnvList = {};
/**
* The actual stack, a list of stack items.
* @type {Array.<StackItem>}
*/
private stack: StackItem[] = [];
/**
* @constructor
* @param {StackItemFactory} factory The stack item factory.
* @param {EnvList} env The environment.
* @param {boolean} inner True if parser has been called recursively.
*/
constructor(private _factory: StackItemFactory,
private _env: EnvList, inner: boolean) {
this.global = {isInner: inner};
this.stack = [ this._factory.create('start', this.global) ];
if (_env) {
this.stack[0].env = _env;
}
this.env = this.stack[0].env;
}
/**
* Set the environment of the stack.
* @param {EnvList} env The new environment.
*/
public set env(env: EnvList) {
this._env = env;
}
/**
* Retrieves the environment of that stack.
* @return {EnvList} The current environment.
*/
public get env(): EnvList {
return this._env;
}
/**
* Pushes items or nodes onto stack.
* @param {...StackItem|MmlNode} args A list of items to push.
*/
public Push(...args: (StackItem | MmlNode)[]) {
for (const node of args) {
if (!node) {
continue;
}
const item = NodeUtil.isNode(node) ?
this._factory.create('mml', node) : node as StackItem;
item.global = this.global;
const [top, success] =
this.stack.length ? this.Top().checkItem(item) : [null, true];
if (!success) {
continue;
}
if (top) {
this.Pop();
this.Push(...top);
continue;
}
this.stack.push(item);
if (item.env) {
if (item.copyEnv) {
Object.assign(item.env, this.env);
}
this.env = item.env;
} else {
item.env = this.env;
}
}
}
/**
* Pop the topmost elements off the stack.
* @return {StackItem} A stack item.
*/
public Pop(): StackItem {
const item = this.stack.pop();
if (!item.isOpen) {
delete item.env;
}
this.env = (this.stack.length ? this.Top().env : {});
return item;
}
/**
* Lookup the nth elements on the stack without removing them.
* @param {number=} n Position of element that should be returned. Default 1.
* @return {StackItem} Nth item on the stack.
*/
public Top(n: number = 1): StackItem {
return this.stack.length < n ? null : this.stack[this.stack.length - n];
}
/**
* Lookup the topmost element on the stack, returning the Mml node in that
* item. Optionally pops the Mml node from that stack item.
* @param {boolean=} noPop Pop top item if true.
* @return {MmlNode} The Mml node in the topmost stack item.
*/
public Prev(noPop?: boolean): MmlNode | void {
const top = this.Top();
return noPop ? top.First : top.Pop();
}
/**
* @override
*/
public toString() {
return 'stack[\n ' + this.stack.join('\n ') + '\n]';
}
}

537
node_modules/mathjax-full/ts/input/tex/StackItem.ts generated vendored Normal file
View File

@@ -0,0 +1,537 @@
/*************************************************************
*
* Copyright (c) 2009-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Stack items hold information on the TexParser stack.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {MmlNode} from '../../core/MmlTree/MmlNode.js';
import {FactoryNodeClass} from '../../core/Tree/Factory.js';
import TexError from './TexError.js';
import StackItemFactory from './StackItemFactory.js';
// Union types for abbreviation.
export type EnvProp = string | number | boolean;
export type EnvList = {[key: string]: EnvProp};
// This is the type for all fields that used to be set with With.
export type Prop = string | number | boolean | MmlNode | PropList;
export type PropList = {[key: string]: Prop};
export type CheckType = [(MmlNode | StackItem)[], boolean];
export interface NodeStack {
/**
* Get or set the topmost element on the node stack without removing it.
* @return {MmlNode} The topmost node on the stack.
*/
First: MmlNode;
/**
* Get or set the last element on the node stack without removing it.
* @return {MmlNode} The last node on the stack.
*/
Last: MmlNode;
/**
* @return {MmlNode} The topmost node on the item's node stack.
*/
Pop(): MmlNode | void;
/**
* Pushes new nodes onto the items node stack.
* @param {MmlNode[]} ...nodes A list of nodes.
*/
Push(...nodes: MmlNode[]): void;
/**
* Get the top n elements on the node stack without removing them.
* @param {number=} n Number of elements that should be returned.
* @return {MmlNode[]} List of nodes on top of stack.
*/
Peek(n?: number): MmlNode[];
/**
* @return {number} The size of the stack.
*/
Size(): number;
/**
* Clears the stack.
*/
Clear(): void;
/**
* Returns nodes on the stack item's node stack as an Mml node. I.e., in case
* the item contains more than one node, it creates an mrow.
* @param {boolean=} inferred If set the mrow will be an inferred mrow.
* @param {boolean=} forceRow If set an mrow will be created, regardless of
* how many nodes the item contains.
* @return {MmlNode} The topmost Mml node.
*/
toMml(inferred?: boolean, forceRow?: boolean): MmlNode;
}
export abstract class MmlStack implements NodeStack {
/**
* @constructor
* @extends {NodeStack}
* @param {MmlNode[]} nodes An initial list of nodes to put on the stack.
*/
constructor(private _nodes: MmlNode[]) { }
/**
* @return {MmlNode[]} The nodes on the stack.
*/
protected get nodes(): MmlNode[] {
return this._nodes;
}
/**
* @override
*/
public Push(...nodes: MmlNode[]) {
this._nodes.push(...nodes);
}
/**
* @override
*/
public Pop(): MmlNode {
return this._nodes.pop();
}
/**
* @override
*/
public get First(): MmlNode {
return this._nodes[this.Size() - 1];
}
/**
* @override
*/
public set First(node: MmlNode) {
this._nodes[this.Size() - 1] = node;
}
/**
* @override
*/
public get Last(): MmlNode {
return this._nodes[0];
}
/**
* @override
*/
public set Last(node: MmlNode) {
this._nodes[0] = node;
}
/**
* @override
*/
public Peek(n?: number): MmlNode[] {
if (n == null) {
n = 1;
}
return this._nodes.slice(this.Size() - n);
}
/**
* @override
*/
public Size(): number {
return this._nodes.length;
}
/**
* @override
*/
public Clear(): void {
this._nodes = [];
}
protected abstract get factory(): StackItemFactory;
/**
* @override
*/
public toMml(inferred: boolean = true, forceRow?: boolean) {
if (this._nodes.length === 1 && !forceRow) {
return this.First;
}
// @test Two Identifiers
return this.create(
'node', inferred ? 'inferredMrow' : 'mrow', this._nodes, {});
}
/**
* Convenience method to create nodes with the node factory on this stack.
* @param {string} kind The kind of node to create.
* @param {any[]} ...rest The remaining arguments for the creation method.
* @return {MmlNode} The newly created node.
*/
public create(kind: string, ...rest: any[]): MmlNode {
return this.factory.configuration.nodeFactory.create(kind, ...rest);
}
}
export interface StackItem extends NodeStack {
/**
* Type of stack item.
* @type {string}
*/
kind: string;
/**
* Is this a closing item, e.g., end.
* @type {boolean}
*/
isClose: boolean;
/**
* Is this an opening item, e.g., begin.
* @type {boolean}
*/
isOpen: boolean;
/**
* Is this a finalising item, i.e., one that only collects nodes.
* @type {boolean}
*/
isFinal: boolean;
/**
* Global properties of the parser.
* @type {EnvList}
*/
global: EnvList;
/**
* Local properties of the stack item.
* @type {EnvList}
*/
env: EnvList;
/**
* Copy local properties when pushed to stack?
* @type {boolean}
*/
copyEnv: boolean;
/**
* Tests if item is of the given type.
* @param {string} kind The type.
* @return {boolean} True if item is of that type.
*/
isKind(kind: string): boolean;
/**
* Get a property of the item.
* @param {string} key Property name.
* @return {Prop} Property value if it exists.
*/
getProperty(key: string): Prop;
/**
* Set a property.
* @param {string} key Property name.
* @param {Prop} value Property value.
* @return {StackItem} The item for pipelining.
*/
setProperty(key: string, value: Prop): StackItem;
/**
* Sets a list of properties.
* @param {PropList} def The properties to set.
* @return {StackItem} Returns the stack item object for pipelining.
*/
setProperties(def: PropList): StackItem;
/**
* Convenience method for returning the string property "name".
* @return {string} The value for the name property.
*/
getName(): string;
/**
* TeX parsing in MathJax is essentially implemented via a nested stack
* automaton. That is the tex parser works on a stack, and each item on the
* stack can have a data stack of its own. Data on the stack is either a stack
* item or a node.
*
* The checkItem method effectively implements the recursive checking of
* input data from the parser against data recursively given on the stack.
*
* I.e., new input is parsed resulting in a new item. When pushed on the stack
* it is checked against the top most item on the stack. This either leads to
* the item being pushed onto the stack or combined with the top most
* element(s), pushing a new item, which is recursively checked, unless an
* error is thrown.
*
* A simple example: If \\end{foo} is parsed, an endItem is created, pushed on
* the stack. Nodes on the stack are collapsed into content of the 'foo'
* environment, until a beginItem for 'foo' is found. If a beginItem is not
* for 'foo' or does not exist an error is thrown.
*
* @param {StackItem} item The pushed item.
* @return {CheckType} True/false or an item or node.
*/
checkItem(item: StackItem): CheckType;
}
export interface StackItemClass extends FactoryNodeClass<StackItem> {
// new (factory: StackItemFactory, ...args: any[]): StackItem;
}
/**
* Abstract basic item class that implements most of the stack item
* functionality. In particular, it contains the base method for checkItem.
*/
export abstract class BaseItem extends MmlStack implements StackItem {
/**
* The fail value.
* @type {CheckType}
*/
protected static fail: CheckType = [null, false];
/**
* The success value.
* @type {CheckType}
*/
protected static success: CheckType = [null, true];
/**
* A list of basic errors.
* @type {{[key: string]: string[]}}
*/
protected static errors: {[key: string]: string[]} = {
// @test ExtraOpenMissingClose
end: ['MissingBeginExtraEnd', 'Missing \\begin{%1} or extra \\end{%1}'],
// @test ExtraCloseMissingOpen
close: ['ExtraCloseMissingOpen', 'Extra close brace or missing open brace'],
// @test MissingLeftExtraRight
right: ['MissingLeftExtraRight', 'Missing \\left or extra \\right'],
middle: ['ExtraMiddle', 'Extra \\middle']
};
/**
* @override
*/
public global: EnvList = {};
private _env: EnvList;
private _properties: PropList = {};
/**
* @constructor
* @extends {MmlStack}
*/
constructor(protected factory: StackItemFactory, ...nodes: MmlNode[]) {
super(nodes);
if (this.isOpen) {
this._env = {};
}
}
/**
* @return {string} The type of the stack item.
*/
public get kind(): string {
return 'base';
}
/**
* @return {EnvList} Get the private environment
*/
public get env(): EnvList {
return this._env;
}
/**
* Set the private environment
* @param {EnvList} value New private environemt.
*/
public set env(value: EnvList) {
this._env = value;
}
/**
* Default is to copy local environment when pushed on stack
*/
public get copyEnv() {
return true;
}
/**
* @override
*/
public getProperty(key: string): Prop {
return this._properties[key];
}
/**
* @override
*/
public setProperty(key: string, value: Prop) {
this._properties[key] = value;
return this;
}
/**
* @return {boolean} True if item is an opening entity, i.e., it expects a
* closing counterpart on the stack later.
*/
get isOpen(): boolean {
return false;
}
/**
* @return {boolean} True if item is an closing entity, i.e., it needs an
* opening counterpart already on the stack.
*/
get isClose(): boolean {
return false;
}
/**
* @return {boolean} True if item is final, i.e., it contains one or multiple
* finished parsed nodes.
*/
get isFinal(): boolean {
return false;
}
/**
* @override
*/
public isKind(kind: string) {
return kind === this.kind;
}
/**
* @override
*/
public checkItem(item: StackItem): CheckType {
if (item.isKind('over') && this.isOpen) {
item.setProperty('num', this.toMml(false));
this.Clear();
}
if (item.isKind('cell') && this.isOpen) {
if (item.getProperty('linebreak')) {
return BaseItem.fail;
}
// @test Ampersand-error
throw new TexError('Misplaced', 'Misplaced %1', item.getName());
}
if (item.isClose && this.getErrors(item.kind)) {
// @test ExtraOpenMissingClose, ExtraCloseMissingOpen,
// MissingLeftExtraRight, MissingBeginExtraEnd
const [id, message] = this.getErrors(item.kind);
throw new TexError(id, message, item.getName());
}
if (!item.isFinal) {
return BaseItem.success;
}
this.Push(item.First);
return BaseItem.fail;
}
/**
* Clears the item's environment.
*/
public clearEnv() {
for (const id of Object.keys(this.env)) {
delete this.env[id];
}
}
/**
* @override
*/
public setProperties(def: PropList) {
Object.assign(this._properties, def);
return this;
}
/**
* @override
*/
public getName() {
return this.getProperty('name') as string;
}
/**
* @override
*/
public toString() {
return this.kind + '[' + this.nodes.join('; ') + ']';
}
/**
* Get error messages for a particular types of stack items. This reads error
* messages from the static errors object, which can be extended in
* subclasses.
* @param {string} kind The stack item type.
* @return {string[]} The list of arguments for the TeXError.
*/
public getErrors(kind: string): string[] {
const CLASS = (this.constructor as typeof BaseItem);
return (CLASS.errors || {})[kind] || BaseItem.errors[kind];
}
}

View File

@@ -0,0 +1,62 @@
/*************************************************************
*
* Copyright (c) 2009-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview A factory for stack items. This allows particular items to be
* overwritten later.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {StackItemClass, StackItem, BaseItem} from './StackItem.js';
import ParseOptions from './ParseOptions.js';
import {AbstractFactory} from '../../core/Tree/Factory.js';
class DummyItem extends BaseItem {}
/**
* The StackItemFactory is initially populated with the default stack item
* classes. They can be changed, deleted or added to, if and when necessary.
*
* @constructor
* @extends {AbstractFactory}
*/
export default class StackItemFactory extends AbstractFactory<StackItem, StackItemClass> {
/**
* @override
*/
public static DefaultStackItems: {[kind: string]: StackItemClass} = {
[DummyItem.prototype.kind]: DummyItem
};
/**
* @override
*/
public defaultKind = 'dummy';
/**
* The parser configuration.
* @type {ParseOptions}
*/
public configuration: ParseOptions = null;
}

82
node_modules/mathjax-full/ts/input/tex/Symbol.ts generated vendored Normal file
View File

@@ -0,0 +1,82 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Symbol classes.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {Args, Attributes, ParseMethod} from './Types.js';
/**
* Symbol class
*/
export class Symbol {
/**
* @constructor
* @param {string} symbol The symbol parsed.
* @param {string} char The corresponding translation.
* @param {Attributes} attributes The attributes for the translation.
*/
constructor(private _symbol: string, private _char: string,
private _attributes: Attributes) {
}
public get symbol(): string {
return this._symbol;
}
public get char(): string {
return this._char;
}
public get attributes(): Attributes {
return this._attributes;
}
}
export class Macro {
/**
* @constructor
* @param {string} symbol The symbol parsed
* @param {ParseMethod} func The parsing function for that symbol.
* @param {Args[]} args Additional arguments for the function.
*/
constructor(private _symbol: string, private _func: ParseMethod,
private _args: Args[] = []) {
}
public get symbol(): string {
return this._symbol;
}
public get func(): ParseMethod {
return this._func;
}
public get args(): Args[] {
return this._args;
}
}

392
node_modules/mathjax-full/ts/input/tex/SymbolMap.ts generated vendored Normal file
View File

@@ -0,0 +1,392 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Symbol map classes.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {Attributes, Args, ParseMethod, ParseInput, ParseResult} from './Types.js';
import {Symbol, Macro} from './Symbol.js';
import {MapHandler} from './MapHandler.js';
/**
* SymbolMaps are the base components for the input parsers.
*
* They provide a contains method that checks if a map is applicable (contains)
* a particular string. Implementing classes then perform the actual symbol
* parsing, from simple regular expression test, straight forward symbol mapping
* to transformational functionality on the parsed string.
*
* @interface
*/
export interface SymbolMap {
/**
* @return {string} The name of the map.
*/
name: string;
/**
* @return {ParseMethod} The default parsing method.
*/
parser: ParseMethod;
/**
* @param {string} symbol A symbol to parse.
* @return {boolean} True if the symbol map applies to the symbol.
*/
contains(symbol: string): boolean;
/**
* @param {string} symbol A symbol to parse.
* @return {ParseMethod} A parse method for the symbol.
*/
parserFor(symbol: string): ParseMethod;
/**
* @param {TexParser} env The current parser.
* @param {string} symbol A symbol to parse.
* @return {ParseResult} The parsed symbol and the rest of the string.
*/
parse([env, symbol]: ParseInput): ParseResult;
}
/**
* @param {ParseResult} result The result to check
* @return {ParseResult} True if result was void, result otherwise
*/
export function parseResult(result: ParseResult): ParseResult {
return result === void 0 ? true : result;
}
/**
* Abstract implementation of symbol maps.
* @template T
*/
export abstract class AbstractSymbolMap<T> implements SymbolMap {
/**
* @constructor
* @implements {SymbolMap}
* @param {string} name Name of the mapping.
* @param {ParseMethod} parser The parser for the mappiong.
*/
constructor(private _name: string, private _parser: ParseMethod) {
MapHandler.register(this);
}
/**
* @override
*/
public get name(): string {
return this._name;
}
/**
* @override
*/
public abstract contains(symbol: string): boolean;
/**
* @override
*/
public parserFor(symbol: string) {
return this.contains(symbol) ? this.parser : null;
}
/**
* @override
*/
public parse([env, symbol]: ParseInput) {
let parser = this.parserFor(symbol);
let mapped = this.lookup(symbol);
return (parser && mapped) ? parseResult(parser(env, mapped as any)) : null;
}
public set parser(parser: ParseMethod) {
this._parser = parser;
}
public get parser(): ParseMethod {
return this._parser;
}
/**
* @param {string} symbol
* @return {T}
*/
public abstract lookup(symbol: string): T;
}
/**
* Regular expressions used for parsing strings.
*/
export class RegExpMap extends AbstractSymbolMap<string> {
/**
* @constructor
* @extends {AbstractSymbolMap}
* @param {string} name Name of the mapping.
* @param {ParseMethod} parser The parser for the mappiong.
* @param {RegExp} regexp The regular expression.
*/
constructor(name: string, parser: ParseMethod, private _regExp: RegExp) {
super(name, parser);
}
/**
* @override
*/
public contains(symbol: string) {
return this._regExp.test(symbol);
}
/**
* @override
*/
public lookup(symbol: string): string {
return this.contains(symbol) ? symbol : null;
}
}
/**
* Parse maps associate strings with parsing functionality.
* @constructor
* @extends {AbstractSymbolMap}
* @template K
*/
export abstract class AbstractParseMap<K> extends AbstractSymbolMap<K> {
private map: Map<string, K> = new Map<string, K>();
/**
* @override
*/
public lookup(symbol: string): K {
return this.map.get(symbol);
}
/**
* @override
*/
public contains(symbol: string) {
return this.map.has(symbol);
}
/**
* Sets mapping for a symbol.
* @param {string} symbol The symbol to map.
* @param {K} object The symbols value in the mapping's codomain.
*/
public add(symbol: string, object: K) {
this.map.set(symbol, object);
}
/**
* Removes a symbol from the map
* @param {string} symbol The symbol to remove
*/
public remove(symbol: string) {
this.map.delete(symbol);
}
}
/**
* Maps symbols that can all be parsed with the same method.
*
* @constructor
* @extends {AbstractParseMap}
*/
export class CharacterMap extends AbstractParseMap<Symbol> {
/**
* @constructor
* @param {string} name Name of the mapping.
* @param {ParseMethod} parser The parser for the mapping.
* @param {JSON} json The JSON representation of the character mapping.
*/
constructor(name: string, parser: ParseMethod,
json: {[index: string]: string | [string, Attributes]}) {
super(name, parser);
for (const key of Object.keys(json)) {
let value = json[key];
let [char, attrs] = (typeof(value) === 'string') ? [value, null] : value;
let character = new Symbol(key, char, attrs);
this.add(key, character);
}
}
}
/**
* Maps symbols that are delimiters, that are all parsed with the same method.
*
* @constructor
* @extends {CharacterMap}
*/
export class DelimiterMap extends CharacterMap {
/**
* @override
*/
public parse([env, symbol]: ParseInput) {
return super.parse([env, '\\' + symbol]);
}
}
/**
* Maps macros that all bring their own parsing method.
*
* @constructor
* @extends {AbstractParseMap}
*/
export class MacroMap extends AbstractParseMap<Macro> {
/**
* @constructor
* @param {string} name Name of the mapping.
* @param {JSON} json The JSON representation of the macro map.
* @param {Record<string, ParseMethod>} functionMap Collection of parse
* functions for the single macros.
*/
constructor(name: string,
json: {[index: string]: string | Args[]},
functionMap: Record<string, ParseMethod>) {
super(name, null);
for (const key of Object.keys(json)) {
let value = json[key];
let [func, ...attrs] = (typeof(value) === 'string') ? [value] : value;
let character = new Macro(key, functionMap[func as string], attrs);
this.add(key, character);
}
}
/**
* @override
*/
public parserFor(symbol: string) {
let macro = this.lookup(symbol);
return macro ? macro.func : null;
}
/**
* @override
*/
public parse([env, symbol]: ParseInput) {
let macro = this.lookup(symbol);
let parser = this.parserFor(symbol);
if (!macro || !parser) {
return null;
}
return parseResult(parser(env, macro.symbol, ...macro.args));
}
}
/**
* Maps macros that all bring their own parsing method.
*
* @constructor
* @extends {MacroMap}
*/
export class CommandMap extends MacroMap {
/**
* @override
*/
public parse([env, symbol]: ParseInput) {
let macro = this.lookup(symbol);
let parser = this.parserFor(symbol);
if (!macro || !parser) {
return null;
}
let saveCommand = env.currentCS;
env.currentCS = '\\' + symbol;
let result = parser(env, '\\' + macro.symbol, ...macro.args);
env.currentCS = saveCommand;
return parseResult(result);
}
}
/**
* Maps macros for environments. It has a general parsing method for
* environments, i.e., one that deals with begin/end, and each environment has
* its own parsing method returning the content.
*
* @constructor
* @extends {MacroMap}
*/
export class EnvironmentMap extends MacroMap {
/**
* @constructor
* @param {string} name Name of the mapping.
* @param {ParseMethod} parser The parser for the environments.
* @param {JSON} json The JSON representation of the macro map.
* @param {Record<string, ParseMethod>} functionMap Collection of parse
* functions for the single macros.
*/
constructor(name: string,
parser: ParseMethod,
json: {[index: string]: string | Args[]},
functionMap: Record<string, ParseMethod>) {
super(name, json, functionMap);
this.parser = parser;
}
/**
* @override
*/
public parse([env, symbol]: ParseInput) {
let macro = this.lookup(symbol);
let envParser = this.parserFor(symbol);
if (!macro || !envParser) {
return null;
}
return parseResult(this.parser(env, macro.symbol, envParser, macro.args));
}
}

680
node_modules/mathjax-full/ts/input/tex/Tags.ts generated vendored Normal file
View File

@@ -0,0 +1,680 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Class for generating tags, references, etc.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import TexParser from './TexParser.js';
import {MmlNode} from '../../core/MmlTree/MmlNode.js';
import {MathItem} from '../../core/MathItem.js';
import {EnvList} from './StackItem.js';
import ParseOptions from './ParseOptions.js';
import {OptionList} from '../../util/Options.js';
/**
* Simple class for label objects.
*/
export class Label {
/**
* @constructor
* @param {string=} tag The tag that's displayed.
* @param {string=} id The id that serves as reference.
*/
constructor(public tag: string = '???', public id: string = '') {}
}
/**
* A simple class for keeping track of tag information.
*/
export class TagInfo {
/**
* @constructor
* @param {string} env The environment name (e.g., align).
* @param {boolean} taggable Environment supports tags (e.g., align* does, but
* split does not.)
* @param {boolean} defaultTags Environment is tagged by default (e.g., align
* is, but align* is not).
* @param {string} tag The tag name (e.g., 1).
* @param {string} tagId The unique id for that tag (e.g., mjx-eqn:1).
* @param {string} tagFormat The formatted tag (e.g., "(1)").
* @param {boolean} noTag A no tagging command has been set (e.g., \notag,
* \nonumber).
* @param {string} labelId The label referring to the tag.
*/
constructor(readonly env: string = '',
readonly taggable: boolean = false,
readonly defaultTags: boolean = false,
public tag: string = null,
public tagId: string = '',
public tagFormat: string = '',
public noTag: boolean = false,
public labelId: string = '') {}
}
export interface Tags {
/**
* The global configurations in which the parsing takes place.
* @type {ParseOptions}
*/
configuration: ParseOptions;
/**
* IDs used in this equation.
* @type {Object.<boolean>}
*/
ids: {[key: string]: boolean};
/**
* IDs used in previous equations.
* @type {Object.<boolean>}
*/
allIds: {[key: string]: boolean};
/**
* Labels in the current equation.
* @type {Object.<Label>}
*/
labels: {[key: string]: Label};
/**
* Labels in previous equations.
* @type {Object.<Label>}
*/
allLabels: {[key: string]: Label};
/**
* The label to use for the next tag.
* @type {string}
*/
label: string;
/**
* True if the equation contains an undefined label and must be reprocessed later.
* @type {boolean}
*/
redo: boolean;
/**
* True when recompiling to update undefined references
* @type {boolean}
*/
refUpdate: boolean;
/**
* The environment that is currently tagged.
* @type {string}
*/
env: string;
/**
* The currently active tag.
* @type {TagInfo}
*/
currentTag: TagInfo;
/**
* How to format tags.
* @param {string} tag The tag string.
* @return {string} The formatted numbered tag.
*/
formatTag(tag: string): string;
/**
* How to format URLs for references.
* @param {string} id The reference id.
* @param {string} base The base URL in the reference.
* @return {}
*/
formatUrl(id: string, base: string): string;
/**
* Set the tag automatically, by incrementing equation number.
*/
autoTag(): void;
/**
* @return {MmlNode|void} Generates and returns the tag node.
*/
getTag(): MmlNode | void;
/**
* Clears tagging information.
*/
clearTag(): void;
/**
* Resets the tag structure after an expression has been typeset.
*/
resetTag(): void;
/**
* Fully resets the tag structure, in particular all the tagging and label
* history.
* @param {number} offset A new offset value to start counting ids from.
*/
reset(offset?: number): void;
/**
* Initialise tagging for a MathItem
* (clear equation-specific labels and ids, set counter
* and check for recompile)
* @param {MathItem} math The MathItem for the current equation
*/
startEquation(math: MathItem<any, any, any>): void;
/**
* Move equation-specific labels and ids to global ones,
* save the counter, and mark the MathItem for redos
*/
finishEquation(math: MathItem<any, any, any>): void;
/**
* Finalizes tag creation.
* @param {MmlNode} node
* @param {EnvList} env List of environment properties.
* @return {MmlNode} The newly created tag.
*/
finalize(node: MmlNode, env: EnvList): MmlNode;
/**
* Starts tagging on a given environment.
* @param {string} env The name of the environment.
* @param {boolean} taggable True if taggable.
* @param {boolean} defaultTags True if tagged by default.
*/
start(env: string, taggable: boolean, defaultTags: boolean): void;
/**
* End tagging.
*/
end(): void;
/**
* Computes the next tag.
* @param {string} tag The tag content.
* @param {boolean} noFormat True if tag should not be formatted.
*/
tag(tag: string, noFormat: boolean): void;
/**
* Call an explicit no tag.
*/
notag(): void;
/**
* Entag an element by creating a table around it.
* @param {MmlNode} node The node to be tagged.
* @param {MmlNode} tag The tag node.
* @return {MmlNode} The table node containing the original node and tag.
*/
enTag(node: MmlNode, tag: MmlNode): MmlNode;
}
export class AbstractTags implements Tags {
/**
* Current equation number.
* @type {number}
*/
protected counter: number = 0;
/**
* Equation number as equation begins.
* @type {number}
*/
protected allCounter: number = 0;
/**
* @override
*/
public configuration: ParseOptions = null;
/**
* @override
*/
public ids: {[key: string]: boolean} = {};
/**
* @override
*/
public allIds: {[key: string]: boolean} = {};
/**
* @override
*/
public labels: {[key: string]: Label} = {};
/**
* @override
*/
public allLabels: {[key: string]: Label} = {};
/**
* @override
*/
public redo: boolean = false;
/**
* @override
*/
public refUpdate: boolean = false;
/**
* @override
*/
public currentTag: TagInfo = new TagInfo();
/**
* Chronology of all previous tags, in case we need to look something up in
* the finalize method.
* @type {TagInfo[]}
*/
protected history: TagInfo[] = [];
private stack: TagInfo[] = [];
/**
* @override
*/
public start(env: string, taggable: boolean, defaultTags: boolean) {
if (this.currentTag) {
this.stack.push(this.currentTag);
}
this.currentTag = new TagInfo(env, taggable, defaultTags);
}
public get env() {
return this.currentTag.env;
}
/**
* @override
*/
public end() {
this.history.push(this.currentTag);
this.currentTag = this.stack.pop();
}
/**
* @override
*/
public tag(tag: string, noFormat: boolean) {
this.currentTag.tag = tag;
this.currentTag.tagFormat = noFormat ? tag : this.formatTag(tag);
this.currentTag.noTag = false;
}
/**
* @override
*/
public notag() {
this.tag('', true);
this.currentTag.noTag = true;
}
protected get noTag(): boolean {
return this.currentTag.noTag;
}
public set label(label: string) {
this.currentTag.labelId = label;
}
public get label() {
return this.currentTag.labelId;
}
/**
* @override
*/
public formatUrl(id: string, base: string) {
return base + '#' + encodeURIComponent(id);
}
/**
* @override
*/
public formatTag(tag: string) {
return '(' + tag + ')';
}
/**
* How to format ids for labelling equations.
* @param {string} id The unique part of the id (e.g., label or number).
* @return {string} The formatted id.
*/
protected formatId(id: string): string {
return 'mjx-eqn:' + id.replace(/\s/g, '_');
}
/**
* How to format numbers in tags.
* @param {number} n The tag number.
* @return {string} The formatted number.
*/
protected formatNumber(n: number): string {
return n.toString();
}
// Tag handling functions.
/**
* @override
*/
public autoTag() {
if (this.currentTag.tag == null) {
this.counter++;
this.tag(this.formatNumber(this.counter), false);
}
}
/**
* @override
*/
public clearTag() {
this.label = '';
this.tag(null, true);
this.currentTag.tagId = '';
}
/**
* @override
*/
public getTag(force: boolean = false) {
if (force) {
this.autoTag();
return this.makeTag();
}
const ct = this.currentTag;
if (ct.taggable && !ct.noTag) {
if (ct.defaultTags) {
this.autoTag();
}
if (ct.tag) {
return this.makeTag();
}
}
return null;
}
/**
* @override
*/
public resetTag() {
this.history = [];
this.redo = false;
this.refUpdate = false;
this.clearTag();
}
/**
* @override
*/
public reset(offset: number = 0) {
this.resetTag();
this.counter = this.allCounter = offset;
this.allLabels = {};
this.allIds = {};
}
/**
* @override
*/
public startEquation(math: MathItem<any, any, any>) {
this.history = [];
this.stack = [];
this.clearTag();
this.currentTag = new TagInfo('', undefined, undefined);
this.labels = {};
this.ids = {};
this.counter = this.allCounter;
this.redo = false;
const recompile = math.inputData.recompile;
if (recompile) {
this.refUpdate = true;
this.counter = recompile.counter;
}
}
/**
* @override
*/
public finishEquation(math: MathItem<any, any, any>) {
if (this.redo) {
math.inputData.recompile = {
state: math.state(),
counter: this.allCounter
};
}
if (!this.refUpdate) {
this.allCounter = this.counter;
}
Object.assign(this.allIds, this.ids);
Object.assign(this.allLabels, this.labels);
}
/**
* @override
*/
public finalize(node: MmlNode, env: EnvList): MmlNode {
if (!env.display || this.currentTag.env ||
this.currentTag.tag == null) {
return node;
}
let tag = this.makeTag();
let table = this.enTag(node, tag);
return table;
}
/**
* @override
*/
public enTag = function(node: MmlNode, tag: MmlNode): MmlNode {
let nf = this.configuration.nodeFactory;
let cell = nf.create('node', 'mtd', [node]);
let row = nf.create('node', 'mlabeledtr', [tag, cell]);
let table = nf.create('node', 'mtable', [row], {
side: this.configuration.options['tagSide'],
minlabelspacing: this.configuration.options['tagIndent'],
displaystyle: true
});
return table;
};
/**
* Sets the tag id.
*/
private makeId() {
this.currentTag.tagId = this.formatId(
this.configuration.options['useLabelIds'] ?
(this.label || this.currentTag.tag) : this.currentTag.tag);
}
/**
* @return {MmlNode} The actual tag node as an mtd.
*/
private makeTag(): MmlNode {
this.makeId();
if (this.label) {
this.labels[this.label] = new Label(this.currentTag.tag, this.currentTag.tagId);
}
let mml = new TexParser('\\text{' + this.currentTag.tagFormat + '}', {},
this.configuration).mml();
return this.configuration.nodeFactory.create('node', 'mtd', [mml],
{id: this.currentTag.tagId});
}
}
/**
* No tags, except where explicitly set.
* @constructor
* @extends {AbstractTags}
*/
export class NoTags extends AbstractTags {
/**
* @override
*/
public autoTag() {}
/**
* @override
*/
public getTag() {
return !this.currentTag.tag ? null : super.getTag();
}
}
/**
* Tags every display formula. Exceptions are: Environments that explicitly
* disallow tags, e.g., equation*.
* @constructor
* @extends {AbstractTags}
*/
export class AllTags extends AbstractTags {
/**
* @override
*/
public finalize(node: MmlNode, env: EnvList) {
if (!env.display || this.history.find(
function(x: TagInfo) { return x.taggable; })) {
return node;
}
let tag = this.getTag(true);
return this.enTag(node, tag);
}
}
/**
* Class interface for factory.
* @interface
*/
export interface TagsClass {
new (): Tags;
}
export namespace TagsFactory {
let tagsMapping = new Map<string, TagsClass>([
['none', NoTags],
['all', AllTags]
]);
let defaultTags = 'none';
/**
* The default options for tagging
* @type {OptionList}
*/
export let OPTIONS: OptionList = {
// Tagging style, used to be autonumber in v2.
tags: defaultTags,
// This specifies the side on which \tag{} macros will place the tags.
// Set to 'left' to place on the left-hand side.
tagSide: 'right',
// This is the amount of indentation (from right or left) for the tags.
tagIndent: '0.8em',
// make element ID's use \label name rather than equation number
// MJ puts in an equation prefix: mjx-eqn
// When true it uses the label name XXX as mjx-eqn:XXX
// If false it uses the actual number N that is displayed: mjx-eqn:N
useLabelIds: true,
// Set to true in order to prevent error messages for duplicate label ids
ignoreDuplicateLabels: false
};
/**
* Add a tagging object.
* @param {string} name Name of the tagging object.
* @param {TagsClass} constr The class of the Tagging object.
*/
export let add = function(name: string, constr: TagsClass) {
tagsMapping.set(name, constr);
};
/**
* Adds a list of tagging objects to the factory.
* @param {{[name: string]: TagsClass}} tags The list of tagging objects.
*/
export let addTags = function(tags: {[name: string]: TagsClass}) {
for (const key of Object.keys(tags)) {
TagsFactory.add(key, tags[key]);
}
};
/**
* Creates a new tagging object.
* @param {string} name The name of the tagging object.
* @return {Tags} The newly created object.
*/
export let create = function(name: string): Tags {
let constr = tagsMapping.get(name) || tagsMapping.get(defaultTags);
if (!constr) {
throw Error('Unknown tags class');
}
return new constr();
};
/**
* Set the name of the default tagging object.
* @param {string} name The default.
*/
export let setDefault = function(name: string) {
defaultTags = name;
};
/**
* @return {Tags} The default tagging object.
*/
export let getDefault = function(): Tags {
return TagsFactory.create(defaultTags);
};
}

169
node_modules/mathjax-full/ts/input/tex/TexConstants.ts generated vendored Normal file
View File

@@ -0,0 +1,169 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Constant definitions for the TeX Parser. These should
* eventually be combined with the MathML structure.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
export namespace TexConstant {
export const Variant = {
NORMAL: 'normal',
BOLD: 'bold',
ITALIC: 'italic',
BOLDITALIC: 'bold-italic',
DOUBLESTRUCK: 'double-struck',
FRAKTUR: 'fraktur',
BOLDFRAKTUR: 'bold-fraktur',
SCRIPT: 'script',
BOLDSCRIPT: 'bold-script',
SANSSERIF: 'sans-serif',
BOLDSANSSERIF: 'bold-sans-serif',
SANSSERIFITALIC: 'sans-serif-italic',
SANSSERIFBOLDITALIC: 'sans-serif-bold-italic',
MONOSPACE: 'monospace',
INITIAL: 'inital',
TAILED: 'tailed',
LOOPED: 'looped',
STRETCHED: 'stretched',
CALLIGRAPHIC: '-tex-calligraphic',
BOLDCALLIGRAPHIC: '-tex-bold-calligraphic',
OLDSTYLE: '-tex-oldstyle',
BOLDOLDSTYLE: '-tex-bold-oldstyle',
MATHITALIC: '-tex-mathit'
};
export const Form = {
PREFIX: 'prefix',
INFIX: 'infix',
POSTFIX: 'postfix'
};
export const LineBreak = {
AUTO: 'auto',
NEWLINE: 'newline',
NOBREAK: 'nobreak',
GOODBREAK: 'goodbreak',
BADBREAK: 'badbreak'
};
export const LineBreakStyle = {
BEFORE: 'before',
AFTER: 'after',
DUPLICATE: 'duplicate',
INFIXLINBREAKSTYLE: 'infixlinebreakstyle'
};
export const IndentAlign = {
LEFT: 'left',
CENTER: 'center',
RIGHT: 'right',
AUTO: 'auto',
ID: 'id',
INDENTALIGN: 'indentalign'
};
export const IndentShift = {
INDENTSHIFT: 'indentshift'
};
export const LineThickness = {
THIN: 'thin',
MEDIUM: 'medium',
THICK: 'thick'
};
export const Notation = {
LONGDIV: 'longdiv',
ACTUARIAL: 'actuarial',
PHASORANGLE: 'phasorangle',
RADICAL: 'radical',
BOX: 'box',
ROUNDEDBOX: 'roundedbox',
CIRCLE: 'circle',
LEFT: 'left',
RIGHT: 'right',
TOP: 'top',
BOTTOM: 'bottom',
UPDIAGONALSTRIKE: 'updiagonalstrike',
DOWNDIAGONALSTRIKE: 'downdiagonalstrike',
VERTICALSTRIKE: 'verticalstrike',
HORIZONTALSTRIKE: 'horizontalstrike',
NORTHEASTARROW: 'northeastarrow',
MADRUWB: 'madruwb',
UPDIAGONALARROW: 'updiagonalarrow'
};
export const Align = {
TOP: 'top',
BOTTOM: 'bottom',
CENTER: 'center',
BASELINE: 'baseline',
AXIS: 'axis',
LEFT: 'left',
RIGHT: 'right'
};
export const Lines = {
NONE: 'none',
SOLID: 'solid',
DASHED: 'dashed'
};
export const Side = {
LEFT: 'left',
RIGHT: 'right',
LEFTOVERLAP: 'leftoverlap',
RIGHTOVERLAP: 'rightoverlap'
};
export const Width = {
AUTO: 'auto',
FIT: 'fit'
};
export const Actiontype = {
TOGGLE: 'toggle',
STATUSLINE: 'statusline',
TOOLTIP: 'tooltip',
INPUT: 'input'
};
export const Overflow = {
LINBREAK: 'linebreak',
SCROLL: 'scroll',
ELIDE: 'elide',
TRUNCATE: 'truncate',
SCALE: 'scale'
};
export const Unit = {
EM: 'em',
EX: 'ex',
PX: 'px',
IN: 'in',
CM: 'cm',
MM: 'mm',
PT: 'pt',
PC: 'pc'
};
}

85
node_modules/mathjax-full/ts/input/tex/TexError.ts generated vendored Normal file
View File

@@ -0,0 +1,85 @@
/*************************************************************
*
* Copyright (c) 2009-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Error class for the TeX parser.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
export default class TexError {
private static pattern =
/%(\d+|\{\d+\}|\{[a-z]+:\%\d+(?:\|(?:%\{\d+\}|%.|[^\}])*)+\}|.)/g;
/**
* Default error message.
* @type {string}
*/
public message: string;
/**
* The old MathJax processing function.
* @param {string} str The basic error message.
* @param {string[]} args The arguments to be replaced in the error message.
* @return {string} The processed error string.
*/
private static processString(str: string, args: string[]): string {
let parts = str.split(TexError.pattern);
for (let i = 1, m = parts.length; i < m; i += 2) {
let c = parts[i].charAt(0); // first char will be { or \d or a char to be
// kept literally
if (c >= '0' && c <= '9') { // %n
parts[i] = args[parseInt(parts[i], 10) - 1];
if (typeof parts[i] === 'number') {
parts[i] = parts[i].toString();
}
} else if (c === '{') { // %{n} or %{plural:%n|...}
c = parts[i].substr(1);
if (c >= '0' && c <= '9') { // %{n}
parts[i] = args[parseInt(parts[i].substr(1, parts[i].length - 2), 10) - 1];
if (typeof parts[i] === 'number') {
parts[i] = parts[i].toString();
}
} else { // %{plural:%n|...}
let match = parts[i].match(/^\{([a-z]+):%(\d+)\|(.*)\}$/);
if (match) {
// Removed plural here.
parts[i] = '%' + parts[i];
}
}
}
if (parts[i] == null) {
parts[i] = '???';
}
}
return parts.join('');
}
/**
* @constructor
* @param{string} id message id (for localization)
* @param{string} message text of English message
* @param{string[]=} rest any substitution arguments
*/
constructor(public id: string, message: string, ...rest: string[]) {
this.message = TexError.processString(message, rest);
}
}

514
node_modules/mathjax-full/ts/input/tex/TexParser.ts generated vendored Normal file
View File

@@ -0,0 +1,514 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview The TexParser. Implements the basic parsing functionality and
* administers the global stack and tree objects.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import ParseUtil from './ParseUtil.js';
import {HandlerType} from './MapHandler.js';
import Stack from './Stack.js';
import StackItemFactory from './StackItemFactory.js';
import {Tags} from './Tags.js';
import TexError from './TexError.js';
import {MmlNode, AbstractMmlNode} from '../../core/MmlTree/MmlNode.js';
import {ParseInput, ParseResult} from './Types.js';
import ParseOptions from './ParseOptions.js';
import {StackItem, EnvList} from './StackItem.js';
import {Symbol} from './Symbol.js';
import {OptionList} from '../../util/Options.js';
/**
* The main Tex Parser class.
*/
export default class TexParser {
/**
* Counter for recursive macros.
* @type {number}
*/
public macroCount: number = 0;
/**
* The stack for items and created nodes.
* @type {Stack}
*/
public stack: Stack;
/**
* Current position in the string that is parsed.
* @type {number}
*/
public i: number = 0;
/**
* The last command sequence
* @type {string}
*/
public currentCS: string = '';
/**
* @constructor
* @param {string} string The string to parse.
* @param {EnvList} env The intial environment representing the current parse
* state of the overall expression translation.
* @param {ParseOptions} configuration A parser configuration.
*/
constructor(private _string: string, env: EnvList, public configuration: ParseOptions) {
const inner = env.hasOwnProperty('isInner');
const isInner = env['isInner'] as boolean;
delete env['isInner'];
let ENV: EnvList;
if (env) {
ENV = {};
for (const id of Object.keys(env)) {
ENV[id] = env[id];
}
}
this.configuration.pushParser(this);
this.stack = new Stack(this.itemFactory, ENV, inner ? isInner : true);
this.Parse();
this.Push(this.itemFactory.create('stop'));
}
/**
* @return {OptionList} The configuration options.
*/
get options(): OptionList {
return this.configuration.options;
}
/**
* @return {StackItemFactory} The factory for stack items.
*/
get itemFactory(): StackItemFactory {
return this.configuration.itemFactory;
}
/**
* @return {Tags} The tags style of this configuration.
*/
get tags(): Tags {
return this.configuration.tags;
}
/**
* Sets the string that should be parsed.
* @param {string} str The new string to parse.
*/
set string(str: string) {
this._string = str;
}
/**
* @return {string} The string that is currently parsed.
*/
get string(): string {
return this._string;
}
/**
* Parses the input with the specified kind of map.
* @param {HandlerType} kind Configuration name.
* @param {ParseInput} input Input to be parsed.
* @return {ParseResult} The output of the parsing function.
*/
public parse(kind: HandlerType, input: ParseInput): ParseResult {
return this.configuration.handlers.get(kind).parse(input);
}
/**
* Maps a symbol to its "parse value" if it exists.
* @param {HandlerType} kind Configuration name.
* @param {string} symbol The symbol to parse.
* @return {any} A boolean, Character, or Macro.
*/
public lookup(kind: HandlerType, symbol: string): any {
return this.configuration.handlers.get(kind).lookup(symbol);
}
/**
* Checks if a symbol is contained in one of the symbol mappings of the
* specified kind.
* @param {HandlerType} kind Configuration name.
* @param {string} symbol The symbol to parse.
* @return {boolean} True if the symbol is contained in the given types of
* symbol mapping.
*/
public contains(kind: HandlerType, symbol: string): boolean {
return this.configuration.handlers.get(kind).contains(symbol);
}
/**
* @override
*/
public toString(): string {
let str = '';
for (const config of Array.from(this.configuration.handlers.keys())) {
str += config + ': ' +
this.configuration.handlers.get(config as HandlerType) + '\n';
}
return str;
}
/**
* Parses the current input string.
*/
public Parse() {
let c: string;
while (this.i < this.string.length) {
c = this.getCodePoint();
this.i += c.length;
this.parse('character', [this, c]);
}
}
/**
* Pushes a new item onto the stack. The item can also be a Mml node,
* but if the mml item is an inferred row, push its children instead.
* @param {StackItem|MmlNode} arg The new item.
*/
public Push(arg: StackItem | MmlNode) {
if (arg instanceof AbstractMmlNode && arg.isInferred) {
this.PushAll(arg.childNodes);
} else {
this.stack.Push(arg);
}
}
/**
* Pushes a list of new items onto the stack.
* @param {StackItem|MmlNode[]} args The new items.
*/
public PushAll(args: (StackItem | MmlNode)[]) {
for (const arg of args) {
this.stack.Push(arg);
}
}
/**
* @return {MmlNode} The internal Mathml structure.
*/
public mml(): MmlNode {
if (!this.stack.Top().isKind('mml')) {
return null;
}
let node = this.stack.Top().First;
this.configuration.popParser();
return node;
}
/************************************************************************
*
* String handling routines
*/
/**
* Convert delimiter to character.
* @param {string} c The delimiter name.
* @return {string} The corresponding character.
*/
public convertDelimiter(c: string): string {
const symbol = this.lookup('delimiter', c) as Symbol;
return symbol ? symbol.char : null;
}
/**
* @return {string} Get the next unicode character in the string
*/
public getCodePoint(): string {
const code = this.string.codePointAt(this.i);
return code === undefined ? '' : String.fromCodePoint(code);
}
/**
* @return {boolean} True if the next character to parse is a space.
*/
public nextIsSpace(): boolean {
return !!this.string.charAt(this.i).match(/\s/);
}
/**
* @return {string} Get the next non-space character.
*/
public GetNext(): string {
while (this.nextIsSpace()) {
this.i++;
}
return this.getCodePoint();
}
/**
* @return {string} Get and return a control-sequence name
*/
public GetCS(): string {
let CS = this.string.slice(this.i).match(/^(([a-z]+) ?|[\uD800-\uDBFF].|.)/i);
if (CS) {
this.i += CS[0].length;
return CS[2] || CS[1];
} else {
this.i++;
return ' ';
}
}
/**
* Get and return a TeX argument (either a single character or control
* sequence, or the contents of the next set of braces).
* @param {string} name Name of the current control sequence.
* @param {boolean} noneOK? True if no argument is OK.
* @return {string} The next argument.
*/
public GetArgument(_name: string, noneOK?: boolean): string {
switch (this.GetNext()) {
case '':
if (!noneOK) {
// @test MissingArgFor
throw new TexError('MissingArgFor', 'Missing argument for %1', this.currentCS);
}
return null;
case '}':
if (!noneOK) {
// @test ExtraCloseMissingOpen
throw new TexError('ExtraCloseMissingOpen',
'Extra close brace or missing open brace');
}
return null;
case '\\':
this.i++;
return '\\' + this.GetCS();
case '{':
let j = ++this.i, parens = 1;
while (this.i < this.string.length) {
switch (this.string.charAt(this.i++)) {
case '\\': this.i++; break;
case '{': parens++; break;
case '}':
if (--parens === 0) {
return this.string.slice(j, this.i - 1);
}
break;
}
}
// @test MissingCloseBrace
throw new TexError('MissingCloseBrace', 'Missing close brace');
}
const c = this.getCodePoint();
this.i += c.length;
return c;
}
/**
* Get an optional LaTeX argument in brackets.
* @param {string} name Name of the current control sequence.
* @param {string} def? The default value for the optional argument.
* @return {string} The optional argument.
*/
public GetBrackets(_name: string, def?: string): string {
if (this.GetNext() !== '[') {
return def;
}
let j = ++this.i, parens = 0;
while (this.i < this.string.length) {
switch (this.string.charAt(this.i++)) {
case '{': parens++; break;
case '\\': this.i++; break;
case '}':
if (parens-- <= 0) {
// @test ExtraCloseLooking1
throw new TexError('ExtraCloseLooking',
'Extra close brace while looking for %1', '\']\'');
}
break;
case ']':
if (parens === 0) {
return this.string.slice(j, this.i - 1);
}
break;
}
}
// @test MissingCloseBracket
throw new TexError('MissingCloseBracket',
'Could not find closing \']\' for argument to %1', this.currentCS);
}
/**
* Get the name of a delimiter (check it in the delimiter list).
* @param {string} name Name of the current control sequence.
* @param {boolean} braceOK? Are braces around the delimiter OK.
* @return {string} The delimiter name.
*/
public GetDelimiter(name: string, braceOK?: boolean): string {
let c = this.GetNext(); this.i += c.length;
if (this.i <= this.string.length) {
if (c === '\\') {
c += this.GetCS();
} else if (c === '{' && braceOK) {
this.i--;
c = this.GetArgument(name).trim();
}
if (this.contains('delimiter', c)) {
return this.convertDelimiter(c);
}
}
// @test MissingOrUnrecognizedDelim1, MissingOrUnrecognizedDelim2
throw new TexError('MissingOrUnrecognizedDelim',
'Missing or unrecognized delimiter for %1', this.currentCS);
}
/**
* Get a dimension (including its units).
* @param {string} name Name of the current control sequence.
* @return {string} The dimension string.
*/
public GetDimen(name: string): string {
if (this.GetNext() === '{') {
let dimen = this.GetArgument(name);
let [value, unit] = ParseUtil.matchDimen(dimen);
if (value) {
// @test Raise In Line, Lower 2, (Raise|Lower) Negative
return value + unit;
}
} else {
// @test Above, Raise, Lower, Modulo, Above With Delims
let dimen = this.string.slice(this.i);
let [value, unit, length] = ParseUtil.matchDimen(dimen, true);
if (value) {
this.i += length;
return value + unit;
}
}
// @test MissingDimOrUnits
throw new TexError('MissingDimOrUnits',
'Missing dimension or its units for %1', this.currentCS);
}
/**
* Get everything up to the given control sequence (token)
* @param {string} name Name of the current control sequence.
* @param {string} token The element until where to parse.
* @return {string} The text between the current position and the given token.
*/
public GetUpTo(_name: string, token: string): string {
while (this.nextIsSpace()) {
this.i++;
}
let j = this.i;
let parens = 0;
while (this.i < this.string.length) {
let k = this.i;
let c = this.GetNext(); this.i += c.length;
switch (c) {
case '\\': c += this.GetCS(); break;
case '{': parens++; break;
case '}':
if (parens === 0) {
// @test ExtraCloseLooking2
throw new TexError('ExtraCloseLooking',
'Extra close brace while looking for %1', token);
}
parens--;
break;
}
if (parens === 0 && c === token) {
return this.string.slice(j, k);
}
}
// @test TokenNotFoundForCommand
throw new TexError('TokenNotFoundForCommand',
'Could not find %1 for %2', token, this.currentCS);
}
/**
* Parse the arguments of a control sequence in a new parser instance.
* @param {string} name Name of the current control sequence.
* @return {MmlNode} The parsed node.
*/
public ParseArg(name: string): MmlNode {
return new TexParser(this.GetArgument(name), this.stack.env,
this.configuration).mml();
}
/**
* Parses a given string up to a given token in a new parser instance.
* @param {string} name Name of the current control sequence.
* @param {string} token A Token at which to end parsing.
* @return {MmlNode} The parsed node.
*/
public ParseUpTo(name: string, token: string): MmlNode {
return new TexParser(this.GetUpTo(name, token), this.stack.env,
this.configuration).mml();
}
/**
* Get a delimiter or empty argument
* @param {string} name Name of the current control sequence.
* @return {string} The delimiter.
*/
public GetDelimiterArg(name: string): string {
let c = ParseUtil.trimSpaces(this.GetArgument(name));
if (c === '') {
return null;
}
if (this.contains('delimiter', c)) {
return c;
}
// @test MissingOrUnrecognizedDelim
throw new TexError('MissingOrUnrecognizedDelim',
'Missing or unrecognized delimiter for %1', this.currentCS);
}
/**
* @return {boolean} True if a star follows the control sequence name.
*/
public GetStar(): boolean {
let star = (this.GetNext() === '*');
if (star) {
this.i++;
}
return star;
}
/**
* Convenience method to create nodes with the node factory of the current
* configuration.
* @param {string} kind The kind of node to create.
* @param {any[]} ...rest The remaining arguments for the creation method.
* @return {MmlNode} The newly created node.
*/
public create(kind: string, ...rest: any[]): MmlNode {
return this.configuration.nodeFactory.create(kind, ...rest);
}
}

38
node_modules/mathjax-full/ts/input/tex/Types.ts generated vendored Normal file
View File

@@ -0,0 +1,38 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Basic type definitions.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {StackItem} from './StackItem.js';
import {Symbol} from './Symbol.js';
import TexParser from './TexParser.js';
export type Args = boolean | number | string | null;
export type Attributes = Record<string, Args>;
export type Environment = Record<string, Args>;
export type ParseInput = [TexParser, string];
export type ParseResult = void | boolean | StackItem;
export type ParseMethod = (parser: TexParser, c: string | Symbol | StackItem, ...rest: any[]) => ParseResult;

View File

@@ -0,0 +1,78 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Configuration file for the action package.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {Configuration} from '../Configuration.js';
import TexParser from '../TexParser.js';
import {CommandMap} from '../SymbolMap.js';
import {ParseMethod} from '../Types.js';
import BaseMethods from '../base/BaseMethods.js';
// Namespace
export let ActionMethods: Record<string, ParseMethod> = {};
ActionMethods.Macro = BaseMethods.Macro;
/**
* Implement \toggle {math1} {math2} ... \endtoggle
* (as an <maction actiontype="toggle">)
* @param {TexParser} parser The current tex parser.
* @param {string} name The name of the calling macro.
*/
ActionMethods.Toggle = function(parser: TexParser, name: string) {
const children = [];
let arg;
while ((arg = parser.GetArgument(name)) !== '\\endtoggle') {
children.push(
new TexParser(arg, parser.stack.env, parser.configuration).mml());
}
parser.Push(
parser.create('node', 'maction', children, {actiontype: 'toggle'}));
};
/**
* Implement \mathtip{math}{tip}
* (an an <maction actiontype="tooltip">)
* @param {TexParser} parser The current tex parser.
* @param {string} name The name of the calling macro.
*/
ActionMethods.Mathtip = function(parser: TexParser, name: string) {
const arg = parser.ParseArg(name);
const tip = parser.ParseArg(name);
parser.Push(
parser.create('node', 'maction', [arg, tip], {actiontype: 'tooltip'}));
};
new CommandMap('action-macros', {
toggle: 'Toggle',
mathtip: 'Mathtip',
texttip: ['Macro', '\\mathtip{#1}{\\text{#2}}', 2]
}, ActionMethods);
export const ActionConfiguration = Configuration.create(
'action', {handler: {macro: ['action-macros']}}
);

View File

@@ -0,0 +1,86 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Configuration file for the AMS package.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {Configuration, ParserConfiguration} from '../Configuration.js';
import {MultlineItem, FlalignItem} from './AmsItems.js';
import {AbstractTags} from '../Tags.js';
import {NEW_OPS} from './AmsMethods.js';
import './AmsMappings.js';
import {CommandMap} from '../SymbolMap.js';
/**
* Standard AMS style tagging.
* @constructor
* @extends {AbstractTags}
*/
export class AmsTags extends AbstractTags { }
/**
* Init method for AMS package.
* @param {ParserConfiguration} config The current configuration.
*/
let init = function(config: ParserConfiguration) {
new CommandMap(NEW_OPS, {}, {});
config.append(Configuration.local({handler: {macro: [NEW_OPS]},
priority: -1}));
};
export const AmsConfiguration = Configuration.create(
'ams', {
handler: {
character: ['AMSmath-operatorLetter'],
delimiter: ['AMSsymbols-delimiter', 'AMSmath-delimiter'],
macro: ['AMSsymbols-mathchar0mi', 'AMSsymbols-mathchar0mo',
'AMSsymbols-delimiter', 'AMSsymbols-macros',
'AMSmath-mathchar0mo', 'AMSmath-macros', 'AMSmath-delimiter'],
environment: ['AMSmath-environment']
},
items: {
[MultlineItem.prototype.kind]: MultlineItem,
[FlalignItem.prototype.kind]: FlalignItem,
},
tags: {'ams': AmsTags},
init: init,
config: (_config: ParserConfiguration, jax: any) => {
//
// Move multlineWidth from old location to ams block (remove in next version)
//
if (jax.parseOptions.options.multlineWidth) {
jax.parseOptions.options.ams.multlineWidth = jax.parseOptions.options.multlineWidth;
}
delete jax.parseOptions.options.multlineWidth;
},
options: {
multlineWidth: '',
ams: {
multlineWidth: '100%', // The width to use for multline environments.
multlineIndent: '1em', // The margin to use on both sides of multline environments.
}
}
}
);

224
node_modules/mathjax-full/ts/input/tex/ams/AmsItems.ts generated vendored Normal file
View File

@@ -0,0 +1,224 @@
/*************************************************************
*
* Copyright (c) 2009-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview StackItems needed for parsing AMS math commands.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {ArrayItem, EqnArrayItem} from '../base/BaseItems.js';
import ParseUtil from '../ParseUtil.js';
import NodeUtil from '../NodeUtil.js';
import TexError from '../TexError.js';
import {TexConstant} from '../TexConstants.js';
import {MmlNode} from '../../../core/MmlTree/MmlNode.js';
/**
* Item dealing with multiline environments as a special case of arrays. Note,
* that all other AMS equation environments (e.g., align, split) can be handled
* by the regular EqnArrayItem class.
*
* Handles tagging information according to the given tagging style.
*/
export class MultlineItem extends ArrayItem {
/**
* @override
*/
constructor(factory: any, ...args: any[]) {
super(factory);
this.factory.configuration.tags.start('multline', true, args[0]);
}
/**
* @override
*/
get kind() {
return 'multline';
}
/**
* @override
*/
public EndEntry() {
if (this.table.length) {
ParseUtil.fixInitialMO(this.factory.configuration, this.nodes);
}
const shove = this.getProperty('shove');
const mtd = this.create('node',
'mtd', this.nodes, shove ? {columnalign: shove} : {});
this.setProperty('shove', null);
this.row.push(mtd);
this.Clear();
}
/**
* @override
*/
public EndRow() {
if (this.row.length !== 1) {
// @test MultlineRowsOneCol
throw new TexError(
'MultlineRowsOneCol',
'The rows within the %1 environment must have exactly one column',
'multline');
}
let row = this.create('node', 'mtr', this.row);
this.table.push(row);
this.row = [];
}
/**
* @override
*/
public EndTable() {
super.EndTable();
if (this.table.length) {
let m = this.table.length - 1, label = -1;
if (!NodeUtil.getAttribute(
NodeUtil.getChildren(this.table[0])[0], 'columnalign')) {
NodeUtil.setAttribute(NodeUtil.getChildren(this.table[0])[0],
'columnalign', TexConstant.Align.LEFT);
}
if (!NodeUtil.getAttribute(
NodeUtil.getChildren(this.table[m])[0], 'columnalign')) {
NodeUtil.setAttribute(NodeUtil.getChildren(this.table[m])[0],
'columnalign', TexConstant.Align.RIGHT);
}
let tag = this.factory.configuration.tags.getTag();
if (tag) {
label = (this.arraydef.side === TexConstant.Align.LEFT ? 0 : this.table.length - 1);
const mtr = this.table[label];
const mlabel = this.create('node', 'mlabeledtr',
[tag].concat(NodeUtil.getChildren(mtr)));
NodeUtil.copyAttributes(mtr, mlabel);
this.table[label] = mlabel;
}
}
this.factory.configuration.tags.end();
}
}
/**
* StackItem for handling flalign, xalignat, and xxalignat environments.
*/
export class FlalignItem extends EqnArrayItem {
/**
* @override
*/
get kind() {
return 'flalign';
}
/**
* @override
*/
constructor(factory: any, public name: string, public numbered: boolean,
public padded: boolean, public center: boolean) {
super(factory);
this.factory.configuration.tags.start(name, numbered, numbered);
}
/**
* @override
*/
public EndEntry() {
super.EndEntry();
const n = this.getProperty('xalignat') as number;
if (!n) return;
if (this.row.length > n) {
throw new TexError('XalignOverflow', 'Extra %1 in row of %2', '&', this.name);
}
}
/**
* @override
*/
public EndRow() {
let cell: MmlNode;
let row = this.row;
//
// For xalignat and xxalignat, pad the row to the expected number if it is too short.
//
const n = this.getProperty('xalignat') as number;
while (row.length < n) {
row.push(this.create('node', 'mtd'));
}
//
// Insert padding cells between pairs of entries, as needed for "fit" columns,
// and include initial and end cells if that is needed.
//
this.row = [];
if (this.padded) {
this.row.push(this.create('node', 'mtd'));
}
while ((cell = row.shift())) {
this.row.push(cell);
cell = row.shift();
if (cell) this.row.push(cell);
if (row.length || this.padded) {
this.row.push(this.create('node', 'mtd'));
}
}
//
if (this.row.length > this.maxrow) {
this.maxrow = this.row.length;
}
super.EndRow();
//
// For full-width environments with labels that aren't supposed to take up space,
// move the label into a zero-width mpadded element that laps in the proper direction.
//
const mtr = this.table[this.table.length - 1];
if (this.getProperty('zeroWidthLabel') && mtr.isKind('mlabeledtr')) {
const mtd = NodeUtil.getChildren(mtr)[0];
const side = this.factory.configuration.options['tagSide'];
const def = {width: 0, ...(side === 'right' ? {lspace: '-1width'} : {})};
const mpadded = this.create('node', 'mpadded', NodeUtil.getChildren(mtd), def);
mtd.setChildren([mpadded]);
}
}
/**
* @override
*/
public EndTable() {
super.EndTable();
if (this.center) {
//
// If there is only one equation (one pair):
// Don't make it 100%, and don't change the indentalign.
//
if (this.maxrow <= 2) {
const def = this.arraydef;
delete def.width;
delete this.global.indentalign;
}
}
}
}

View File

@@ -0,0 +1,443 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Mappings for TeX parsing of the AMS math package.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {AmsMethods} from './AmsMethods.js';
import * as sm from '../SymbolMap.js';
import {TexConstant} from '../TexConstants.js';
import ParseMethods from '../ParseMethods.js';
import ParseUtil from '../ParseUtil.js';
import {TEXCLASS} from '../../../core/MmlTree/MmlNode.js';
import {MATHSPACE} from '../../../util/lengths.js';
/**
* Operators from the AMS Math package.
*/
new sm.CharacterMap('AMSmath-mathchar0mo', ParseMethods.mathchar0mo, {
iiiint: ['\u2A0C', {texClass: TEXCLASS.OP}]
});
/**
* Extra characters that are letters in \operatorname
*/
new sm.RegExpMap('AMSmath-operatorLetter', AmsMethods.operatorLetter, /[-*]/i);
/**
* Macros from the AMS Math package.
*/
new sm.CommandMap('AMSmath-macros', {
mathring: ['Accent', '02DA'], // or 0x30A
nobreakspace: 'Tilde',
negmedspace: ['Spacer', MATHSPACE.negativemediummathspace],
negthickspace: ['Spacer', MATHSPACE.negativethickmathspace],
idotsint: ['MultiIntegral', '\\int\\cdots\\int'],
dddot: ['Accent', '20DB'],
ddddot: ['Accent', '20DC'],
sideset: 'SideSet',
boxed: ['Macro', '\\fbox{$\\displaystyle{#1}$}', 1],
tag: 'HandleTag',
notag: 'HandleNoTag',
eqref: ['HandleRef', true],
substack: ['Macro', '\\begin{subarray}{c}#1\\end{subarray}', 1],
injlim: ['NamedOp', 'inj&thinsp;lim'],
projlim: ['NamedOp', 'proj&thinsp;lim'],
varliminf: ['Macro', '\\mathop{\\underline{\\mmlToken{mi}{lim}}}'],
varlimsup: ['Macro', '\\mathop{\\overline{\\mmlToken{mi}{lim}}}'],
varinjlim: ['Macro', '\\mathop{\\underrightarrow{\\mmlToken{mi}{lim}}}'],
varprojlim: ['Macro', '\\mathop{\\underleftarrow{\\mmlToken{mi}{lim}}}'],
DeclareMathOperator: 'HandleDeclareOp',
operatorname: 'HandleOperatorName',
genfrac: 'Genfrac',
frac: ['Genfrac', '', '', '', ''],
tfrac: ['Genfrac', '', '', '', '1'],
dfrac: ['Genfrac', '', '', '', '0'],
binom: ['Genfrac', '(', ')', '0', ''],
tbinom: ['Genfrac', '(', ')', '0', '1'],
dbinom: ['Genfrac', '(', ')', '0', '0'],
cfrac: 'CFrac',
shoveleft: ['HandleShove', TexConstant.Align.LEFT],
shoveright: ['HandleShove', TexConstant.Align.RIGHT],
xrightarrow: ['xArrow', 0x2192, 5, 10],
xleftarrow: ['xArrow', 0x2190, 10, 5]
}, AmsMethods);
/**
* Environments from the AMS Math package.
*/
new sm.EnvironmentMap('AMSmath-environment', ParseMethods.environment, {
'equation*': ['Equation', null, false],
'eqnarray*': ['EqnArray', null, false, true, 'rcl',
ParseUtil.cols(0, MATHSPACE.thickmathspace), '.5em'],
align: ['EqnArray', null, true, true, 'rl', ParseUtil.cols(0, 2)],
'align*': ['EqnArray', null, false, true, 'rl', ParseUtil.cols(0, 2)],
multline: ['Multline', null, true],
'multline*': ['Multline', null, false],
split: ['EqnArray', null, false, false, 'rl', ParseUtil.cols(0)],
gather: ['EqnArray', null, true, true, 'c'],
'gather*': ['EqnArray', null, false, true, 'c'],
alignat: ['AlignAt', null, true, true],
'alignat*': ['AlignAt', null, false, true],
alignedat: ['AlignAt', null, false, false],
aligned: ['AmsEqnArray', null, null, null, 'rl', ParseUtil.cols(0, 2), '.5em', 'D'],
gathered: ['AmsEqnArray', null, null, null, 'c', null, '.5em', 'D'],
xalignat: ['XalignAt', null, true, true],
'xalignat*': ['XalignAt', null, false, true],
xxalignat: ['XalignAt', null, false, false],
flalign: ['FlalignArray', null, true, false, true, 'rlc', 'auto auto fit'],
'flalign*': ['FlalignArray', null, false, false, true, 'rlc', 'auto auto fit'],
subarray: ['Array', null, null, null, null, ParseUtil.cols(0), '0.1em', 'S', 1],
smallmatrix: ['Array', null, null, null, 'c', ParseUtil.cols(1 / 3),
'.2em', 'S', 1],
matrix: ['Array', null, null, null, 'c'],
pmatrix: ['Array', null, '(', ')', 'c'],
bmatrix: ['Array', null, '[', ']', 'c'],
Bmatrix: ['Array', null, '\\{', '\\}', 'c'],
vmatrix: ['Array', null, '\\vert', '\\vert', 'c'],
Vmatrix: ['Array', null, '\\Vert', '\\Vert', 'c'],
cases: ['Array', null, '\\{', '.', 'll', null, '.2em', 'T']
}, AmsMethods);
/**
* Delimiters from the AMS Math package.
*/
new sm.DelimiterMap('AMSmath-delimiter', ParseMethods.delimiter, {
'\\lvert': ['\u007C', {texClass: TEXCLASS.OPEN}],
'\\rvert': ['\u007C', {texClass: TEXCLASS.CLOSE}],
'\\lVert': ['\u2016', {texClass: TEXCLASS.OPEN}],
'\\rVert': ['\u2016', {texClass: TEXCLASS.CLOSE}]
});
/**
* Identifiers from the AMS Symbols package.
*/
new sm.CharacterMap('AMSsymbols-mathchar0mi', ParseMethods.mathchar0mi, {
// Lowercase Greek letters
digamma: '\u03DD',
varkappa: '\u03F0',
// Uppercase Greek letters
varGamma: ['\u0393', {mathvariant: TexConstant.Variant.ITALIC}],
varDelta: ['\u0394', {mathvariant: TexConstant.Variant.ITALIC}],
varTheta: ['\u0398', {mathvariant: TexConstant.Variant.ITALIC}],
varLambda: ['\u039B', {mathvariant: TexConstant.Variant.ITALIC}],
varXi: ['\u039E', {mathvariant: TexConstant.Variant.ITALIC}],
varPi: ['\u03A0', {mathvariant: TexConstant.Variant.ITALIC}],
varSigma: ['\u03A3', {mathvariant: TexConstant.Variant.ITALIC}],
varUpsilon: ['\u03A5', {mathvariant: TexConstant.Variant.ITALIC}],
varPhi: ['\u03A6', {mathvariant: TexConstant.Variant.ITALIC}],
varPsi: ['\u03A8', {mathvariant: TexConstant.Variant.ITALIC}],
varOmega: ['\u03A9', {mathvariant: TexConstant.Variant.ITALIC}],
// Hebrew letters
beth: '\u2136',
gimel: '\u2137',
daleth: '\u2138',
// Miscellaneous symbols
// hbar: '\u0127', // in TeX/jax.js
backprime: ['\u2035', {variantForm: true}],
hslash: '\u210F',
varnothing: ['\u2205', {variantForm: true}],
blacktriangle: '\u25B4',
triangledown: ['\u25BD', {variantForm: true}],
blacktriangledown: '\u25BE',
square: '\u25FB',
Box: '\u25FB',
blacksquare: '\u25FC',
lozenge: '\u25CA',
Diamond: '\u25CA',
blacklozenge: '\u29EB',
circledS: ['\u24C8', {mathvariant: TexConstant.Variant.NORMAL}],
bigstar: '\u2605',
// angle: '\u2220', // in TeX/jax.js
sphericalangle: '\u2222',
measuredangle: '\u2221',
nexists: '\u2204',
complement: '\u2201',
mho: '\u2127',
eth: ['\u00F0', {mathvariant: TexConstant.Variant.NORMAL}],
Finv: '\u2132',
diagup: '\u2571',
Game: '\u2141',
diagdown: '\u2572',
Bbbk: ['\u006B',
{mathvariant: TexConstant.Variant.DOUBLESTRUCK}],
yen: '\u00A5',
circledR: '\u00AE',
checkmark: '\u2713',
maltese: '\u2720'
});
/**
* Operators from the AMS Symbols package.
*/
new sm.CharacterMap('AMSsymbols-mathchar0mo', ParseMethods.mathchar0mo, {
// Binary operators
dotplus: '\u2214',
ltimes: '\u22C9',
smallsetminus: ['\u2216', {variantForm: true}],
rtimes: '\u22CA',
Cap: '\u22D2',
doublecap: '\u22D2',
leftthreetimes: '\u22CB',
Cup: '\u22D3',
doublecup: '\u22D3',
rightthreetimes: '\u22CC',
barwedge: '\u22BC',
curlywedge: '\u22CF',
veebar: '\u22BB',
curlyvee: '\u22CE',
doublebarwedge: '\u2A5E',
boxminus: '\u229F',
circleddash: '\u229D',
boxtimes: '\u22A0',
circledast: '\u229B',
boxdot: '\u22A1',
circledcirc: '\u229A',
boxplus: '\u229E',
centerdot: ['\u22C5', {variantForm: true}],
divideontimes: '\u22C7',
intercal: '\u22BA',
// Binary relations
leqq: '\u2266',
geqq: '\u2267',
leqslant: '\u2A7D',
geqslant: '\u2A7E',
eqslantless: '\u2A95',
eqslantgtr: '\u2A96',
lesssim: '\u2272',
gtrsim: '\u2273',
lessapprox: '\u2A85',
gtrapprox: '\u2A86',
approxeq: '\u224A',
lessdot: '\u22D6',
gtrdot: '\u22D7',
lll: '\u22D8',
llless: '\u22D8',
ggg: '\u22D9',
gggtr: '\u22D9',
lessgtr: '\u2276',
gtrless: '\u2277',
lesseqgtr: '\u22DA',
gtreqless: '\u22DB',
lesseqqgtr: '\u2A8B',
gtreqqless: '\u2A8C',
doteqdot: '\u2251',
Doteq: '\u2251',
eqcirc: '\u2256',
risingdotseq: '\u2253',
circeq: '\u2257',
fallingdotseq: '\u2252',
triangleq: '\u225C',
backsim: '\u223D',
thicksim: ['\u223C', {variantForm: true}],
backsimeq: '\u22CD',
thickapprox: ['\u2248', {variantForm: true}],
subseteqq: '\u2AC5',
supseteqq: '\u2AC6',
Subset: '\u22D0',
Supset: '\u22D1',
sqsubset: '\u228F',
sqsupset: '\u2290',
preccurlyeq: '\u227C',
succcurlyeq: '\u227D',
curlyeqprec: '\u22DE',
curlyeqsucc: '\u22DF',
precsim: '\u227E',
succsim: '\u227F',
precapprox: '\u2AB7',
succapprox: '\u2AB8',
vartriangleleft: '\u22B2',
lhd: '\u22B2',
vartriangleright: '\u22B3',
rhd: '\u22B3',
trianglelefteq: '\u22B4',
unlhd: '\u22B4',
trianglerighteq: '\u22B5',
unrhd: '\u22B5',
vDash: ['\u22A8', {variantForm: true}],
Vdash: '\u22A9',
Vvdash: '\u22AA',
smallsmile: ['\u2323', {variantForm: true}],
shortmid: ['\u2223', {variantForm: true}],
smallfrown: ['\u2322', {variantForm: true}],
shortparallel: ['\u2225', {variantForm: true}],
bumpeq: '\u224F',
between: '\u226C',
Bumpeq: '\u224E',
pitchfork: '\u22D4',
varpropto: ['\u221D', {variantForm: true}],
backepsilon: '\u220D',
blacktriangleleft: '\u25C2',
blacktriangleright: '\u25B8',
therefore: '\u2234',
because: '\u2235',
eqsim: '\u2242',
vartriangle: ['\u25B3', {variantForm: true}],
Join: '\u22C8',
// Negated relations
nless: '\u226E',
ngtr: '\u226F',
nleq: '\u2270',
ngeq: '\u2271',
nleqslant: ['\u2A87', {variantForm: true}],
ngeqslant: ['\u2A88', {variantForm: true}],
nleqq: ['\u2270', {variantForm: true}],
ngeqq: ['\u2271', {variantForm: true}],
lneq: '\u2A87',
gneq: '\u2A88',
lneqq: '\u2268',
gneqq: '\u2269',
lvertneqq: ['\u2268', {variantForm: true}],
gvertneqq: ['\u2269', {variantForm: true}],
lnsim: '\u22E6',
gnsim: '\u22E7',
lnapprox: '\u2A89',
gnapprox: '\u2A8A',
nprec: '\u2280',
nsucc: '\u2281',
npreceq: ['\u22E0', {variantForm: true}],
nsucceq: ['\u22E1', {variantForm: true}],
precneqq: '\u2AB5',
succneqq: '\u2AB6',
precnsim: '\u22E8',
succnsim: '\u22E9',
precnapprox: '\u2AB9',
succnapprox: '\u2ABA',
nsim: '\u2241',
ncong: '\u2247',
nshortmid: ['\u2224', {variantForm: true}],
nshortparallel: ['\u2226', {variantForm: true}],
nmid: '\u2224',
nparallel: '\u2226',
nvdash: '\u22AC',
nvDash: '\u22AD',
nVdash: '\u22AE',
nVDash: '\u22AF',
ntriangleleft: '\u22EA',
ntriangleright: '\u22EB',
ntrianglelefteq: '\u22EC',
ntrianglerighteq: '\u22ED',
nsubseteq: '\u2288',
nsupseteq: '\u2289',
nsubseteqq: ['\u2288', {variantForm: true}],
nsupseteqq: ['\u2289', {variantForm: true}],
subsetneq: '\u228A',
supsetneq: '\u228B',
varsubsetneq: ['\u228A', {variantForm: true}],
varsupsetneq: ['\u228B', {variantForm: true}],
subsetneqq: '\u2ACB',
supsetneqq: '\u2ACC',
varsubsetneqq: ['\u2ACB', {variantForm: true}],
varsupsetneqq: ['\u2ACC', {variantForm: true}],
// Arrows
leftleftarrows: '\u21C7',
rightrightarrows: '\u21C9',
leftrightarrows: '\u21C6',
rightleftarrows: '\u21C4',
Lleftarrow: '\u21DA',
Rrightarrow: '\u21DB',
twoheadleftarrow: '\u219E',
twoheadrightarrow: '\u21A0',
leftarrowtail: '\u21A2',
rightarrowtail: '\u21A3',
looparrowleft: '\u21AB',
looparrowright: '\u21AC',
leftrightharpoons: '\u21CB',
rightleftharpoons: ['\u21CC', {variantForm: true}],
curvearrowleft: '\u21B6',
curvearrowright: '\u21B7',
circlearrowleft: '\u21BA',
circlearrowright: '\u21BB',
Lsh: '\u21B0',
Rsh: '\u21B1',
upuparrows: '\u21C8',
downdownarrows: '\u21CA',
upharpoonleft: '\u21BF',
upharpoonright: '\u21BE',
downharpoonleft: '\u21C3',
restriction: '\u21BE',
multimap: '\u22B8',
downharpoonright: '\u21C2',
leftrightsquigarrow: '\u21AD',
rightsquigarrow: '\u21DD',
leadsto: '\u21DD',
dashrightarrow: '\u21E2',
dashleftarrow: '\u21E0',
// Negated arrows
nleftarrow: '\u219A',
nrightarrow: '\u219B',
nLeftarrow: '\u21CD',
nRightarrow: '\u21CF',
nleftrightarrow: '\u21AE',
nLeftrightarrow: '\u21CE'
});
/**
* Delimiters from the AMS Symbols package.
*/
new sm.DelimiterMap('AMSsymbols-delimiter', ParseMethods.delimiter, {
// corners
'\\ulcorner': '\u231C',
'\\urcorner': '\u231D',
'\\llcorner': '\u231E',
'\\lrcorner': '\u231F'
});
/**
* Macros from the AMS Symbols package.
*/
new sm.CommandMap('AMSsymbols-macros', {
implies: ['Macro', '\\;\\Longrightarrow\\;'],
impliedby: ['Macro', '\\;\\Longleftarrow\\;']
}, AmsMethods);

View File

@@ -0,0 +1,602 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview The AMS Parse methods.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {StackItem} from '../StackItem.js';
import {ParseMethod} from '../Types.js';
import ParseUtil from '../ParseUtil.js';
import ParseMethods from '../ParseMethods.js';
import NodeUtil from '../NodeUtil.js';
import {TexConstant} from '../TexConstants.js';
import TexParser from '../TexParser.js';
import TexError from '../TexError.js';
import {Macro} from '../Symbol.js';
import {CommandMap} from '../SymbolMap.js';
import {ArrayItem} from '../base/BaseItems.js';
import {FlalignItem} from './AmsItems.js';
import BaseMethods from '../base/BaseMethods.js';
import {TEXCLASS} from '../../../core/MmlTree/MmlNode.js';
import {MmlMunderover} from '../../../core/MmlTree/MmlNodes/munderover.js';
import {MmlNode, AbstractMmlTokenNode} from '../../../core/MmlTree/MmlNode.js';
// Namespace
export const AmsMethods: Record<string, ParseMethod> = {};
/**
* Handle AMS array environments.
* @param {TexParser} parser The calling parser.
* @param {StackItem} begin The opening stackitem.
* @param {boolean} numbered Environment numbered.
* @param {boolean} taggable Environment taggable (e.g., align* is taggable,
* split is not).
* @param {string} align Column alignment.
* @param {string} spacing Column spacing.
* @param {string} style Display style indicator.
*/
AmsMethods.AmsEqnArray = function(parser: TexParser, begin: StackItem,
numbered: boolean, taggable: boolean,
align: string, spacing: string,
style: string) {
// @test Aligned, Gathered
const args = parser.GetBrackets('\\begin{' + begin.getName() + '}');
const array = BaseMethods.EqnArray(parser, begin, numbered, taggable, align, spacing, style);
return ParseUtil.setArrayAlign(array as ArrayItem, args);
};
/**
* Handle AMS alignat environments.
* @param {TexParser} parser The calling parser.
* @param {StackItem} begin The opening stackitem.
* @param {boolean} numbered Environment numbered.
* @param {boolean} taggable Environment taggable (e.g., align* is taggable,
* split is not).
*/
AmsMethods.AlignAt = function(parser: TexParser, begin: StackItem,
numbered: boolean, taggable: boolean) {
const name = begin.getName();
let n, valign, align = '', spacing = [];
if (!taggable) {
// @test Alignedat
valign = parser.GetBrackets('\\begin{' + name + '}');
}
n = parser.GetArgument('\\begin{' + name + '}');
if (n.match(/[^0-9]/)) {
// @test PositiveIntegerArg
throw new TexError('PositiveIntegerArg',
'Argument to %1 must me a positive integer',
'\\begin{' + name + '}');
}
let count = parseInt(n, 10);
while (count > 0) {
align += 'rl';
spacing.push('0em 0em');
count--;
}
let spaceStr = spacing.join(' ');
if (taggable) {
// @test Alignat, Alignat Star
return AmsMethods.EqnArray(parser, begin, numbered, taggable, align, spaceStr);
}
// @test Alignedat
let array = AmsMethods.EqnArray(parser, begin, numbered, taggable, align, spaceStr);
return ParseUtil.setArrayAlign(array as ArrayItem, valign);
};
/**
* Implements multline environment (mostly handled through STACKITEM below)
* @param {TexParser} parser The calling parser.
* @param {StackItem} begin The opening stackitem.
* @param {boolean} numbered Environment numbered.
*/
AmsMethods.Multline = function (parser: TexParser, begin: StackItem, numbered: boolean) {
// @test Shove*, Multline
parser.Push(begin);
ParseUtil.checkEqnEnv(parser);
const item = parser.itemFactory.create('multline', numbered, parser.stack) as ArrayItem;
item.arraydef = {
displaystyle: true,
rowspacing: '.5em',
columnspacing: '100%',
width: parser.options.ams['multlineWidth'],
side: parser.options['tagSide'],
minlabelspacing: parser.options['tagIndent'],
framespacing: parser.options.ams['multlineIndent'] + ' 0',
frame: '', // Use frame spacing with no actual frame
'data-width-includes-label': true // take label space out of 100% width
};
return item;
};
/**
* Generate an align at environment.
* @param {TexParser} parser The current TeX parser.
* @param {StackItem} begin The begin stackitem.
* @param {boolean} numbered Is this a numbered array.
* @param {boolean} padded Is it padded.
*/
AmsMethods.XalignAt = function(parser: TexParser, begin: StackItem,
numbered: boolean, padded: boolean) {
let n = parser.GetArgument('\\begin{' + begin.getName() + '}');
if (n.match(/[^0-9]/)) {
throw new TexError('PositiveIntegerArg',
'Argument to %1 must me a positive integer',
'\\begin{' + begin.getName() + '}');
}
const align = (padded ? 'crl' : 'rlc');
const width = (padded ? 'fit auto auto' : 'auto auto fit');
const item = AmsMethods.FlalignArray(parser, begin, numbered, padded, false, align, width, true) as FlalignItem;
item.setProperty('xalignat', 2 * parseInt(n));
return item;
};
/**
* Generate an flalign environment.
* @param {TexParser} parser The current TeX parser.
* @param {StackItem} begin The begin stackitem.
* @param {boolean} numbered Is this a numbered array.
* @param {boolean} padded Is it padded.
* @param {boolean} center Is it centered.
* @param {string} align The horizontal alignment for columns
* @param {string} width The column widths of the table
* @param {boolean} zeroWidthLabel True if the label should be in llap/rlap
*/
AmsMethods.FlalignArray = function(parser: TexParser, begin: StackItem, numbered: boolean,
padded: boolean, center: boolean, align: string,
width: string, zeroWidthLabel: boolean = false) {
parser.Push(begin);
ParseUtil.checkEqnEnv(parser);
align = align
.split('')
.join(' ')
.replace(/r/g, 'right')
.replace(/l/g, 'left')
.replace(/c/g, 'center');
const item = parser.itemFactory.create(
'flalign', begin.getName(), numbered, padded, center, parser.stack) as FlalignItem;
item.arraydef = {
width: '100%',
displaystyle: true,
columnalign: align,
columnspacing: '0em',
columnwidth: width,
rowspacing: '3pt',
side: parser.options['tagSide'],
minlabelspacing: (zeroWidthLabel ? '0' : parser.options['tagIndent']),
'data-width-includes-label': true,
};
item.setProperty('zeroWidthLabel', zeroWidthLabel);
return item;
};
export const NEW_OPS = 'ams-declare-ops';
/**
* Handle DeclareMathOperator.
* @param {TexParser} parser The calling parser.
* @param {string} name The macro name.
*/
AmsMethods.HandleDeclareOp = function (parser: TexParser, name: string) {
let star = (parser.GetStar() ? '*' : '');
let cs = ParseUtil.trimSpaces(parser.GetArgument(name));
if (cs.charAt(0) === '\\') {
cs = cs.substr(1);
}
let op = parser.GetArgument(name);
(parser.configuration.handlers.retrieve(NEW_OPS) as CommandMap).
add(cs, new Macro(cs, AmsMethods.Macro, [`\\operatorname${star}{${op}}`]));
};
/**
* Handle operatorname.
* @param {TexParser} parser The calling parser.
* @param {string} name The macro name.
*/
AmsMethods.HandleOperatorName = function(parser: TexParser, name: string) {
// @test Operatorname
const star = parser.GetStar();
//
// Parse the argument using operator letters and grouping multiple letters.
//
let op = ParseUtil.trimSpaces(parser.GetArgument(name));
let mml = new TexParser(op, {
...parser.stack.env,
font: TexConstant.Variant.NORMAL,
multiLetterIdentifiers: /^[-*a-z]+/i as any,
operatorLetters: true
}, parser.configuration).mml();
//
// If we get something other than a single mi, wrap in a TeXAtom.
//
if (!mml.isKind('mi')) {
mml = parser.create('node', 'TeXAtom', [mml]);
}
//
// Mark the limit properties and the TeX class.
//
NodeUtil.setProperties(mml, {movesupsub: star, movablelimits: true, texClass: TEXCLASS.OP});
//
// Skip a following \limits macro if not a starred operator
//
if (!star) {
const c = parser.GetNext(), i = parser.i;
if (c === '\\' && ++parser.i && parser.GetCS() !== 'limits') {
parser.i = i;
}
}
//
parser.Push(mml);
};
/**
* Handle sideset.
* @param {TexParser} parser The calling parser.
* @param {string} name The macro name.
*/
AmsMethods.SideSet = function (parser: TexParser, name: string) {
//
// Get the pre- and post-scripts, and any extra material from the arguments
//
const [preScripts, preRest] = splitSideSet(parser.ParseArg(name));
const [postScripts, postRest] = splitSideSet(parser.ParseArg(name));
const base = parser.ParseArg(name);
let mml = base;
//
// If there are pre-scripts...
//
if (preScripts) {
//
// If there is other material...
//
if (preRest) {
//
// Replace the empty base of the prescripts with a phantom element of the
// original base, with width 0 (but still of the correct height and depth).
// so the scripts will be at the right heights.
//
preScripts.replaceChild(
parser.create('node', 'mphantom', [
parser.create('node', 'mpadded', [ParseUtil.copyNode(base, parser)], {width: 0})
]),
NodeUtil.getChildAt(preScripts, 0)
);
} else {
//
// If there is no extra meterial, make a mmultiscripts element
//
mml = parser.create('node', 'mmultiscripts', [base]);
//
// Add any postscripts
//
if (postScripts) {
NodeUtil.appendChildren(mml, [
NodeUtil.getChildAt(postScripts, 1) || parser.create('node', 'none'),
NodeUtil.getChildAt(postScripts, 2) || parser.create('node', 'none')
]);
}
//
// Add the prescripts (left aligned)
//
NodeUtil.setProperty(mml, 'scriptalign', 'left');
NodeUtil.appendChildren(mml, [
parser.create('node', 'mprescripts'),
NodeUtil.getChildAt(preScripts, 1) || parser.create('node', 'none'),
NodeUtil.getChildAt(preScripts, 2) || parser.create('node', 'none')
]);
}
}
//
// If there are postscripts and we didn't make a mmultiscript element above...
//
if (postScripts && mml === base) {
//
// Replace the emtpy base with actual base, and use that as the mml
//
postScripts.replaceChild(base, NodeUtil.getChildAt(postScripts, 0));
mml = postScripts;
}
//
// Put the needed pieces into a TeXAtom of class OP.
// Note that the postScripts are in the mml element,
// either as part of the mmultiscripts node, or the
// msubsup with the base inserted into it.
//
const mrow = parser.create('node', 'TeXAtom', [], {texClass: TEXCLASS.OP, movesupsub: true, movablelimits: true});
if (preRest) {
preScripts && mrow.appendChild(preScripts);
mrow.appendChild(preRest);
}
mrow.appendChild(mml);
postRest && mrow.appendChild(postRest);
parser.Push(mrow);
};
/**
* Utility for breaking the \sideset scripts from any other material.
* @param {MmlNode} mml The node to check.
* @return {[MmlNode, MmlNode]} The msubsup with the scripts together with any extra nodes.
*/
function splitSideSet(mml: MmlNode): [MmlNode, MmlNode] {
if (!mml || (mml.isInferred && mml.childNodes.length === 0)) return [null, null];
if (mml.isKind('msubsup') && checkSideSetBase(mml)) return [mml, null];
const child = NodeUtil.getChildAt(mml, 0);
if (!(mml.isInferred && child && checkSideSetBase(child))) return [null, mml];
mml.childNodes.splice(0, 1); // remove first child
return [child, mml];
}
/**
* Utility for checking if a \sideset argument has scripts with an empty base.
* @param {MmlNode} mml The node to check.
* @return {boolean} True if the base is not and empty mi element.
*/
function checkSideSetBase(mml: MmlNode): boolean {
const base = mml.childNodes[0];
return base && base.isKind('mi') && (base as AbstractMmlTokenNode).getText() === '';
}
/**
* Handle extra letters in \operatorname (- and *), default to normal otherwise.
* @param {TexParser} parser The calling parser.
* @param {string} c The letter being checked
*/
AmsMethods.operatorLetter = function (parser: TexParser, c: string) {
return parser.stack.env.operatorLetters ? ParseMethods.variable(parser, c) : false;
};
/**
* Handle multi integral signs.
* @param {TexParser} parser The calling parser.
* @param {string} name The macro name.
* @param {string} integral The actual integral sign.
*/
AmsMethods.MultiIntegral = function(parser: TexParser, name: string,
integral: string) {
let next = parser.GetNext();
if (next === '\\') {
// @test MultiInt with Command
let i = parser.i;
next = parser.GetArgument(name);
parser.i = i;
if (next === '\\limits') {
if (name === '\\idotsint') {
// @test MultiInt with Limits
integral = '\\!\\!\\mathop{\\,\\,' + integral + '}';
}
else {
// Question: This is not used anymore?
integral = '\\!\\!\\!\\mathop{\\,\\,\\,' + integral + '}';
}
}
}
// @test MultiInt, MultiInt in Context
parser.string = integral + ' ' + parser.string.slice(parser.i);
parser.i = 0;
};
/**
* Handle stretchable arrows.
* @param {TexParser} parser The calling parser.
* @param {string} name The macro name.
* @param {number} chr The arrow character in hex code.
* @param {number} l Left width.
* @param {number} r Right width.
*/
AmsMethods.xArrow = function(parser: TexParser, name: string,
chr: number, l: number, r: number) {
let def = {width: '+' + ParseUtil.Em((l + r) / 18), lspace: ParseUtil.Em(l / 18)};
let bot = parser.GetBrackets(name);
let first = parser.ParseArg(name);
let dstrut = parser.create('node', 'mspace', [], {depth: '.25em'});
let arrow = parser.create('token',
'mo', {stretchy: true, texClass: TEXCLASS.REL}, String.fromCodePoint(chr));
arrow = parser.create('node', 'mstyle', [arrow], {scriptlevel: 0});
let mml = parser.create('node', 'munderover', [arrow]) as MmlMunderover;
let mpadded = parser.create('node', 'mpadded', [first, dstrut], def);
NodeUtil.setAttribute(mpadded, 'voffset', '-.2em');
NodeUtil.setAttribute(mpadded, 'height', '-.2em');
NodeUtil.setChild(mml, mml.over, mpadded);
if (bot) {
// @test Above Below Left Arrow, Above Below Right Arrow
let bottom = new TexParser(bot, parser.stack.env, parser.configuration).mml();
let bstrut = parser.create('node', 'mspace', [], {height: '.75em'});
mpadded = parser.create('node', 'mpadded', [bottom, bstrut], def);
NodeUtil.setAttribute(mpadded, 'voffset', '.15em');
NodeUtil.setAttribute(mpadded, 'depth', '-.15em');
NodeUtil.setChild(mml, mml.under, mpadded);
}
// @test Above Left Arrow, Above Right Arrow, Above Left Arrow in Context,
// Above Right Arrow in Context
NodeUtil.setProperty(mml, 'subsupOK', true);
parser.Push(mml);
};
/**
* Record presence of \shoveleft and \shoveright
* @param {TexParser} parser The calling parser.
* @param {string} name The macro name.
* @param {string} shove The shove value.
*/
AmsMethods.HandleShove = function(parser: TexParser, _name: string,
shove: string) {
let top = parser.stack.Top();
// @test Shove (Left|Right) (Top|Middle|Bottom)
if (top.kind !== 'multline') {
// @test Shove Error Environment
throw new TexError('CommandOnlyAllowedInEnv',
'%1 only allowed in %2 environment',
parser.currentCS, 'multline');
}
if (top.Size()) {
// @test Shove Error (Top|Middle|Bottom)
throw new TexError('CommandAtTheBeginingOfLine',
'%1 must come at the beginning of the line', parser.currentCS);
}
top.setProperty('shove', shove);
};
/**
* Handle \cfrac
* @param {TexParser} parser The calling parser.
* @param {string} name The macro name.
*/
AmsMethods.CFrac = function(parser: TexParser, name: string) {
let lr = ParseUtil.trimSpaces(parser.GetBrackets(name, ''));
let num = parser.GetArgument(name);
let den = parser.GetArgument(name);
let lrMap: {[key: string]: string} = {
l: TexConstant.Align.LEFT, r: TexConstant.Align.RIGHT, '': ''};
let numNode = new TexParser('\\strut\\textstyle{' + num + '}',
parser.stack.env, parser.configuration).mml();
let denNode = new TexParser('\\strut\\textstyle{' + den + '}',
parser.stack.env, parser.configuration).mml();
let frac = parser.create('node', 'mfrac', [numNode, denNode]);
lr = lrMap[lr];
if (lr == null) {
// @test Center Fraction Error
throw new TexError('IllegalAlign', 'Illegal alignment specified in %1', parser.currentCS);
}
if (lr) {
// @test Right Fraction, Left Fraction
NodeUtil.setProperties(frac, {numalign: lr, denomalign: lr});
}
// @test Center Fraction
parser.Push(frac);
};
/**
* Implement AMS generalized fraction.
* @param {TexParser} parser The calling parser.
* @param {string} name The macro name.
* @param {string} left Left delimiter.
* @param {string} right Right delimiter.
* @param {string} thick Line thickness.
* @param {string} style Math style.
*/
AmsMethods.Genfrac = function(parser: TexParser, name: string, left: string,
right: string, thick: string, style: string) {
if (left == null) { // @test Genfrac
left = parser.GetDelimiterArg(name);
}
if (right == null) { // @test Genfrac
right = parser.GetDelimiterArg(name);
}
if (thick == null) { // @test Genfrac
thick = parser.GetArgument(name);
}
if (style == null) { // @test Genfrac
style = ParseUtil.trimSpaces(parser.GetArgument(name));
}
let num = parser.ParseArg(name);
let den = parser.ParseArg(name);
let frac = parser.create('node', 'mfrac', [num, den]);
if (thick !== '') {
// @test Normal Binomial, Text Binomial, Display Binomial
NodeUtil.setAttribute(frac, 'linethickness', thick);
}
if (left || right) {
// @test Normal Binomial, Text Binomial, Display Binomial
NodeUtil.setProperty(frac, 'withDelims', true);
frac = ParseUtil.fixedFence(parser.configuration, left, frac, right);
}
if (style !== '') {
let styleDigit = parseInt(style, 10);
let styleAlpha = ['D', 'T', 'S', 'SS'][styleDigit];
if (styleAlpha == null) {
// @test Genfrac Error
throw new TexError('BadMathStyleFor', 'Bad math style for %1', parser.currentCS);
}
frac = parser.create('node', 'mstyle', [frac]);
if (styleAlpha === 'D') {
// @test Display Fraction, Display Sub Fraction, Display Binomial,
// Display Sub Binomial
NodeUtil.setProperties(frac, {displaystyle: true, scriptlevel: 0});
}
else {
// @test Text Fraction, Text Sub Fraction, Text Binomial,
// Text Sub Binomial
NodeUtil.setProperties(frac, {displaystyle: false,
scriptlevel: styleDigit - 1});
}
}
// @test Text Fraction, Normal Sub Binomial, Normal Binomial
parser.Push(frac);
};
/**
* Add the tag to the environment (to be added to the table row later).
* @param {TexParser} parser The calling parser.
* @param {string} name The macro name.
*/
AmsMethods.HandleTag = function(parser: TexParser, name: string) {
if (!parser.tags.currentTag.taggable && parser.tags.env) {
// @test Illegal Tag Error
throw new TexError('CommandNotAllowedInEnv',
'%1 not allowed in %2 environment',
parser.currentCS, parser.tags.env);
}
if (parser.tags.currentTag.tag) {
// @test Double Tag Error
throw new TexError('MultipleCommand', 'Multiple %1', parser.currentCS);
}
let star = parser.GetStar();
let tagId = ParseUtil.trimSpaces(parser.GetArgument(name));
parser.tags.tag(tagId, star);
};
AmsMethods.HandleNoTag = BaseMethods.HandleNoTag;
AmsMethods.HandleRef = BaseMethods.HandleRef;
AmsMethods.Macro = BaseMethods.Macro;
AmsMethods.Accent = BaseMethods.Accent;
AmsMethods.Tilde = BaseMethods.Tilde;
AmsMethods.Array = BaseMethods.Array;
AmsMethods.Spacer = BaseMethods.Spacer;
AmsMethods.NamedOp = BaseMethods.NamedOp;
AmsMethods.EqnArray = BaseMethods.EqnArray;
AmsMethods.Equation = BaseMethods.Equation;

View File

@@ -0,0 +1,46 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Configuration file for the AMScd package.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {Configuration} from '../Configuration.js';
import './AmsCdMappings.js';
export const AmsCdConfiguration = Configuration.create(
'amscd', {
handler: {
character: ['amscd_special'],
macro: ['amscd_macros'],
environment: ['amscd_environment']
},
options: {
amscd: {
colspace: '5pt',
rowspace: '5pt',
harrowsize: '2.75em',
varrowsize: '1.75em',
hideHorizontalLabels: false
}
}
}
);

View File

@@ -0,0 +1,38 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Symbol mappings for the AMScd package.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import * as sm from '../SymbolMap.js';
import ParseMethods from '../ParseMethods.js';
import AmsCdMethods from './AmsCdMethods.js';
new sm.EnvironmentMap('amscd_environment', ParseMethods.environment,
{CD: 'CD'}, AmsCdMethods);
new sm.CommandMap('amscd_macros', {
minCDarrowwidth: 'minCDarrowwidth',
minCDarrowheight: 'minCDarrowheight',
}, AmsCdMethods);
new sm.MacroMap('amscd_special', {'@': 'arrow'}, AmsCdMethods);

View File

@@ -0,0 +1,201 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Methods for the AMScd package.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import TexParser from '../TexParser.js';
import {ParseMethod} from '../Types.js';
import {StackItem, EnvList} from '../StackItem.js';
import {ArrayItem} from '../base/BaseItems.js';
import {Other} from '../base/BaseConfiguration.js';
import {MmlMunderover} from '../../../core/MmlTree/MmlNodes/munderover.js';
import {TEXCLASS} from '../../../core/MmlTree/MmlNode.js';
import NodeUtil from '../NodeUtil.js';
// Namespace
let AmsCdMethods: Record<string, ParseMethod> = {};
/**
* Handles CD environment for commutative diagrams.
* @param {TexParser} parser The calling parser.
* @param {StackItem} begin The opening stackitem.
*/
AmsCdMethods.CD = function(parser: TexParser, begin: StackItem) {
parser.Push(begin);
let item = parser.itemFactory.create('array') as ArrayItem;
let options = parser.configuration.options.amscd;
item.setProperties({
minw: parser.stack.env.CD_minw || options.harrowsize,
minh: parser.stack.env.CD_minh || options.varrowsize
});
item.arraydef = {
columnalign: 'center',
columnspacing: options.colspace,
rowspacing: options.rowspace,
displaystyle: true
};
return item;
};
/**
* Converts arrows.
* @param {TexParser} parser The calling parser.
* @param {string} name The macro name.
*/
AmsCdMethods.arrow = function(parser: TexParser, name: string) {
let c = parser.string.charAt(parser.i);
if (!c.match(/[><VA.|=]/)) {
return Other(parser, name);
} else {
parser.i++;
}
let first = parser.stack.Top();
if (!first.isKind('array') || first.Size()) {
AmsCdMethods.cell(parser, name);
first = parser.stack.Top();
}
let top = first as ArrayItem;
//
// Add enough cells to place the arrow correctly
//
let arrowRow = ((top.table.length % 2) === 1);
let n = (top.row.length + (arrowRow ? 0 : 1)) % 2;
while (n) {
AmsCdMethods.cell(parser, name);
n--;
}
let mml;
let hdef = {minsize: top.getProperty('minw'), stretchy: true},
vdef = {minsize: top.getProperty('minh'),
stretchy: true, symmetric: true, lspace: 0, rspace: 0};
if (c === '.') {
} else if (c === '|') {
mml = parser.create('token', 'mo', vdef, '\u2225');
} else if (c === '=') {
mml = parser.create('token', 'mo', hdef, '=');
} else {
//
// for @>>> @<<< @VVV and @AAA, get the arrow and labels
//
// TODO: cleanup!
let arrow: string = ({
'>': '\u2192', '<': '\u2190', 'V': '\u2193', 'A': '\u2191'} as {[key: string]: string}) [c];
let a = parser.GetUpTo(name + c, c);
let b = parser.GetUpTo(name + c, c);
if (c === '>' || c === '<') {
//
// Lay out horizontal arrows with munderover if it has labels
//
mml = parser.create('token', 'mo', hdef, arrow);
if (!a) {
a = '\\kern ' + top.getProperty('minw');
} // minsize needs work
if (a || b) {
let pad: EnvList = {width: '+.67em', lspace: '.33em'};
mml = parser.create('node', 'munderover', [mml]) as MmlMunderover;
if (a) {
let nodeA = new TexParser(a, parser.stack.env, parser.configuration).mml();
let mpadded = parser.create('node', 'mpadded', [nodeA], pad);
NodeUtil.setAttribute(mpadded, 'voffset', '.1em');
NodeUtil.setChild(mml, mml.over, mpadded);
}
if (b) {
let nodeB = new TexParser(b, parser.stack.env, parser.configuration).mml();
NodeUtil.setChild(mml, mml.under, parser.create('node', 'mpadded', [nodeB], pad));
}
if (parser.configuration.options.amscd.hideHorizontalLabels) {
mml = parser.create('node', 'mpadded', mml, {depth: 0, height: '.67em'});
}
}
} else {
//
// Lay out vertical arrows with mrow if there are labels
//
let arrowNode = parser.create('token', 'mo', vdef, arrow);
mml = arrowNode;
if (a || b) {
mml = parser.create('node', 'mrow');
if (a) {
NodeUtil.appendChildren(
mml, [new TexParser('\\scriptstyle\\llap{' + a + '}', parser.stack.env, parser.configuration).mml()]);
}
arrowNode.texClass = TEXCLASS.ORD;
NodeUtil.appendChildren(mml, [arrowNode]);
if (b) {
NodeUtil.appendChildren(mml, [new TexParser('\\scriptstyle\\rlap{' + b + '}',
parser.stack.env, parser.configuration).mml()]);
}
}
}
}
if (mml) {
parser.Push(mml);
}
AmsCdMethods.cell(parser, name);
};
/**
* Converts a cell in the diagram.
* @param {TexParser} parser The calling parser.
* @param {string} name The macro name.
*/
AmsCdMethods.cell = function(parser: TexParser, name: string) {
let top = parser.stack.Top() as ArrayItem;
if ((top.table || []).length % 2 === 0 && (top.row || []).length === 0) {
//
// Add a strut to the first cell in even rows to get
// better spacing of arrow rows.
//
parser.Push(parser.create('node', 'mpadded', [], {height: '8.5pt', depth: '2pt'}));
}
parser.Push(parser.itemFactory.create('cell').setProperties({isEntry: true, name: name}));
};
/**
* Sets minimal width for arrows.
* @param {TexParser} parser The calling parser.
* @param {string} name The macro name.
*/
AmsCdMethods.minCDarrowwidth = function(parser: TexParser, name: string) {
parser.stack.env.CD_minw = parser.GetDimen(name);
};
/**
* Sets minimal height for arrows.
* @param {TexParser} parser The calling parser.
* @param {string} name The macro name.
*/
AmsCdMethods.minCDarrowheight = function(parser: TexParser, name: string) {
parser.stack.env.CD_minh = parser.GetDimen(name);
};
export default AmsCdMethods;

View File

@@ -0,0 +1,168 @@
/*************************************************************
*
* Copyright (c) 2019-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Configuration file for the autoload package.
*
* @author dpvc@mathjax.org (Davide P. Cervone)
*/
import {Configuration, ParserConfiguration} from '../Configuration.js';
import TexParser from '../TexParser.js';
import {CommandMap} from '../SymbolMap.js';
import {Macro} from '../Symbol.js';
import {TeX} from '../../tex.js';
import {RequireLoad, RequireConfiguration} from '../require/RequireConfiguration.js';
import {Package} from '../../../components/package.js';
import {expandable, defaultOptions} from '../../../util/Options.js';
/**
* Autoload an extension when the first macro for it is encountered
* (if the extension has already been loaded, remove the autoload
* macros and environments so they won't try to load it again, and
* back up to read the macro again, call the RequireLoad command to
* either load the extension, or initialize it.)
*
* @param {TexParser} parser The TeX input parser
* @param {string} name The control sequence that is running
* @param {string} extension The extension to load
* @param {boolean} isMacro True if this is a macro, false if an environment
*/
function Autoload(parser: TexParser, name: string, extension: string, isMacro: boolean) {
if (Package.packages.has(parser.options.require.prefix + extension)) {
const def = parser.options.autoload[extension];
const [macros, envs] = (def.length === 2 && Array.isArray(def[0]) ? def : [def, []]);
for (const macro of macros) {
AutoloadMacros.remove(macro);
}
for (const env of envs) {
AutoloadEnvironments.remove(env);
}
//
// Put back the macro or \begin and read it again
//
parser.string = (isMacro ? name + ' ' : '\\begin{' + name.slice(1) + '}' ) + parser.string.slice(parser.i);
parser.i = 0;
}
RequireLoad(parser, extension);
}
/**
* Check if the require extension has been initialized
* (If autoload has been included in the TeX packages, but require isn't, then we need
* to set up the options here and configure the require package in configAutoload below.
* the priorities of the initialization and configuration are set so that autoload
* will run after require when both are used.)
*/
function initAutoload(config: ParserConfiguration) {
if (!config.options.require) {
defaultOptions(config.options, RequireConfiguration.options);
}
}
/**
* Create the macros and environments for the extensions that need to be loaded.
* Only ones that aren't already defined are made to autoload
* (except for \color, which is overridden if present)
*/
function configAutoload(config: ParserConfiguration, jax: TeX<any, any, any>) {
const parser = jax.parseOptions;
const macros = parser.handlers.get('macro');
const environments = parser.handlers.get('environment');
const autoload = parser.options.autoload;
parser.packageData.set('autoload', {Autoload}); // used by textmacros to tell if a macro is autoloading
//
// Loop through the autoload definitions
//
for (const extension of Object.keys(autoload)) {
const def = autoload[extension];
const [macs, envs] = (def.length === 2 && Array.isArray(def[0]) ? def : [def, []]);
//
// Create the macros
//
for (const name of macs) {
if (!macros.lookup(name) || name === 'color') {
AutoloadMacros.add(name, new Macro(name, Autoload, [extension, true]));
}
}
//
// Create the environments
//
for (const name of envs) {
if (!environments.lookup(name)) {
AutoloadEnvironments.add(name, new Macro(name, Autoload, [extension, false]));
}
}
}
//
// Check if the require extension needs to be configured
//
if (!parser.packageData.get('require')) {
RequireConfiguration.config(config, jax);
}
}
/**
* The command and environment maps for the macros that autoload extensions
*/
const AutoloadMacros = new CommandMap('autoload-macros', {}, {});
const AutoloadEnvironments = new CommandMap('autoload-environments', {}, {});
/**
* The configuration object for configmacros
*/
export const AutoloadConfiguration = Configuration.create(
'autoload', {
handler: {
macro: ['autoload-macros'],
environment: ['autoload-environments']
},
options: {
//
// These are the extension names and the macros and environments they contain.
// The format is [macros...] or [[macros...], [environments...]]
// You can prevent one from being autoloaded by setting
// it to [] in the options when the TeX input jax is created.
// You can include the prefix if it is not the default one from require
//
autoload: expandable({
action: ['toggle', 'mathtip', 'texttip'],
amscd: [[], ['CD']],
bbox: ['bbox'],
boldsymbol: ['boldsymbol'],
braket: ['bra', 'ket', 'braket', 'set', 'Bra', 'Ket', 'Braket', 'Set', 'ketbra', 'Ketbra'],
bussproofs: [[], ['prooftree']],
cancel: ['cancel', 'bcancel', 'xcancel', 'cancelto'],
color: ['color', 'definecolor', 'textcolor', 'colorbox', 'fcolorbox'],
enclose: ['enclose'],
extpfeil: ['xtwoheadrightarrow', 'xtwoheadleftarrow', 'xmapsto', 'xlongequal', 'xtofrom', 'Newextarrow'],
html: ['href', 'class', 'style', 'cssId'],
mhchem: ['ce', 'pu'],
newcommand: ['newcommand', 'renewcommand', 'newenvironment', 'renewenvironment', 'def', 'let'],
unicode: ['unicode'],
verb: ['verb']
})
},
config: configAutoload,
init: initAutoload,
priority: 10
}
);

View File

@@ -0,0 +1,197 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Configuration for the Base LaTeX parser.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {Configuration} from '../Configuration.js';
import {MapHandler} from '../MapHandler.js';
import TexError from '../TexError.js';
import NodeUtil from '../NodeUtil.js';
import TexParser from '../TexParser.js';
import {CharacterMap} from '../SymbolMap.js';
import * as bitem from './BaseItems.js';
import {AbstractTags} from '../Tags.js';
import './BaseMappings.js';
import {getRange} from '../../../core/MmlTree/OperatorDictionary.js';
import {MmlNode} from '../../../core/MmlTree/MmlNode.js';
import ParseOptions from '../ParseOptions.js';
/**
* Remapping some ASCII characters to their Unicode operator equivalent.
*/
new CharacterMap('remap', null, {
'-': '\u2212',
'*': '\u2217',
'`': '\u2018' // map ` to back quote
});
/**
* Default handling of characters (as <mo> elements).
* @param {TexParser} parser The calling parser.
* @param {string} char The character to parse.
*/
export function Other(parser: TexParser, char: string) {
const font = parser.stack.env['font'];
let def = font ?
// @test Other Font
{mathvariant: parser.stack.env['font']} : {};
const remap = (MapHandler.getMap('remap') as CharacterMap).lookup(char);
const range = getRange(char);
const type = (range ? range[3] : 'mo');
// @test Other
// @test Other Remap
let mo = parser.create('token', type, def, (remap ? remap.char : char));
range[4] && mo.attributes.set('mathvariant', range[4]);
if (type === 'mo') {
NodeUtil.setProperty(mo, 'fixStretchy', true);
parser.configuration.addNode('fixStretchy', mo);
}
parser.Push(mo);
}
/**
* Handle undefined control sequence.
* @param {TexParser} parser The calling parser.
* @param {string} name The name of the control sequence.
*/
function csUndefined(_parser: TexParser, name: string) {
// @test Undefined-CS
throw new TexError('UndefinedControlSequence',
'Undefined control sequence %1', '\\' + name);
}
/**
* Handle undefined environments.
* @param {TexParser} parser The calling parser.
* @param {string} name The name of the control sequence.
*/
function envUndefined(_parser: TexParser, env: string) {
// @test Undefined-Env
throw new TexError('UnknownEnv', 'Unknown environment \'%1\'', env);
}
/**
* Filter for removing spacing following \nonscript
* @param{ParseOptions} data The active tex parser.
*/
function filterNonscript({data}: {data: ParseOptions}) {
for (const mml of data.getList('nonscript')) {
//
// This is the list of mspace elements or mrow > mstyle > mspace
// that followed \nonscript macros to be tested for removal.
//
if (mml.attributes.get('scriptlevel') > 0) {
//
// The mspace needs to be removed, since we are in a script style.
// Remove it from the DOM and from the list of mspace elements.
//
const parent = mml.parent;
parent.childNodes.splice(parent.childIndex(mml), 1);
data.removeFromList(mml.kind, [mml]);
//
// If it is an mrow > mstyle > mspace, then we have just
// removed the mrow from its list, and must remove
// the mstyle and mspace from their lists as well.
//
if (mml.isKind('mrow')) {
const mstyle = mml.childNodes[0] as MmlNode;
data.removeFromList('mstyle', [mstyle]);
data.removeFromList('mspace', mstyle.childNodes[0].childNodes as MmlNode[]);
}
} else if (mml.isKind('mrow')) {
//
// This is an mrow > mstyle > mspace but we're not in a script
// style, so remove the mrow that we had added in the NonscriptItem.
//
mml.parent.replaceChild(mml.childNodes[0], mml);
data.removeFromList('mrow', [mml]);
}
}
}
/**
* @constructor
* @extends {AbstractTags}
*/
export class BaseTags extends AbstractTags { }
/**
* The base configuration.
* @type {Configuration}
*/
export const BaseConfiguration: Configuration = Configuration.create(
'base', {
handler: {
character: ['command', 'special', 'letter', 'digit'],
delimiter: ['delimiter'],
// Note, that the position of the delimiters here is important!
macro: ['delimiter', 'macros', 'mathchar0mi', 'mathchar0mo', 'mathchar7'],
environment: ['environment']
},
fallback: {
character: Other,
macro: csUndefined,
environment: envUndefined
},
items: {
// BaseItems
[bitem.StartItem.prototype.kind]: bitem.StartItem,
[bitem.StopItem.prototype.kind]: bitem.StopItem,
[bitem.OpenItem.prototype.kind]: bitem.OpenItem,
[bitem.CloseItem.prototype.kind]: bitem.CloseItem,
[bitem.PrimeItem.prototype.kind]: bitem.PrimeItem,
[bitem.SubsupItem.prototype.kind]: bitem.SubsupItem,
[bitem.OverItem.prototype.kind]: bitem.OverItem,
[bitem.LeftItem.prototype.kind]: bitem.LeftItem,
[bitem.Middle.prototype.kind]: bitem.Middle,
[bitem.RightItem.prototype.kind]: bitem.RightItem,
[bitem.BeginItem.prototype.kind]: bitem.BeginItem,
[bitem.EndItem.prototype.kind]: bitem.EndItem,
[bitem.StyleItem.prototype.kind]: bitem.StyleItem,
[bitem.PositionItem.prototype.kind]: bitem.PositionItem,
[bitem.CellItem.prototype.kind]: bitem.CellItem,
[bitem.MmlItem.prototype.kind]: bitem.MmlItem,
[bitem.FnItem.prototype.kind]: bitem.FnItem,
[bitem.NotItem.prototype.kind]: bitem.NotItem,
[bitem.NonscriptItem.prototype.kind]: bitem.NonscriptItem,
[bitem.DotsItem.prototype.kind]: bitem.DotsItem,
[bitem.ArrayItem.prototype.kind]: bitem.ArrayItem,
[bitem.EqnArrayItem.prototype.kind]: bitem.EqnArrayItem,
[bitem.EquationItem.prototype.kind]: bitem.EquationItem
},
options: {
maxMacros: 1000,
baseURL: (typeof(document) === 'undefined' ||
document.getElementsByTagName('base').length === 0) ?
'' : String(document.location).replace(/#.*$/, '')
},
tags: {
base: BaseTags
},
postprocessors: [[filterNonscript, -4]]
}
);

1242
node_modules/mathjax-full/ts/input/tex/base/BaseItems.ts generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,760 @@
/*************************************************************
*
* Copyright (c) 2017-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Base mappings for TeX Parsing.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import * as sm from '../SymbolMap.js';
import {TexConstant} from '../TexConstants.js';
import BaseMethods from './BaseMethods.js';
import ParseMethods from '../ParseMethods.js';
import ParseUtil from '../ParseUtil.js';
import {TEXCLASS} from '../../../core/MmlTree/MmlNode.js';
import {MATHSPACE, em} from '../../../util/lengths.js';
/**
* Letter pattern for parsing identifiers and operators.
*/
new sm.RegExpMap('letter', ParseMethods.variable, /[a-z]/i);
/**
* Digit pattern for parsing numbers.
*/
new sm.RegExpMap('digit', ParseMethods.digit, /[0-9.,]/);
/**
* Pattern for spotting start of commands.
*/
new sm.RegExpMap('command', ParseMethods.controlSequence, /^\\/ );
/**
* Treatment of special characters in LaTeX.
*/
new sm.MacroMap('special', {
// This is now handled with a RegExp!
// '\\': 'ControlSequence',
'{': 'Open',
'}': 'Close',
'~': 'Tilde',
'^': 'Superscript',
'_': 'Subscript',
' ': 'Space',
'\t': 'Space',
'\r': 'Space',
'\n': 'Space',
'\'': 'Prime',
'%': 'Comment',
'&': 'Entry',
'#': 'Hash',
'\u00A0': 'Space',
'\u2019': 'Prime'
}, BaseMethods);
/**
* Macros for identifiers.
*/
new sm.CharacterMap('mathchar0mi', ParseMethods.mathchar0mi, {
// Lower-case greek
alpha: '\u03B1',
beta: '\u03B2',
gamma: '\u03B3',
delta: '\u03B4',
epsilon: '\u03F5',
zeta: '\u03B6',
eta: '\u03B7',
theta: '\u03B8',
iota: '\u03B9',
kappa: '\u03BA',
lambda: '\u03BB',
mu: '\u03BC',
nu: '\u03BD',
xi: '\u03BE',
omicron: '\u03BF', // added for completeness
pi: '\u03C0',
rho: '\u03C1',
sigma: '\u03C3',
tau: '\u03C4',
upsilon: '\u03C5',
phi: '\u03D5',
chi: '\u03C7',
psi: '\u03C8',
omega: '\u03C9',
varepsilon: '\u03B5',
vartheta: '\u03D1',
varpi: '\u03D6',
varrho: '\u03F1',
varsigma: '\u03C2',
varphi: '\u03C6',
// Ord symbols
S: ['\u00A7', {mathvariant: TexConstant.Variant.NORMAL}],
aleph: ['\u2135', {mathvariant: TexConstant.Variant.NORMAL}],
hbar: ['\u210F', {variantForm: true}],
imath: '\u0131',
jmath: '\u0237',
ell: '\u2113',
wp: ['\u2118', {mathvariant: TexConstant.Variant.NORMAL}],
Re: ['\u211C', {mathvariant: TexConstant.Variant.NORMAL}],
Im: ['\u2111', {mathvariant: TexConstant.Variant.NORMAL}],
partial: ['\u2202', {mathvariant: TexConstant.Variant.ITALIC}],
infty: ['\u221E', {mathvariant: TexConstant.Variant.NORMAL}],
prime: ['\u2032', {variantForm: true}],
emptyset: ['\u2205', {mathvariant: TexConstant.Variant.NORMAL}],
nabla: ['\u2207', {mathvariant: TexConstant.Variant.NORMAL}],
top: ['\u22A4', {mathvariant: TexConstant.Variant.NORMAL}],
bot: ['\u22A5', {mathvariant: TexConstant.Variant.NORMAL}],
angle: ['\u2220', {mathvariant: TexConstant.Variant.NORMAL}],
triangle: ['\u25B3', {mathvariant: TexConstant.Variant.NORMAL}],
backslash: ['\u2216', {mathvariant: TexConstant.Variant.NORMAL}],
forall: ['\u2200', {mathvariant: TexConstant.Variant.NORMAL}],
exists: ['\u2203', {mathvariant: TexConstant.Variant.NORMAL}],
neg: ['\u00AC', {mathvariant: TexConstant.Variant.NORMAL}],
lnot: ['\u00AC', {mathvariant: TexConstant.Variant.NORMAL}],
flat: ['\u266D', {mathvariant: TexConstant.Variant.NORMAL}],
natural: ['\u266E', {mathvariant: TexConstant.Variant.NORMAL}],
sharp: ['\u266F', {mathvariant: TexConstant.Variant.NORMAL}],
clubsuit: ['\u2663', {mathvariant: TexConstant.Variant.NORMAL}],
diamondsuit: ['\u2662', {mathvariant: TexConstant.Variant.NORMAL}],
heartsuit: ['\u2661', {mathvariant: TexConstant.Variant.NORMAL}],
spadesuit: ['\u2660', {mathvariant: TexConstant.Variant.NORMAL}]
});
/**
* Macros for operators.
*/
new sm.CharacterMap('mathchar0mo', ParseMethods.mathchar0mo, {
surd: '\u221A',
// big ops
coprod: ['\u2210', {texClass: TEXCLASS.OP,
movesupsub: true}],
bigvee: ['\u22C1', {texClass: TEXCLASS.OP,
movesupsub: true}],
bigwedge: ['\u22C0', {texClass: TEXCLASS.OP,
movesupsub: true}],
biguplus: ['\u2A04', {texClass: TEXCLASS.OP,
movesupsub: true}],
bigcap: ['\u22C2', {texClass: TEXCLASS.OP,
movesupsub: true}],
bigcup: ['\u22C3', {texClass: TEXCLASS.OP,
movesupsub: true}],
'int': ['\u222B', {texClass: TEXCLASS.OP}],
intop: ['\u222B', {texClass: TEXCLASS.OP,
movesupsub: true, movablelimits: true}],
iint: ['\u222C', {texClass: TEXCLASS.OP}],
iiint: ['\u222D', {texClass: TEXCLASS.OP}],
prod: ['\u220F', {texClass: TEXCLASS.OP,
movesupsub: true}],
sum: ['\u2211', {texClass: TEXCLASS.OP,
movesupsub: true}],
bigotimes: ['\u2A02', {texClass: TEXCLASS.OP,
movesupsub: true}],
bigoplus: ['\u2A01', {texClass: TEXCLASS.OP,
movesupsub: true}],
bigodot: ['\u2A00', {texClass: TEXCLASS.OP,
movesupsub: true}],
oint: ['\u222E', {texClass: TEXCLASS.OP}],
bigsqcup: ['\u2A06', {texClass: TEXCLASS.OP,
movesupsub: true}],
smallint: ['\u222B', {largeop: false}],
// binary operations
triangleleft: '\u25C3',
triangleright: '\u25B9',
bigtriangleup: '\u25B3',
bigtriangledown: '\u25BD',
wedge: '\u2227',
land: '\u2227',
vee: '\u2228',
lor: '\u2228',
cap: '\u2229',
cup: '\u222A',
ddagger: '\u2021',
dagger: '\u2020',
sqcap: '\u2293',
sqcup: '\u2294',
uplus: '\u228E',
amalg: '\u2A3F',
diamond: '\u22C4',
bullet: '\u2219',
wr: '\u2240',
div: '\u00F7',
divsymbol: '\u00F7',
odot: ['\u2299', {largeop: false}],
oslash: ['\u2298', {largeop: false}],
otimes: ['\u2297', {largeop: false}],
ominus: ['\u2296', {largeop: false}],
oplus: ['\u2295', {largeop: false}],
mp: '\u2213',
pm: '\u00B1',
circ: '\u2218',
bigcirc: '\u25EF',
setminus: '\u2216',
cdot: '\u22C5',
ast: '\u2217',
times: '\u00D7',
star: '\u22C6',
// Relations
propto: '\u221D',
sqsubseteq: '\u2291',
sqsupseteq: '\u2292',
parallel: '\u2225',
mid: '\u2223',
dashv: '\u22A3',
vdash: '\u22A2',
leq: '\u2264',
le: '\u2264',
geq: '\u2265',
ge: '\u2265',
lt: '\u003C',
gt: '\u003E',
succ: '\u227B',
prec: '\u227A',
approx: '\u2248',
succeq: '\u2AB0', // or '227C',
preceq: '\u2AAF', // or '227D',
supset: '\u2283',
subset: '\u2282',
supseteq: '\u2287',
subseteq: '\u2286',
'in': '\u2208',
ni: '\u220B',
notin: '\u2209',
owns: '\u220B',
gg: '\u226B',
ll: '\u226A',
sim: '\u223C',
simeq: '\u2243',
perp: '\u22A5',
equiv: '\u2261',
asymp: '\u224D',
smile: '\u2323',
frown: '\u2322',
ne: '\u2260',
neq: '\u2260',
cong: '\u2245',
doteq: '\u2250',
bowtie: '\u22C8',
models: '\u22A8',
notChar: '\u29F8',
// Arrows
Leftrightarrow: '\u21D4',
Leftarrow: '\u21D0',
Rightarrow: '\u21D2',
leftrightarrow: '\u2194',
leftarrow: '\u2190',
gets: '\u2190',
rightarrow: '\u2192',
to: ['\u2192', {accent: false}],
mapsto: '\u21A6',
leftharpoonup: '\u21BC',
leftharpoondown: '\u21BD',
rightharpoonup: '\u21C0',
rightharpoondown: '\u21C1',
nearrow: '\u2197',
searrow: '\u2198',
nwarrow: '\u2196',
swarrow: '\u2199',
rightleftharpoons: '\u21CC',
hookrightarrow: '\u21AA',
hookleftarrow: '\u21A9',
longleftarrow: '\u27F5',
Longleftarrow: '\u27F8',
longrightarrow: '\u27F6',
Longrightarrow: '\u27F9',
Longleftrightarrow: '\u27FA',
longleftrightarrow: '\u27F7',
longmapsto: '\u27FC',
// Misc.
ldots: '\u2026',
cdots: '\u22EF',
vdots: '\u22EE',
ddots: '\u22F1',
dotsc: '\u2026', // dots with commas
dotsb: '\u22EF', // dots with binary ops and relations
dotsm: '\u22EF', // dots with multiplication
dotsi: '\u22EF', // dots with integrals
dotso: '\u2026', // other dots
ldotp: ['\u002E', {texClass: TEXCLASS.PUNCT}],
cdotp: ['\u22C5', {texClass: TEXCLASS.PUNCT}],
colon: ['\u003A', {texClass: TEXCLASS.PUNCT}]
});
/**
* Macros for special characters and identifiers.
*/
new sm.CharacterMap('mathchar7', ParseMethods.mathchar7, {
Gamma: '\u0393',
Delta: '\u0394',
Theta: '\u0398',
Lambda: '\u039B',
Xi: '\u039E',
Pi: '\u03A0',
Sigma: '\u03A3',
Upsilon: '\u03A5',
Phi: '\u03A6',
Psi: '\u03A8',
Omega: '\u03A9',
'_': '\u005F',
'#': '\u0023',
'$': '\u0024',
'%': '\u0025',
'&': '\u0026',
And: '\u0026'
});
/**
* Macros for delimiters.
*/
new sm.DelimiterMap('delimiter', ParseMethods.delimiter, {
'(': '(',
')': ')',
'[': '[',
']': ']',
'<': '\u27E8',
'>': '\u27E9',
'\\lt': '\u27E8',
'\\gt': '\u27E9',
'/': '/',
'|': ['|', {texClass: TEXCLASS.ORD}],
'.': '',
'\\\\': '\\',
'\\lmoustache': '\u23B0', // non-standard
'\\rmoustache': '\u23B1', // non-standard
'\\lgroup': '\u27EE', // non-standard
'\\rgroup': '\u27EF', // non-standard
'\\arrowvert': '\u23D0',
'\\Arrowvert': '\u2016',
'\\bracevert': '\u23AA', // non-standard
'\\Vert': ['\u2016', {texClass: TEXCLASS.ORD}],
'\\|': ['\u2016', {texClass: TEXCLASS.ORD}],
'\\vert': ['|', {texClass: TEXCLASS.ORD}],
'\\uparrow': '\u2191',
'\\downarrow': '\u2193',
'\\updownarrow': '\u2195',
'\\Uparrow': '\u21D1',
'\\Downarrow': '\u21D3',
'\\Updownarrow': '\u21D5',
'\\backslash': '\\',
'\\rangle': '\u27E9',
'\\langle': '\u27E8',
'\\rbrace': '}',
'\\lbrace': '{',
'\\}': '}',
'\\{': '{',
'\\rceil': '\u2309',
'\\lceil': '\u2308',
'\\rfloor': '\u230B',
'\\lfloor': '\u230A',
'\\lbrack': '[',
'\\rbrack': ']'
});
/**
* Macros for LaTeX commands.
*/
new sm.CommandMap('macros', {
displaystyle: ['SetStyle', 'D', true, 0],
textstyle: ['SetStyle', 'T', false, 0],
scriptstyle: ['SetStyle', 'S', false, 1],
scriptscriptstyle: ['SetStyle', 'SS', false, 2],
rm: ['SetFont', TexConstant.Variant.NORMAL],
mit: ['SetFont', TexConstant.Variant.ITALIC],
oldstyle: ['SetFont', TexConstant.Variant.OLDSTYLE],
cal: ['SetFont', TexConstant.Variant.CALLIGRAPHIC],
it: ['SetFont', TexConstant.Variant.MATHITALIC], // needs special handling
bf: ['SetFont', TexConstant.Variant.BOLD],
bbFont: ['SetFont', TexConstant.Variant.DOUBLESTRUCK],
scr: ['SetFont', TexConstant.Variant.SCRIPT],
frak: ['SetFont', TexConstant.Variant.FRAKTUR],
sf: ['SetFont', TexConstant.Variant.SANSSERIF],
tt: ['SetFont', TexConstant.Variant.MONOSPACE],
mathrm: ['MathFont', TexConstant.Variant.NORMAL],
mathup: ['MathFont', TexConstant.Variant.NORMAL],
mathnormal: ['MathFont', ''],
mathbf: ['MathFont', TexConstant.Variant.BOLD],
mathbfup: ['MathFont', TexConstant.Variant.BOLD],
mathit: ['MathFont', TexConstant.Variant.MATHITALIC],
mathbfit: ['MathFont', TexConstant.Variant.BOLDITALIC],
mathbb: ['MathFont', TexConstant.Variant.DOUBLESTRUCK],
Bbb: ['MathFont', TexConstant.Variant.DOUBLESTRUCK],
mathfrak: ['MathFont', TexConstant.Variant.FRAKTUR],
mathbffrak: ['MathFont', TexConstant.Variant.BOLDFRAKTUR],
mathscr: ['MathFont', TexConstant.Variant.SCRIPT],
mathbfscr: ['MathFont', TexConstant.Variant.BOLDSCRIPT],
mathsf: ['MathFont', TexConstant.Variant.SANSSERIF],
mathsfup: ['MathFont', TexConstant.Variant.SANSSERIF],
mathbfsf: ['MathFont', TexConstant.Variant.BOLDSANSSERIF],
mathbfsfup: ['MathFont', TexConstant.Variant.BOLDSANSSERIF],
mathsfit: ['MathFont', TexConstant.Variant.SANSSERIFITALIC],
mathbfsfit: ['MathFont', TexConstant.Variant.SANSSERIFBOLDITALIC],
mathtt: ['MathFont', TexConstant.Variant.MONOSPACE],
mathcal: ['MathFont', TexConstant.Variant.CALLIGRAPHIC],
mathbfcal: ['MathFont', TexConstant.Variant.BOLDCALLIGRAPHIC],
symrm: ['MathFont', TexConstant.Variant.NORMAL],
symup: ['MathFont', TexConstant.Variant.NORMAL],
symnormal: ['MathFont', ''],
symbf: ['MathFont', TexConstant.Variant.BOLD],
symbfup: ['MathFont', TexConstant.Variant.BOLD],
symit: ['MathFont', TexConstant.Variant.ITALIC],
symbfit: ['MathFont', TexConstant.Variant.BOLDITALIC],
symbb: ['MathFont', TexConstant.Variant.DOUBLESTRUCK],
symfrak: ['MathFont', TexConstant.Variant.FRAKTUR],
symbffrak: ['MathFont', TexConstant.Variant.BOLDFRAKTUR],
symscr: ['MathFont', TexConstant.Variant.SCRIPT],
symbfscr: ['MathFont', TexConstant.Variant.BOLDSCRIPT],
symsf: ['MathFont', TexConstant.Variant.SANSSERIF],
symsfup: ['MathFont', TexConstant.Variant.SANSSERIF],
symbfsf: ['MathFont', TexConstant.Variant.BOLDSANSSERIF],
symbfsfup: ['MathFont', TexConstant.Variant.BOLDSANSSERIF],
symsfit: ['MathFont', TexConstant.Variant.SANSSERIFITALIC],
symbfsfit: ['MathFont', TexConstant.Variant.SANSSERIFBOLDITALIC],
symtt: ['MathFont', TexConstant.Variant.MONOSPACE],
symcal: ['MathFont', TexConstant.Variant.CALLIGRAPHIC],
symbfcal: ['MathFont', TexConstant.Variant.BOLDCALLIGRAPHIC],
textrm: ['HBox', null, TexConstant.Variant.NORMAL],
textup: ['HBox', null, TexConstant.Variant.NORMAL],
textnormal: ['HBox'],
textit: ['HBox', null, TexConstant.Variant.ITALIC],
textbf: ['HBox', null, TexConstant.Variant.BOLD],
textsf: ['HBox', null, TexConstant.Variant.SANSSERIF],
texttt: ['HBox', null, TexConstant.Variant.MONOSPACE],
tiny: ['SetSize', 0.5],
Tiny: ['SetSize', 0.6], // non-standard
scriptsize: ['SetSize', 0.7],
small: ['SetSize', 0.85],
normalsize: ['SetSize', 1.0],
large: ['SetSize', 1.2],
Large: ['SetSize', 1.44],
LARGE: ['SetSize', 1.73],
huge: ['SetSize', 2.07],
Huge: ['SetSize', 2.49],
arcsin: 'NamedFn',
arccos: 'NamedFn',
arctan: 'NamedFn',
arg: 'NamedFn',
cos: 'NamedFn',
cosh: 'NamedFn',
cot: 'NamedFn',
coth: 'NamedFn',
csc: 'NamedFn',
deg: 'NamedFn',
det: 'NamedOp',
dim: 'NamedFn',
exp: 'NamedFn',
gcd: 'NamedOp',
hom: 'NamedFn',
inf: 'NamedOp',
ker: 'NamedFn',
lg: 'NamedFn',
lim: 'NamedOp',
liminf: ['NamedOp', 'lim&thinsp;inf'],
limsup: ['NamedOp', 'lim&thinsp;sup'],
ln: 'NamedFn',
log: 'NamedFn',
max: 'NamedOp',
min: 'NamedOp',
Pr: 'NamedOp',
sec: 'NamedFn',
sin: 'NamedFn',
sinh: 'NamedFn',
sup: 'NamedOp',
tan: 'NamedFn',
tanh: 'NamedFn',
limits: ['Limits', 1],
nolimits: ['Limits', 0],
overline: ['UnderOver', '2015'],
underline: ['UnderOver', '2015'],
overbrace: ['UnderOver', '23DE', 1],
underbrace: ['UnderOver', '23DF', 1],
overparen: ['UnderOver', '23DC'],
underparen: ['UnderOver', '23DD'],
overrightarrow: ['UnderOver', '2192'],
underrightarrow: ['UnderOver', '2192'],
overleftarrow: ['UnderOver', '2190'],
underleftarrow: ['UnderOver', '2190'],
overleftrightarrow: ['UnderOver', '2194'],
underleftrightarrow: ['UnderOver', '2194'],
overset: 'Overset',
underset: 'Underset',
overunderset: 'Overunderset',
stackrel: ['Macro', '\\mathrel{\\mathop{#2}\\limits^{#1}}', 2],
stackbin: ['Macro', '\\mathbin{\\mathop{#2}\\limits^{#1}}', 2],
over: 'Over',
overwithdelims: 'Over',
atop: 'Over',
atopwithdelims: 'Over',
above: 'Over',
abovewithdelims: 'Over',
brace: ['Over', '{', '}'],
brack: ['Over', '[', ']'],
choose: ['Over', '(', ')'],
frac: 'Frac',
sqrt: 'Sqrt',
root: 'Root',
uproot: ['MoveRoot', 'upRoot'],
leftroot: ['MoveRoot', 'leftRoot'],
left: 'LeftRight',
right: 'LeftRight',
middle: 'LeftRight',
llap: 'Lap',
rlap: 'Lap',
raise: 'RaiseLower',
lower: 'RaiseLower',
moveleft: 'MoveLeftRight',
moveright: 'MoveLeftRight',
',': ['Spacer', MATHSPACE.thinmathspace],
':': ['Spacer', MATHSPACE.mediummathspace],
'>': ['Spacer', MATHSPACE.mediummathspace],
';': ['Spacer', MATHSPACE.thickmathspace],
'!': ['Spacer', MATHSPACE.negativethinmathspace],
enspace: ['Spacer', .5],
quad: ['Spacer', 1],
qquad: ['Spacer', 2],
thinspace: ['Spacer', MATHSPACE.thinmathspace],
negthinspace: ['Spacer', MATHSPACE.negativethinmathspace],
hskip: 'Hskip',
hspace: 'Hskip',
kern: 'Hskip',
mskip: 'Hskip',
mspace: 'Hskip',
mkern: 'Hskip',
rule: 'rule',
Rule: ['Rule'],
Space: ['Rule', 'blank'],
nonscript: 'Nonscript',
big: ['MakeBig', TEXCLASS.ORD, 0.85],
Big: ['MakeBig', TEXCLASS.ORD, 1.15],
bigg: ['MakeBig', TEXCLASS.ORD, 1.45],
Bigg: ['MakeBig', TEXCLASS.ORD, 1.75],
bigl: ['MakeBig', TEXCLASS.OPEN, 0.85],
Bigl: ['MakeBig', TEXCLASS.OPEN, 1.15],
biggl: ['MakeBig', TEXCLASS.OPEN, 1.45],
Biggl: ['MakeBig', TEXCLASS.OPEN, 1.75],
bigr: ['MakeBig', TEXCLASS.CLOSE, 0.85],
Bigr: ['MakeBig', TEXCLASS.CLOSE, 1.15],
biggr: ['MakeBig', TEXCLASS.CLOSE, 1.45],
Biggr: ['MakeBig', TEXCLASS.CLOSE, 1.75],
bigm: ['MakeBig', TEXCLASS.REL, 0.85],
Bigm: ['MakeBig', TEXCLASS.REL, 1.15],
biggm: ['MakeBig', TEXCLASS.REL, 1.45],
Biggm: ['MakeBig', TEXCLASS.REL, 1.75],
mathord: ['TeXAtom', TEXCLASS.ORD],
mathop: ['TeXAtom', TEXCLASS.OP],
mathopen: ['TeXAtom', TEXCLASS.OPEN],
mathclose: ['TeXAtom', TEXCLASS.CLOSE],
mathbin: ['TeXAtom', TEXCLASS.BIN],
mathrel: ['TeXAtom', TEXCLASS.REL],
mathpunct: ['TeXAtom', TEXCLASS.PUNCT],
mathinner: ['TeXAtom', TEXCLASS.INNER],
vcenter: ['TeXAtom', TEXCLASS.VCENTER],
buildrel: 'BuildRel',
hbox: ['HBox', 0],
text: 'HBox',
mbox: ['HBox', 0],
fbox: 'FBox',
boxed: ['Macro', '\\fbox{$\\displaystyle{#1}$}', 1],
framebox: 'FrameBox',
strut: 'Strut',
mathstrut: ['Macro', '\\vphantom{(}'],
phantom: 'Phantom',
vphantom: ['Phantom', 1, 0],
hphantom: ['Phantom', 0, 1],
smash: 'Smash',
acute: ['Accent', '00B4'], // or 0301 or 02CA
grave: ['Accent', '0060'], // or 0300 or 02CB
ddot: ['Accent', '00A8'], // or 0308
tilde: ['Accent', '007E'], // or 0303 or 02DC
bar: ['Accent', '00AF'], // or 0304 or 02C9
breve: ['Accent', '02D8'], // or 0306
check: ['Accent', '02C7'], // or 030C
hat: ['Accent', '005E'], // or 0302 or 02C6
vec: ['Accent', '2192'], // or 20D7
dot: ['Accent', '02D9'], // or 0307
widetilde: ['Accent', '007E', 1], // or 0303 or 02DC
widehat: ['Accent', '005E', 1], // or 0302 or 02C6
matrix: 'Matrix',
array: 'Matrix',
pmatrix: ['Matrix', '(', ')'],
cases: ['Matrix', '{', '', 'left left', null, '.1em', null,
true],
eqalign: ['Matrix', null, null, 'right left',
em(MATHSPACE.thickmathspace), '.5em', 'D'],
displaylines: ['Matrix', null, null, 'center', null, '.5em', 'D'],
cr: 'Cr',
'\\': 'CrLaTeX',
newline: ['CrLaTeX', true],
hline: ['HLine', 'solid'],
hdashline: ['HLine', 'dashed'],
// noalign: 'HandleNoAlign',
eqalignno: ['Matrix', null, null, 'right left',
em(MATHSPACE.thickmathspace), '.5em', 'D', null,
'right'],
leqalignno: ['Matrix', null, null, 'right left',
em(MATHSPACE.thickmathspace), '.5em', 'D', null,
'left'],
hfill: 'HFill',
hfil: 'HFill', // \hfil treated as \hfill for now
hfilll: 'HFill', // \hfilll treated as \hfill for now
// TeX substitution macros
bmod: ['Macro', '\\mmlToken{mo}[lspace="thickmathspace"' +
' rspace="thickmathspace"]{mod}'],
pmod: ['Macro', '\\pod{\\mmlToken{mi}{mod}\\kern 6mu #1}', 1],
mod: ['Macro', '\\mathchoice{\\kern18mu}{\\kern12mu}' +
'{\\kern12mu}{\\kern12mu}\\mmlToken{mi}{mod}\\,\\,#1',
1],
pod: ['Macro', '\\mathchoice{\\kern18mu}{\\kern8mu}' +
'{\\kern8mu}{\\kern8mu}(#1)', 1],
iff: ['Macro', '\\;\\Longleftrightarrow\\;'],
skew: ['Macro', '{{#2{#3\\mkern#1mu}\\mkern-#1mu}{}}', 3],
pmb: ['Macro', '\\rlap{#1}\\kern1px{#1}', 1],
TeX: ['Macro', 'T\\kern-.14em\\lower.5ex{E}\\kern-.115em X'],
LaTeX: ['Macro', 'L\\kern-.325em\\raise.21em' +
'{\\scriptstyle{A}}\\kern-.17em\\TeX'],
' ': ['Macro', '\\text{ }'],
// Specially handled
not: 'Not',
dots: 'Dots',
space: 'Tilde',
'\u00A0': 'Tilde',
// LaTeX
begin: 'BeginEnd',
end: 'BeginEnd',
label: 'HandleLabel',
ref: 'HandleRef',
nonumber: 'HandleNoTag',
// Internal use:
mathchoice: 'MathChoice',
mmlToken: 'MmlToken'
}, BaseMethods);
/**
* Macros for LaTeX environments.
*/
new sm.EnvironmentMap('environment', ParseMethods.environment, {
array: ['AlignedArray'],
equation: ['Equation', null, true],
eqnarray: ['EqnArray', null, true, true, 'rcl',
ParseUtil.cols(0, MATHSPACE.thickmathspace), '.5em']
}, BaseMethods);
/**
* Mapping for negated operators.
*/
new sm.CharacterMap('not_remap', null, {
'\u2190': '\u219A',
'\u2192': '\u219B',
'\u2194': '\u21AE',
'\u21D0': '\u21CD',
'\u21D2': '\u21CF',
'\u21D4': '\u21CE',
'\u2208': '\u2209',
'\u220B': '\u220C',
'\u2223': '\u2224',
'\u2225': '\u2226',
'\u223C': '\u2241',
'\u007E': '\u2241',
'\u2243': '\u2244',
'\u2245': '\u2247',
'\u2248': '\u2249',
'\u224D': '\u226D',
'\u003D': '\u2260',
'\u2261': '\u2262',
'\u003C': '\u226E',
'\u003E': '\u226F',
'\u2264': '\u2270',
'\u2265': '\u2271',
'\u2272': '\u2274',
'\u2273': '\u2275',
'\u2276': '\u2278',
'\u2277': '\u2279',
'\u227A': '\u2280',
'\u227B': '\u2281',
'\u2282': '\u2284',
'\u2283': '\u2285',
'\u2286': '\u2288',
'\u2287': '\u2289',
'\u22A2': '\u22AC',
'\u22A8': '\u22AD',
'\u22A9': '\u22AE',
'\u22AB': '\u22AF',
'\u227C': '\u22E0',
'\u227D': '\u22E1',
'\u2291': '\u22E2',
'\u2292': '\u22E3',
'\u22B2': '\u22EA',
'\u22B3': '\u22EB',
'\u22B4': '\u22EC',
'\u22B5': '\u22ED',
'\u2203': '\u2204'
});

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,123 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Configuration file for the bbox package.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {Configuration} from '../Configuration.js';
import TexParser from '../TexParser.js';
import {CommandMap} from '../SymbolMap.js';
import {ParseMethod} from '../Types.js';
import TexError from '../TexError.js';
// Namespace
export let BboxMethods: Record<string, ParseMethod> = {};
/**
* Implements MathJax Bbox macro to pad and colorize background boxes.
* @param {TexParser} parser The current tex parser.
* @param {string} name The name of the calling macro.
*/
BboxMethods.BBox = function(parser: TexParser, name: string) {
const bbox = parser.GetBrackets(name, '');
let math = parser.ParseArg(name);
const parts = bbox.split(/,/);
let def, background, style;
for (let i = 0, m = parts.length; i < m; i++) {
const part = parts[i].trim();
const match = part.match(/^(\.\d+|\d+(\.\d*)?)(pt|em|ex|mu|px|in|cm|mm)$/);
if (match) {
// @test Bbox-Padding
if (def) {
// @test Bbox-Padding-Error
throw new TexError('MultipleBBoxProperty', '%1 specified twice in %2', 'Padding', name);
}
const pad = BBoxPadding(match[1] + match[3]);
if (pad) {
// @test Bbox-Padding
def = {
height: '+' + pad,
depth: '+' + pad,
lspace: pad,
width: '+' + (2 * parseInt(match[1], 10)) + match[3]
};
}
} else if (part.match(/^([a-z0-9]+|\#[0-9a-f]{6}|\#[0-9a-f]{3})$/i)) {
// @test Bbox-Background
if (background) {
// @test Bbox-Background-Error
throw new TexError('MultipleBBoxProperty', '%1 specified twice in %2',
'Background', name);
}
background = part;
} else if (part.match(/^[-a-z]+:/i)) {
// @test Bbox-Frame
if (style) {
// @test Bbox-Frame-Error
throw new TexError('MultipleBBoxProperty', '%1 specified twice in %2',
'Style', name);
}
style = BBoxStyle(part);
} else if (part !== '') {
// @test Bbox-General-Error
throw new TexError(
'InvalidBBoxProperty',
'"%1" doesn\'t look like a color, a padding dimension, or a style',
part);
}
}
if (def) {
// @test Bbox-Padding
math = parser.create('node', 'mpadded', [math], def);
}
if (background || style) {
def = {};
if (background) {
// @test Bbox-Background
Object.assign(def, {mathbackground: background});
}
if (style) {
// @test Bbox-Frame
Object.assign(def, {style: style});
}
math = parser.create('node', 'mstyle', [math], def);
}
parser.Push(math);
};
// Dummy methods. Need to be made Safe with security check.
let BBoxStyle = function(styles: string) {
return styles;
};
let BBoxPadding = function(pad: string) {
return pad;
};
new CommandMap('bbox', {bbox: 'BBox'}, BboxMethods);
export const BboxConfiguration = Configuration.create(
'bbox', {handler: {macro: ['bbox']}}
);

View File

@@ -0,0 +1,113 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Configuration file for the boldsymbol package.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {MmlNode} from '../../../core/MmlTree/MmlNode.js';
import {Configuration} from '../Configuration.js';
import NodeUtil from '../NodeUtil.js';
import TexParser from '../TexParser.js';
import {TexConstant} from '../TexConstants.js';
import {CommandMap} from '../SymbolMap.js';
import {ParseMethod} from '../Types.js';
import {NodeFactory} from '../NodeFactory.js';
import ParseOptions from '../ParseOptions.js';
let BOLDVARIANT: {[key: string]: string} = {};
BOLDVARIANT[TexConstant.Variant.NORMAL] = TexConstant.Variant.BOLD;
BOLDVARIANT[TexConstant.Variant.ITALIC] = TexConstant.Variant.BOLDITALIC;
BOLDVARIANT[TexConstant.Variant.FRAKTUR] = TexConstant.Variant.BOLDFRAKTUR;
BOLDVARIANT[TexConstant.Variant.SCRIPT] = TexConstant.Variant.BOLDSCRIPT;
BOLDVARIANT[TexConstant.Variant.SANSSERIF] = TexConstant.Variant.BOLDSANSSERIF;
BOLDVARIANT['-tex-calligraphic'] = '-tex-bold-calligraphic';
BOLDVARIANT['-tex-oldstyle'] = '-tex-bold-oldstyle';
BOLDVARIANT['-tex-mathit'] = TexConstant.Variant.BOLDITALIC;
// Namespace
export let BoldsymbolMethods: Record<string, ParseMethod> = {};
/**
* Parse function for boldsymbol macro.
* @param {TexParser} parser The current tex parser.
* @param {string} name The name of the macro.
*/
BoldsymbolMethods.Boldsymbol = function(parser: TexParser, name: string) {
let boldsymbol = parser.stack.env['boldsymbol'];
parser.stack.env['boldsymbol'] = true;
let mml = parser.ParseArg(name);
parser.stack.env['boldsymbol'] = boldsymbol;
parser.Push(mml);
};
new CommandMap('boldsymbol', {boldsymbol: 'Boldsymbol'}, BoldsymbolMethods);
/**
* Creates token nodes in bold font if possible.
* @param {NodeFactory} factory The current node factory.
* @param {string} kind The type of token node to create.
* @param {any} def Properties for the node.
* @param {string} text The text content.
* @return {MmlNode} The generated token node.
*/
export function createBoldToken(factory: NodeFactory, kind: string,
def: any, text: string): MmlNode {
let token = NodeFactory.createToken(factory, kind, def, text);
if (kind !== 'mtext' &&
factory.configuration.parser.stack.env['boldsymbol']) {
NodeUtil.setProperty(token, 'fixBold', true);
factory.configuration.addNode('fixBold', token);
}
return token;
}
/**
* Postprocessor to rewrite token nodes to bold font, if possible.
* @param {ParseOptions} data The parse options.
*/
export function rewriteBoldTokens(arg: {data: ParseOptions}) {
for (let node of arg.data.getList('fixBold')) {
if (NodeUtil.getProperty(node, 'fixBold')) {
let variant = NodeUtil.getAttribute(node, 'mathvariant') as string;
if (variant == null) {
NodeUtil.setAttribute(node, 'mathvariant', TexConstant.Variant.BOLD);
} else {
NodeUtil.setAttribute(node,
'mathvariant', BOLDVARIANT[variant] || variant);
}
NodeUtil.removeProperties(node, 'fixBold');
}
}
}
export const BoldsymbolConfiguration = Configuration.create(
'boldsymbol', {
handler: {macro: ['boldsymbol']},
nodes: {'token': createBoldToken},
postprocessors: [rewriteBoldTokens]
}
);

View File

@@ -0,0 +1,42 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Configuration file for the Braket package.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {Configuration} from '../Configuration.js';
import {BraketItem} from './BraketItems.js';
import './BraketMappings.js';
export const BraketConfiguration = Configuration.create(
'braket', {
handler: {
character: ['Braket-characters'],
macro: ['Braket-macros']
},
items: {
[BraketItem.prototype.kind]: BraketItem,
}
}
);

View File

@@ -0,0 +1,89 @@
/*************************************************************
*
* Copyright (c) 2009-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Stack items for parsing the braket package.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {CheckType, BaseItem, StackItem} from '../StackItem.js';
import {TEXCLASS} from '../../../core/MmlTree/MmlNode.js';
import ParseUtil from '../ParseUtil.js';
/**
* A bra-ket command. Collates elements from the opening brace to the closing
* brace, adding bars to a given maximal number (e.g., only one in case of
* set). To finalise it adds the surrounding angle brackets or braces.
*/
export class BraketItem extends BaseItem {
/**
* @override
*/
get kind() {
return 'braket';
}
/**
* @override
*/
get isOpen() {
return true;
}
/**
* @override
*/
public checkItem(item: StackItem): CheckType {
if (item.isKind('close')) {
return [[this.factory.create('mml', this.toMml())], true];
}
if (item.isKind('mml')) {
this.Push(item.toMml());
if (this.getProperty('single')) {
return [[this.toMml()], true];
}
return BaseItem.fail;
}
return super.checkItem(item);
}
/**
* @override
*/
public toMml() {
let inner = super.toMml();
let open = this.getProperty('open') as string;
let close = this.getProperty('close') as string;
if (this.getProperty('stretchy')) {
return ParseUtil.fenced(this.factory.configuration, open, inner, close);
}
let attrs = {fence: true, stretchy: false, symmetric: true, texClass: TEXCLASS.OPEN};
let openNode = this.create('token', 'mo', attrs, open);
attrs.texClass = TEXCLASS.CLOSE;
let closeNode = this.create('token', 'mo', attrs, close);
let mrow = this.create('node', 'mrow', [openNode, inner, closeNode],
{open: open, close: close, texClass: TEXCLASS.INNER});
return mrow;
}
}

View File

@@ -0,0 +1,56 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Mappings for TeX parsing of the braket package.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {CommandMap, MacroMap} from '../SymbolMap.js';
import BraketMethods from './BraketMethods.js';
/**
* Macros for braket package.
*/
new CommandMap('Braket-macros', {
bra: ['Macro', '{\\langle {#1} \\vert}', 1],
ket: ['Macro', '{\\vert {#1} \\rangle}', 1],
braket: ['Braket', '\u27E8', '\u27E9', false, Infinity],
'set': ['Braket', '{', '}', false, 1],
Bra: ['Macro', '{\\left\\langle {#1} \\right\\vert}', 1],
Ket: ['Macro', '{\\left\\vert {#1} \\right\\rangle}', 1],
Braket: ['Braket', '\u27E8', '\u27E9', true, Infinity],
Set: ['Braket', '{', '}', true, 1],
// Not part of the LaTeX package:
ketbra: ['Macro', '{\\vert {#1} \\rangle\\langle {#2} \\vert}', 2],
Ketbra: ['Macro', '{\\left\\vert {#1} \\right\\rangle\\left\\langle {#2} \\right\\vert}', 2],
// Treatment of bar.
'|': 'Bar'
}, BraketMethods);
/**
* Character map for braket package.
*/
new MacroMap('Braket-characters', {
'|': 'Bar'
}, BraketMethods);

View File

@@ -0,0 +1,99 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Methods for TeX parsing of the braket package.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {ParseMethod} from '../Types.js';
import BaseMethods from '../base/BaseMethods.js';
import TexParser from '../TexParser.js';
import {TEXCLASS} from '../../../core/MmlTree/MmlNode.js';
import TexError from '../TexError.js';
let BraketMethods: Record<string, ParseMethod> = {};
BraketMethods.Macro = BaseMethods.Macro;
/**
* Generate a bra-ket expression.
* @param {TexParser} parser The current TeX parser.
* @param {string} name Name of the current control sequence.
* @param {string} open Opening delimiter.
* @param {string} close Closing delimiter.
* @param {boolean} stretchy Is it stretchy.
* @param {number} barmax Maximum number of bars allowed.
*/
BraketMethods.Braket = function(parser: TexParser, _name: string,
open: string, close: string,
stretchy: boolean, barmax: number) {
let next = parser.GetNext();
if (next === '') {
throw new TexError('MissingArgFor', 'Missing argument for %1', parser.currentCS);
}
let single = true;
if (next === '{') {
parser.i++;
single = false;
}
parser.Push(
parser.itemFactory.create('braket')
.setProperties({barmax: barmax, barcount: 0, open: open,
close: close, stretchy: stretchy, single: single}));
};
/**
* Generate a bar. If inside a bra-ket expressions it's handled accordingly.
* @param {TexParser} parser The current TeX parser.
* @param {string} name Name of the current control sequence.
*/
BraketMethods.Bar = function(parser: TexParser, name: string) {
let c = name === '|' ? '|' : '\u2225';
let top = parser.stack.Top();
if (top.kind !== 'braket' ||
top.getProperty('barcount') >= top.getProperty('barmax')) {
let mml = parser.create('token', 'mo', {texClass: TEXCLASS.ORD, stretchy: false}, c);
parser.Push(mml);
return;
}
if (c === '|' && parser.GetNext() === '|') {
parser.i++;
c = '\u2225';
}
let stretchy = top.getProperty('stretchy');
if (!stretchy) {
let node = parser.create('token', 'mo', {stretchy: false, braketbar: true}, c);
parser.Push(node);
return;
}
let node = parser.create('node', 'TeXAtom', [], {texClass: TEXCLASS.CLOSE});
parser.Push(node);
top.setProperty('barcount', top.getProperty('barcount') as number + 1);
node = parser.create('token', 'mo', {stretchy: true, braketbar: true}, c);
parser.Push(node);
node = parser.create('node', 'TeXAtom', [], {texClass: TEXCLASS.OPEN});
parser.Push(node);
};
export default BraketMethods;

View File

@@ -0,0 +1,49 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Configuration file for the Bussproofs package.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {Configuration} from '../Configuration.js';
import {ProofTreeItem} from './BussproofsItems.js';
import {saveDocument, clearDocument, balanceRules, makeBsprAttributes} from './BussproofsUtil.js';
import './BussproofsMappings.js';
export const BussproofsConfiguration = Configuration.create(
'bussproofs', {
handler: {
macro: ['Bussproofs-macros'],
environment: ['Bussproofs-environments']
},
items: {
[ProofTreeItem.prototype.kind]: ProofTreeItem,
},
preprocessors: [
[saveDocument, 1]
],
postprocessors: [
[clearDocument, 3],
[makeBsprAttributes, 2],
[balanceRules, 1]
]
}
);

View File

@@ -0,0 +1,88 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Items for TeX parsing of bussproofs.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import TexError from '../TexError.js';
import {BaseItem, CheckType, StackItem} from '../StackItem.js';
import {MmlNode} from '../../../core/MmlTree/MmlNode.js';
import Stack from '../Stack.js';
import * as BussproofsUtil from './BussproofsUtil.js';
export class ProofTreeItem extends BaseItem {
/**
* The current left label.
* @type {MmlNode[]}
*/
public leftLabel: MmlNode[] = null;
/**
* The current right label.
* @type {MmlNode[]}
*/
public rigthLabel: MmlNode[] = null;
private innerStack: Stack = new Stack(this.factory, {}, true);
/**
* @override
*/
public get kind() {
return 'proofTree';
}
/**
* @override
*/
public checkItem(item: StackItem): CheckType {
if (item.isKind('end') && item.getName() === 'prooftree') {
let node = this.toMml();
BussproofsUtil.setProperty(node, 'proof', true);
return [[this.factory.create('mml', node), item], true];
}
if (item.isKind('stop')) {
throw new TexError('EnvMissingEnd', 'Missing \\end{%1}', this.getName());
}
this.innerStack.Push(item);
return BaseItem.fail;
}
/**
* @override
*/
public toMml() {
const tree = super.toMml();
const start = this.innerStack.Top();
if (start.isKind('start') && !start.Size()) {
return tree;
}
this.innerStack.Push(this.factory.create('stop'));
let prefix = this.innerStack.Top().toMml();
return this.create('node', 'mrow', [prefix, tree], {});
}
}

View File

@@ -0,0 +1,85 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Mappings for TeX parsing for Bussproofs package commands.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import BussproofsMethods from './BussproofsMethods.js';
import ParseMethods from '../ParseMethods.js';
import {CommandMap, EnvironmentMap} from '../SymbolMap.js';
/**
* Macros for bussproofs etc.
*/
new CommandMap('Bussproofs-macros', {
AxiomC: 'Axiom',
UnaryInfC: ['Inference', 1],
BinaryInfC: ['Inference', 2],
TrinaryInfC: ['Inference', 3],
QuaternaryInfC: ['Inference', 4],
QuinaryInfC: ['Inference', 5],
RightLabel: ['Label', 'right'],
LeftLabel: ['Label', 'left'],
// Abbreviations are automatically enabled
AXC: 'Axiom',
UIC: ['Inference', 1],
BIC: ['Inference', 2],
TIC: ['Inference', 3],
RL: ['Label', 'right'],
LL: ['Label', 'left'],
noLine: ['SetLine', 'none', false],
singleLine: ['SetLine', 'solid', false],
solidLine: ['SetLine', 'solid', false],
dashedLine: ['SetLine', 'dashed', false],
// Not yet implemented in CSS!
// doubleLine: ['SetLine', 'double', false],
// dottedLine: ['SetLine', 'dotted', false],
alwaysNoLine: ['SetLine', 'none', true],
alwaysSingleLine: ['SetLine', 'solid', true],
alwaysSolidLine: ['SetLine', 'solid', true],
alwaysDashedLine: ['SetLine', 'dashed', true],
// Not yet implemented in CSS!
// alwaysDoubleLine: ['SetLine', 'double', true],
// alwaysDottedLine: ['SetLine', 'dotted', true],
rootAtTop: ['RootAtTop', true],
alwaysRootAtTop: ['RootAtTop', true],
rootAtBottom: ['RootAtTop', false],
alwaysRootAtBottom: ['RootAtTop', false],
// TODO: always commands should be persistent.
fCenter: 'FCenter',
Axiom: 'AxiomF',
UnaryInf: ['InferenceF', 1],
BinaryInf: ['InferenceF', 2],
TrinaryInf: ['InferenceF', 3],
QuaternaryInf: ['InferenceF', 4],
QuinaryInf: ['InferenceF', 5]
}, BussproofsMethods);
new EnvironmentMap('Bussproofs-environments', ParseMethods.environment, {
prooftree: ['Prooftree', null, false]
}, BussproofsMethods);

View File

@@ -0,0 +1,352 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Mappings for TeX parsing for the bussproofs package.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {ParseMethod} from '../Types.js';
import TexError from '../TexError.js';
import TexParser from '../TexParser.js';
import ParseUtil from '../ParseUtil.js';
import {StackItem} from '../StackItem.js';
import {MmlNode} from '../../../core/MmlTree/MmlNode.js';
import * as BussproofsUtil from './BussproofsUtil.js';
// Namespace
let BussproofsMethods: Record<string, ParseMethod> = {};
/**
* Implements the proof tree environment.
* @param {TexParser} parser The current parser.
* @param {StackItem} begin The opening element of the environment.
* @return {StackItem} The proof tree stackitem.
*/
// TODO: Error handling if we have leftover elements or elements are not in the
// required order.
BussproofsMethods.Prooftree = function(parser: TexParser, begin: StackItem): StackItem {
parser.Push(begin);
// TODO: Check if opening a proof tree is legal.
let newItem = parser.itemFactory.create('proofTree').
setProperties({name: begin.getName(),
line: 'solid', currentLine: 'solid', rootAtTop: false});
// parser.Push(item);
return newItem;
};
/**
* Implements the Axiom command.
* @param {TexParser} parser The current parser.
* @param {string} name The name of the command.
*/
BussproofsMethods.Axiom = function(parser: TexParser, name: string) {
let top = parser.stack.Top();
// TODO: Label error
if (top.kind !== 'proofTree') {
throw new TexError('IllegalProofCommand',
'Proof commands only allowed in prooftree environment.');
}
let content = paddedContent(parser, parser.GetArgument(name));
BussproofsUtil.setProperty(content, 'axiom', true);
top.Push(content);
};
/**
* Pads content of an inference rule.
* @param {TexParser} parser The calling parser.
* @param {string} content The content to be padded.
* @return {MmlNode} The mrow element with padded content.
*/
const paddedContent = function(parser: TexParser, content: string): MmlNode {
// Add padding on either site.
let nodes = ParseUtil.internalMath(parser, ParseUtil.trimSpaces(content), 0);
if (!nodes[0].childNodes[0].childNodes.length) {
return parser.create('node', 'mrow', []);
}
let lpad = parser.create('node', 'mspace', [], {width: '.5ex'});
let rpad = parser.create('node', 'mspace', [], {width: '.5ex'});
return parser.create('node', 'mrow', [lpad, ...nodes, rpad]);
};
/**
* Implements the Inference rule commands.
* @param {TexParser} parser The current parser.
* @param {string} name The name of the command.
* @param {number} n Number of premises for this inference rule.
*/
BussproofsMethods.Inference = function(parser: TexParser, name: string, n: number) {
let top = parser.stack.Top();
if (top.kind !== 'proofTree') {
throw new TexError('IllegalProofCommand',
'Proof commands only allowed in prooftree environment.');
}
if (top.Size() < n) {
throw new TexError('BadProofTree', 'Proof tree badly specified.');
}
const rootAtTop = top.getProperty('rootAtTop') as boolean;
const childCount = (n === 1 && !top.Peek()[0].childNodes.length) ? 0 : n;
let children: MmlNode[] = [];
do {
if (children.length) {
children.unshift(parser.create('node', 'mtd', [], {}));
}
children.unshift(
parser.create('node', 'mtd', [top.Pop()],
{'rowalign': (rootAtTop ? 'top' : 'bottom')}));
n--;
} while (n > 0);
let row = parser.create('node', 'mtr', children, {});
let table = parser.create('node', 'mtable', [row], {framespacing: '0 0'});
let conclusion = paddedContent(parser, parser.GetArgument(name));
let style = top.getProperty('currentLine') as string;
if (style !== top.getProperty('line')) {
top.setProperty('currentLine', top.getProperty('line'));
}
let rule = createRule(
parser, table, [conclusion], top.getProperty('left') as MmlNode,
top.getProperty('right') as MmlNode, style, rootAtTop);
top.setProperty('left', null);
top.setProperty('right', null);
BussproofsUtil.setProperty(rule, 'inference', childCount);
parser.configuration.addNode('inference', rule);
top.Push(rule);
};
/**
* Creates a ND style inference rule.
* @param {TexParser} parser The calling parser.
* @param {MmlNode} premise The premise (a single table).
* @param {MmlNode[]} conclusions Elements that are combined into the conclusion.
* @param {MmlNode|null} left The left label if it exists.
* @param {MmlNode|null} right The right label if it exists.
* @param {string} style Style of inference rule line.
* @param {boolean} rootAtTop Direction of inference rule: true for root at top.
*/
function createRule(parser: TexParser, premise: MmlNode,
conclusions: MmlNode[], left: MmlNode | null,
right: MmlNode | null, style: string,
rootAtTop: boolean) {
const upper = parser.create(
'node', 'mtr', [parser.create('node', 'mtd', [premise], {})], {});
const lower = parser.create(
'node', 'mtr', [parser.create('node', 'mtd', conclusions, {})], {});
let rule = parser.create('node', 'mtable', rootAtTop ? [lower, upper] : [upper, lower],
{align: 'top 2', rowlines: style, framespacing: '0 0'});
BussproofsUtil.setProperty(rule, 'inferenceRule', rootAtTop ? 'up' : 'down');
let leftLabel, rightLabel;
if (left) {
leftLabel = parser.create(
'node', 'mpadded', [left],
{height: '+.5em', width: '+.5em', voffset: '-.15em'});
BussproofsUtil.setProperty(leftLabel, 'prooflabel', 'left');
}
if (right) {
rightLabel = parser.create(
'node', 'mpadded', [right],
{height: '+.5em', width: '+.5em', voffset: '-.15em'});
BussproofsUtil.setProperty(rightLabel, 'prooflabel', 'right');
}
let children, label;
if (left && right) {
children = [leftLabel, rule, rightLabel];
label = 'both';
} else if (left) {
children = [leftLabel, rule];
label = 'left';
} else if (right) {
children = [rule, rightLabel];
label = 'right';
} else {
return rule;
}
rule = parser.create('node', 'mrow', children);
BussproofsUtil.setProperty(rule, 'labelledRule', label);
return rule;
}
/**
* Implements the label command.
* @param {TexParser} parser The current parser.
* @param {string} name The name of the command.
* @param {string} side The side of the label.
*/
BussproofsMethods.Label = function(parser: TexParser, name: string, side: string) {
let top = parser.stack.Top();
// Label error
if (top.kind !== 'proofTree') {
throw new TexError('IllegalProofCommand',
'Proof commands only allowed in prooftree environment.');
}
let content = ParseUtil.internalMath(parser, parser.GetArgument(name), 0);
let label = (content.length > 1) ?
parser.create('node', 'mrow', content, {}) : content[0];
top.setProperty(side, label);
};
/**
* Sets line style for inference rules.
* @param {TexParser} parser The current parser.
* @param {string} name The name of the command.
* @param {string} style The line style to set.
* @param {boolean} always Set as permanent style.
*/
BussproofsMethods.SetLine = function(parser: TexParser, _name: string, style: string, always: boolean) {
let top = parser.stack.Top();
// Label error
if (top.kind !== 'proofTree') {
throw new TexError('IllegalProofCommand',
'Proof commands only allowed in prooftree environment.');
}
top.setProperty('currentLine', style);
if (always) {
top.setProperty('line', style);
}
};
/**
* Implements commands indicating where the root of the proof tree is.
* @param {TexParser} parser The current parser.
* @param {string} name The name of the command.
* @param {string} where If true root is at top, otherwise at bottom.
*/
BussproofsMethods.RootAtTop = function(parser: TexParser, _name: string, where: boolean) {
let top = parser.stack.Top();
if (top.kind !== 'proofTree') {
throw new TexError('IllegalProofCommand',
'Proof commands only allowed in prooftree environment.');
}
top.setProperty('rootAtTop', where);
};
/**
* Implements Axiom command for sequents.
* @param {TexParser} parser The current parser.
* @param {string} name The name of the command.
*/
BussproofsMethods.AxiomF = function(parser: TexParser, name: string) {
let top = parser.stack.Top();
if (top.kind !== 'proofTree') {
throw new TexError('IllegalProofCommand',
'Proof commands only allowed in prooftree environment.');
}
let line = parseFCenterLine(parser, name);
BussproofsUtil.setProperty(line, 'axiom', true);
top.Push(line);
};
/**
* Parses a line with a sequent (i.e., one containing \\fcenter).
* @param {TexParser} parser The current parser.
* @param {string} name The name of the calling command.
* @return {MmlNode} The parsed line.
*/
function parseFCenterLine(parser: TexParser, name: string): MmlNode {
let dollar = parser.GetNext();
if (dollar !== '$') {
throw new TexError('IllegalUseOfCommand',
'Use of %1 does not match it\'s definition.', name);
}
parser.i++;
let axiom = parser.GetUpTo(name, '$');
if (axiom.indexOf('\\fCenter') === -1) {
throw new TexError('IllegalUseOfCommand',
'Missing \\fCenter in %1.', name);
}
// Check for fCenter and throw error?
let [prem, conc] = axiom.split('\\fCenter');
let premise = (new TexParser(prem, parser.stack.env, parser.configuration)).mml();
let conclusion = (new TexParser(conc, parser.stack.env, parser.configuration)).mml();
let fcenter = (new TexParser('\\fCenter', parser.stack.env, parser.configuration)).mml();
const left = parser.create('node', 'mtd', [premise], {});
const middle = parser.create('node', 'mtd', [fcenter], {});
const right = parser.create('node', 'mtd', [conclusion], {});
const row = parser.create('node', 'mtr', [left, middle, right], {});
const table = parser.create('node', 'mtable', [row], {columnspacing: '.5ex', columnalign: 'center 2'});
BussproofsUtil.setProperty(table, 'sequent', true);
parser.configuration.addNode('sequent', row);
return table;
}
/**
* Placeholder for Fcenter macro that can be overwritten with renewcommand.
* @param {TexParser} parser The current parser.
* @param {string} name The name of the command.
*/
BussproofsMethods.FCenter = function(_parser: TexParser, _name: string) { };
/**
* Implements inference rules for sequents.
* @param {TexParser} parser The current parser.
* @param {string} name The name of the command.
* @param {number} n Number of premises for this inference rule.
*/
BussproofsMethods.InferenceF = function(parser: TexParser, name: string, n: number) {
let top = parser.stack.Top();
if (top.kind !== 'proofTree') {
throw new TexError('IllegalProofCommand',
'Proof commands only allowed in prooftree environment.');
}
if (top.Size() < n) {
throw new TexError('BadProofTree', 'Proof tree badly specified.');
}
const rootAtTop = top.getProperty('rootAtTop') as boolean;
const childCount = (n === 1 && !top.Peek()[0].childNodes.length) ? 0 : n;
let children: MmlNode[] = [];
do {
if (children.length) {
children.unshift(parser.create('node', 'mtd', [], {}));
}
children.unshift(
parser.create('node', 'mtd', [top.Pop()],
{'rowalign': (rootAtTop ? 'top' : 'bottom')}));
n--;
} while (n > 0);
let row = parser.create('node', 'mtr', children, {});
let table = parser.create('node', 'mtable', [row], {framespacing: '0 0'});
let conclusion = parseFCenterLine(parser, name); // TODO: Padding
let style = top.getProperty('currentLine') as string;
if (style !== top.getProperty('line')) {
top.setProperty('currentLine', top.getProperty('line'));
}
let rule = createRule(
parser, table, [conclusion], top.getProperty('left') as MmlNode,
top.getProperty('right') as MmlNode, style, rootAtTop);
top.setProperty('left', null);
top.setProperty('right', null);
BussproofsUtil.setProperty(rule, 'inference', childCount);
parser.configuration.addNode('inference', rule);
top.Push(rule);
};
export default BussproofsMethods;

View File

@@ -0,0 +1,626 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Postfilter utility for the Bussproofs package.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import ParseOptions from '../ParseOptions.js';
import NodeUtil from '../NodeUtil.js';
import ParseUtil from '../ParseUtil.js';
import {MmlNode} from '../../../core/MmlTree/MmlNode.js';
import {Property} from '../../../core/Tree/Node.js';
import {MathItem} from '../../../core/MathItem.js';
import {MathDocument} from '../../../core/MathDocument.js';
type MATHITEM = MathItem<any, any, any>;
type MATHDOCUMENT = MathDocument<any, any, any>;
type FilterData = {math: MATHITEM, document: MATHDOCUMENT, data: ParseOptions};
/**
* Global constants local to the module. They instantiate an output jax for
* bounding box computation.
*/
let doc: MATHDOCUMENT = null;
let item: MATHITEM = null;
/**
* Get the bounding box of a node.
* @param {MmlNode} node The target node.
*/
let getBBox = function(node: MmlNode) {
item.root = node;
let {w: width} = (doc.outputJax as any).getBBox(item, doc);
return width;
};
/**
* Get the actual table that represents the inference rule, i.e., the rule
* without the label. We ignore preceding elements or spaces.
*
* @param {MmlNode} node The out node representing the inference.
* @return {MmlNode} The actual table representing the inference rule.
*/
let getRule = function(node: MmlNode): MmlNode {
let i = 0;
while (node && !NodeUtil.isType(node, 'mtable')) {
if (NodeUtil.isType(node, 'text')) {
return null;
}
if (NodeUtil.isType(node, 'mrow')) {
node = node.childNodes[0] as MmlNode;
i = 0;
continue;
}
node = node.parent.childNodes[i] as MmlNode;
i++;
}
return node;
};
/*******************************
* Convenience methods for retrieving bits of the proof tree.
*/
/**
* Gets premises of an inference rule.
* @param {MmlNode} rule The rule.
* @param {string} direction Up or down.
* @return {MmlNode} The premisses.
*/
let getPremises = function(rule: MmlNode, direction: string): MmlNode {
return rule.childNodes[direction === 'up' ? 1 : 0].childNodes[0].
childNodes[0].childNodes[0].childNodes[0] as MmlNode;
};
/**
* Gets nth premise.
* @param {MmlNode} premises The premises.
* @param {number} n Number of premise to get.
* @return {MmlNode} The nth premise.
*/
let getPremise = function(premises: MmlNode, n: number): MmlNode {
return premises.childNodes[n].childNodes[0].childNodes[0] as MmlNode;
};
/**
* Gets first premise.
* @param {MmlNode} premises The premises.
* @return {MmlNode} The first premise.
*/
let firstPremise = function(premises: MmlNode): MmlNode {
return getPremise(premises, 0) as MmlNode;
};
/**
* Gets last premise.
* @param {MmlNode} premises The premises.
* @return {MmlNode} The last premise.
*/
let lastPremise = function(premises: MmlNode): MmlNode {
return getPremise(premises, premises.childNodes.length - 1);
};
/**
* Get conclusion in an inference rule.
* @param {MmlNode} rule The rule.
* @param {string} direction Up or down.
* @return {MmlNode} The conclusion.
*/
let getConclusion = function(rule: MmlNode, direction: string): MmlNode {
return rule.childNodes[direction === 'up' ? 0 : 1].childNodes[0].childNodes[0].childNodes[0] as MmlNode;
};
/**
* Gets the actual column element in an inference rule. I.e., digs down through
* row, padding and space elements.
* @param {MmlNode} inf The rule.
* @return {MmlNode} The mtd element.
*/
let getColumn = function(inf: MmlNode): MmlNode {
while (inf && !NodeUtil.isType(inf, 'mtd')) {
inf = inf.parent as MmlNode;
}
return inf;
};
/**
* Gets the next sibling of an inference rule.
* @param {MmlNode} inf The inference rule.
* @return {MmlNode} The next sibling.
*/
let nextSibling = function(inf: MmlNode): MmlNode {
return inf.parent.childNodes[inf.parent.childNodes.indexOf(inf) + 1] as MmlNode;
};
/**
* Gets the previous sibling of an inference rule.
* @param {MmlNode} inf The inference rule.
* @return {MmlNode} The previous sibling.
*/
// @ts-ignore
let previousSibling = function(inf: MmlNode): MmlNode {
return inf.parent.childNodes[inf.parent.childNodes.indexOf(inf) - 1] as MmlNode;
};
/**
* Get the parent inference rule.
* @param {MmlNode} inf The inference rule.
* @return {MmlNode} Its parent.
*/
let getParentInf = function(inf: MmlNode): MmlNode {
while (inf && getProperty(inf, 'inference') == null) {
inf = inf.parent as MmlNode;
}
return inf;
};
// Computes bbox spaces
//
//
/**
* Computes spacing left or right of an inference rule. In the case of
* right: right space + right label
* left: left space + left label
* @param {MmlNode} inf The overall proof tree.
* @param {MmlNode} rule The particular inference rule.
* @param {boolean = false} right True for right, o/w left.
* @return {number} The spacing next to the rule.
*/
let getSpaces = function(inf: MmlNode, rule: MmlNode, right: boolean = false): number {
let result = 0;
if (inf === rule) {
return result;
}
if (inf !== rule.parent) {
let children = inf.childNodes as MmlNode[];
let index = right ? children.length - 1 : 0;
if (NodeUtil.isType(children[index], 'mspace')) {
result += getBBox(children[index]);
}
inf = rule.parent;
}
if (inf === rule) {
return result;
}
let children = inf.childNodes as MmlNode[];
let index = right ? children.length - 1 : 0;
if (children[index] !== rule) {
result += getBBox(children[index]);
}
return result;
};
// - Get rule T from Wrapper W.
// - Get conclusion C in T.
// - w: Preceding/following space/label.
// - (x - y)/2: Distance from left boundary to middle of C.
/**
* Computes an space adjustment value to move the inference rule.
* @param {MmlNode} inf The inference rule.
* @param {boolean = false} right True if adjustments are on the right.
* @return {number} The adjustment value.
*/
let adjustValue = function(inf: MmlNode, right: boolean = false): number {
let rule = getRule(inf);
let conc = getConclusion(rule, getProperty(rule, 'inferenceRule') as string);
// TODO: Here we have to improve sequent adjustment!
let w = getSpaces(inf, rule, right);
let x = getBBox(rule);
let y = getBBox(conc);
return w + ((x - y) / 2);
};
/**
* Adds (positive or negative) space in the column containing the inference rule.
* @param {ParseOptions} config The parser configuration.
* @param {MmlNode} inf The inference rule to place.
* @param {number} space The space to be added.
* @param {boolean = false} right True if adjustment is on the right.
*/
let addSpace = function(config: ParseOptions, inf: MmlNode,
space: number, right: boolean = false) {
if (getProperty(inf, 'inferenceRule') ||
getProperty(inf, 'labelledRule')) {
const mrow = config.nodeFactory.create('node', 'mrow');
inf.parent.replaceChild(mrow, inf);
mrow.setChildren([inf]);
moveProperties(inf, mrow);
inf = mrow;
}
// TODO: Simplify below as we now have a definite mrow.
const index = right ? inf.childNodes.length - 1 : 0;
let mspace = inf.childNodes[index] as MmlNode;
if (NodeUtil.isType(mspace, 'mspace')) {
NodeUtil.setAttribute(
mspace, 'width',
ParseUtil.Em(ParseUtil.dimen2em(
NodeUtil.getAttribute(mspace, 'width') as string) + space));
return;
}
mspace = config.nodeFactory.create('node', 'mspace', [],
{width: ParseUtil.Em(space)});
if (right) {
inf.appendChild(mspace);
return;
}
mspace.parent = inf;
inf.childNodes.unshift(mspace);
};
/**
* Propagates properties up the tree.
* @param {MmlNode} src The source node.
* @param {MmlNode} dest The destination node.
*/
let moveProperties = function(src: MmlNode, dest: MmlNode) {
let props = ['inference', 'proof', 'maxAdjust', 'labelledRule'];
props.forEach(x => {
let value = getProperty(src, x);
if (value != null) {
setProperty(dest, x, value);
removeProperty(src, x);
}
});
};
/********************************
* The following methods deal with sequents. There are still issues with the
* spatial layout, though.
*/
// Sequents look like this: table row 3 cells
// The table has the 'sequent' property.
// The row is the node that is actually saved in the config object.
/**
* Method to adjust sequent positioning after the tree is computed.
* @param {ParseOptions} config Parser configuration options.
*/
let adjustSequents = function(config: ParseOptions) {
let sequents = config.nodeLists['sequent'];
if (!sequents) {
return;
}
for (let i = sequents.length - 1, seq; seq = sequents[i]; i--) {
if (getProperty(seq, 'sequentProcessed')) {
removeProperty(seq, 'sequentProcessed');
continue;
}
let collect = [];
let inf = getParentInf(seq);
if (getProperty(inf, 'inference') !== 1) {
continue;
}
collect.push(seq);
while (getProperty(inf, 'inference') === 1) {
// In case we have a table with a label.
inf = getRule(inf);
let premise = firstPremise(getPremises(inf, getProperty(inf, 'inferenceRule') as string));
let sequent = (getProperty(premise, 'inferenceRule')) ?
// If the first premise is an inference rule, check the conclusions for a sequent.
getConclusion(premise, getProperty(premise, 'inferenceRule') as string) :
// Otherwise it is a hyp and we have to check the formula itself.
premise;
if (getProperty(sequent, 'sequent')) {
seq = sequent.childNodes[0] as MmlNode;
collect.push(seq);
setProperty(seq, 'sequentProcessed', true);
}
inf = premise;
}
adjustSequentPairwise(config, collect);
}
};
/**
* Add spaces to the sequents where necessary.
* @param {ParseOptions} config Parser configuration options.
* @param {MmlNode} sequent The sequent inference rule.
* @param {number} position Position of formula to adjust (0 or 2).
* @param {string} direction Left or right of the turnstyle.
* @param {number} width The space to add to the formulas.
*/
const addSequentSpace = function(config: ParseOptions, sequent: MmlNode,
position: number, direction: string, width: number) {
let mspace = config.nodeFactory.create('node', 'mspace', [],
{width: ParseUtil.Em(width)});
if (direction === 'left') {
let row = sequent.childNodes[position].childNodes[0] as MmlNode;
mspace.parent = row;
row.childNodes.unshift(mspace);
} else {
sequent.childNodes[position].appendChild(mspace);
}
setProperty(sequent.parent, 'sequentAdjust_' + direction, width);
};
/**
* Adjusts the sequent positioning for a list of inference rules by pairwise
* adjusting the width of formulas in sequents. I.e.,
* A,B |- C
* ------------
* A |- B,C
*
* will be adjusted to
*
* A, B |- C
* ----------------
* A |- B,C
*
* @param {ParseOptions} config Parser configuration options.
* @param {MmlNode[]} sequents The list of sequents.
*/
const adjustSequentPairwise = function(config: ParseOptions, sequents: MmlNode[]) {
let top = sequents.pop();
while (sequents.length) {
let bottom = sequents.pop();
let [left, right] = compareSequents(top, bottom);
if (getProperty(top.parent, 'axiom')) {
addSequentSpace(config, left < 0 ? top : bottom, 0, 'left', Math.abs(left));
addSequentSpace(config, right < 0 ? top : bottom, 2, 'right', Math.abs(right));
}
top = bottom;
}
};
/**
* Compares the top and bottom sequent of a inference rule
* Top: A |- B
* ----------
* Bottom: C |- D
*
* @param {MmlNode} top Top sequent.
* @param {MmlNode} bottom Bottom sequent.
* @return {[number, number]} The delta for left and right side of the sequents.
*/
const compareSequents = function(top: MmlNode, bottom: MmlNode): [number, number] {
const tr = getBBox(top.childNodes[2] as MmlNode);
const br = getBBox(bottom.childNodes[2] as MmlNode);
const tl = getBBox(top.childNodes[0] as MmlNode);
const bl = getBBox(bottom.childNodes[0] as MmlNode);
// Deltas
const dl = tl - bl;
const dr = tr - br;
return [dl, dr];
};
// For every inference rule we adjust the width of ruler by subtracting and
// adding suitable spaces around the rule. The algorithm in detail.
//
// Notions that we need:
//
//
// * Inference: The inference consisting either of an inference rule or a
// structure containing the rule plus 0 - 2 labels and spacing
// elements. s l{0,1} t r{0,1} s', m,n \in IN_0
//
// Technically this is realised as nested rows, if the spaces
// and/or labels exist:
// mr s mr l t r /mr s' /mr
//
// * InferenceRule: The rule without the labels and spacing.
//
// * Conclusion: The element forming the conclusion of the rule. In
// downwards inferences this is the final row of the table.
//
// * Premises: The premises of the rule. In downwards inferences this is the
// first row of the rule. Note that this is a rule itself,
// with one column for each premise and an empty column
// inbetween.
//
// * |x|: Width of bounding box of element x.
//
// Left adjustment:
//
// * For the given inference I:
// + compute rule R of I
// + compute premises P of I
// + compute premise P_f, P_l as first and last premise of I
//
// * If P_f is an inference rule:
// + compute adjust value a_f for wrapper W_f of P_f
// + add -a_f space to wrapper W_f
// + add a_f space to wrapper W
//
// * If P_l is an inference rule:
// + compute adjust value a_l for wrapper W_l of P_l
// + if I has (right) label L: a_l = a_l + |L|
// + add -a_l space to P_l
// + a_l = max(a_l, A_I), where A_I is saved ajust value in the
// "maxAdjust" attribute of I.
//
// + Case I is proof: Add a_l space to inf. (Correct after proof.)
// + Case I has sibling: Add a_l space to sibling. (Correct after column.)
// + Otherwise: Propagate a_l by
// ++ find direct parent infererence rule I'
// ++ Set A_{I'} = a_l.
//
/**
* Implements the above algorithm.
* @param {FilterData} arg The parser configuration and mathitem to filter.
*/
export let balanceRules = function(arg: FilterData) {
item = new arg.document.options.MathItem('', null, arg.math.display);
let config = arg.data;
adjustSequents(config);
let inferences = config.nodeLists['inference'] || [];
for (let inf of inferences) {
let isProof = getProperty(inf, 'proof');
// This currently only works with downwards rules.
let rule = getRule(inf);
let premises = getPremises(rule, getProperty(rule, 'inferenceRule') as string);
let premiseF = firstPremise(premises);
if (getProperty(premiseF, 'inference')) {
let adjust = adjustValue(premiseF);
if (adjust) {
addSpace(config, premiseF, -adjust);
let w = getSpaces(inf, rule, false);
addSpace(config, inf, adjust - w);
}
}
// Right adjust:
let premiseL = lastPremise(premises);
if (getProperty(premiseL, 'inference') == null) {
continue;
}
let adjust = adjustValue(premiseL, true);
addSpace(config, premiseL, -adjust, true);
let w = getSpaces(inf, rule, true);
let maxAdjust = getProperty(inf, 'maxAdjust') as number;
if (maxAdjust != null) {
adjust = Math.max(adjust, maxAdjust);
}
let column: MmlNode;
if (isProof || !(column = getColumn(inf))) {
// After the tree we add a space with the accumulated max value.
// If the element is not in a column, we know we have some noise and the
// proof is an mrow around the final inference.
addSpace(config,
// in case the rule has been moved into an mrow in Left Adjust.
getProperty(inf, 'proof') ? inf : inf.parent, adjust - w, true);
continue;
}
let sibling = nextSibling(column);
if (sibling) {
// If there is a next column, it is the empty one and we make it wider by
// the accumulated max value.
const pos = config.nodeFactory.create('node', 'mspace', [],
{width: adjust - w + 'em'});
sibling.appendChild(pos);
inf.removeProperty('maxAdjust');
continue;
}
let parentRule = getParentInf(column);
if (!parentRule) {
continue;
}
// We are currently in rightmost inference, so we propagate the max
// correction value up in the tree.
adjust = getProperty(parentRule, 'maxAdjust') ?
Math.max(getProperty(parentRule, 'maxAdjust') as number, adjust) : adjust;
setProperty(parentRule, 'maxAdjust', adjust);
}
};
/**
* Facilities for semantically relevant properties. These are used by SRE and
* are always prefixed with bspr_.
*/
let property_prefix = 'bspr_';
let blacklistedProperties = {
[property_prefix + 'maxAdjust']: true
};
/**
* Sets a bussproofs property used for postprocessing and to convey
* semantics. Uses the bspr prefix.
* @param {MmlNode} node The node.
* @param {string} property The property to set.
* @param {Property} value Its value.
*/
export let setProperty = function(node: MmlNode, property: string, value: Property) {
NodeUtil.setProperty(node, property_prefix + property, value);
};
/**
* Gets a bussproofs property.
* @param {MmlNode} node The node.
* @param {string} property The property to retrieve.
* @return {Property} The property object.
*/
export let getProperty = function(node: MmlNode, property: string): Property {
return NodeUtil.getProperty(node, property_prefix + property);
};
/**
* Removes a bussproofs property.
* @param {MmlNode} node
* @param {string} property
*/
export let removeProperty = function(node: MmlNode, property: string) {
node.removeProperty(property_prefix + property);
};
/**
* Postprocessor that adds properties as attributes to the nodes, unless they
* are blacklisted.
* @param {FilterData} arg The object to post-process.
*/
export let makeBsprAttributes = function(arg: FilterData) {
arg.data.root.walkTree((mml: MmlNode, _data?: any) => {
let attr: string[] = [];
mml.getPropertyNames().forEach(x => {
if (!blacklistedProperties[x] && x.match(RegExp('^' + property_prefix))) {
attr.push(x + ':' + mml.getProperty(x));
}
});
if (attr.length) {
NodeUtil.setAttribute(mml, 'semantics', attr.join(';'));
}
});
};
/**
* Preprocessor that sets the document and jax for bounding box computations
* @param {FilterData} arg The object to pre-process.
*/
export let saveDocument = function (arg: FilterData) {
doc = arg.document;
if (!('getBBox' in doc.outputJax)) {
throw Error('The bussproofs extension requires an output jax with a getBBox() method');
}
};
/**
* Clear the document when we are done
* @param {FilterData} arg The object to pre-process.
*/
export let clearDocument = function (_arg: FilterData) {
doc = null;
};

View File

@@ -0,0 +1,87 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Configuration file for the cancel package.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {Configuration} from '../Configuration.js';
import TexParser from '../TexParser.js';
import {TexConstant} from '../TexConstants.js';
import {CommandMap} from '../SymbolMap.js';
import {ParseMethod} from '../Types.js';
import ParseUtil from '../ParseUtil.js';
import {ENCLOSE_OPTIONS} from '../enclose/EncloseConfiguration.js';
// Namespace
export let CancelMethods: Record<string, ParseMethod> = {};
/**
* Parse function for cancel macros of the form \(b|x)?cancel[attributes]{math}
* @param {TexParser} parser The current tex parser.
* @param {string} name The name of the calling macro.
* @param {string} notation The type of cancel notation to use.
*/
CancelMethods.Cancel = function(parser: TexParser, name: string, notation: string) {
const attr = parser.GetBrackets(name, '');
const math = parser.ParseArg(name);
const def = ParseUtil.keyvalOptions(attr, ENCLOSE_OPTIONS);
def['notation'] = notation;
parser.Push(parser.create('node', 'menclose', [math], def));
};
/**
* Parse function implementing \cancelto{value}[attributes]{math}
* @param {TexParser} parser The current tex parser.
* @param {string} name The name of the calling macro.
*/
CancelMethods.CancelTo = function(parser: TexParser, name: string) {
const attr = parser.GetBrackets(name, '');
let value = parser.ParseArg(name);
const math = parser.ParseArg(name);
const def = ParseUtil.keyvalOptions(attr, ENCLOSE_OPTIONS);
def ['notation'] = [TexConstant.Notation.UPDIAGONALSTRIKE,
TexConstant.Notation.UPDIAGONALARROW,
TexConstant.Notation.NORTHEASTARROW].join(' ');
value = parser.create('node', 'mpadded', [value],
{depth: '-.1em', height: '+.1em', voffset: '.1em'});
parser.Push(parser.create('node', 'msup',
[parser.create('node', 'menclose', [math], def), value]));
};
new CommandMap('cancel', {
cancel: ['Cancel', TexConstant.Notation.UPDIAGONALSTRIKE],
bcancel: ['Cancel', TexConstant.Notation.DOWNDIAGONALSTRIKE],
xcancel: ['Cancel', TexConstant.Notation.UPDIAGONALSTRIKE + ' ' +
TexConstant.Notation.DOWNDIAGONALSTRIKE],
cancelto: 'CancelTo'
}, CancelMethods);
export const CancelConfiguration = Configuration.create(
'cancel', {handler: {macro: ['cancel']}}
);

View File

@@ -0,0 +1,212 @@
import {Configuration} from '../Configuration.js';
import {EnvironmentMap, MacroMap} from '../SymbolMap.js';
import ParseUtil from '../ParseUtil.js';
import BaseMethods from '../base/BaseMethods.js';
import TexParser from '../TexParser.js';
import TexError from '../TexError.js';
import {BeginItem, EqnArrayItem} from '../base/BaseItems.js';
import {AmsTags} from '../ams/AmsConfiguration.js';
import {StackItem, CheckType} from '../StackItem.js';
import {MmlMtable} from '../../../core/MmlTree/MmlNodes/mtable.js';
import {EmpheqUtil} from '../empheq/EmpheqUtil.js';
/**
* The StackItem for the numcases environment.
*/
export class CasesBeginItem extends BeginItem {
/**
* @override
*/
get kind() {
return 'cases-begin';
}
/**
* @override
*/
public checkItem(item: StackItem) {
if (item.isKind('end') && item.getName() === this.getName()) {
if (this.getProperty('end')) {
this.setProperty('end', false);
return [[], true] as CheckType;
}
}
return super.checkItem(item);
}
}
/**
* A tagging class for the subnumcases environment.
*/
export class CasesTags extends AmsTags {
/**
* The counter for the subnumber.
*/
protected subcounter = 0;
/**
* @override
*/
public start(env: string, taggable: boolean, defaultTags: boolean) {
this.subcounter = 0;
super.start(env, taggable, defaultTags);
}
/**
* @override
*/
public autoTag() {
if (this.currentTag.tag != null) return;
if (this.currentTag.env === 'subnumcases') {
if (this.subcounter === 0) this.counter++;
this.subcounter++;
this.tag(this.formatNumber(this.counter, this.subcounter), false);
} else {
if (this.subcounter === 0 || this.currentTag.env !== 'numcases-left') this.counter++;
this.tag(this.formatNumber(this.counter), false);
}
}
/**
* @override
*/
public formatNumber(n: number, m: number = null) {
return n.toString() + (m === null ? '' : String.fromCharCode(0x60 + m));
}
}
export const CasesMethods = {
/**
* Implements the numcases environment.
*
* @param {TexParser} texparser The active tex parser.
* @param {CasesBeginItem} begin The environment begin item.
*/
NumCases(parser: TexParser, begin: CasesBeginItem) {
if (parser.stack.env.closing === begin.getName()) {
delete parser.stack.env.closing;
parser.Push(parser.itemFactory.create('end').setProperty('name', begin.getName())); // finish eqnarray
const cases = parser.stack.Top();
const table = cases.Last as MmlMtable;
const original = ParseUtil.copyNode(table, parser) as MmlMtable;
const left = cases.getProperty('left');
EmpheqUtil.left(table, original, left + '\\empheqlbrace\\,', parser, 'numcases-left');
parser.Push(parser.itemFactory.create('end').setProperty('name', begin.getName()));
return null;
} else {
const left = parser.GetArgument('\\begin{' + begin.getName() + '}');
begin.setProperty('left', left);
const array = BaseMethods.EqnArray(parser, begin, true, true, 'll', ) as EqnArrayItem;
array.arraydef.displaystyle = false;
array.arraydef.rowspacing = '.2em';
array.setProperty('numCases', true);
parser.Push(begin);
return array;
}
},
/**
* Replacement for & in cases environment.
*/
Entry(parser: TexParser, name: string) {
if (!parser.stack.Top().getProperty('numCases')) {
return BaseMethods.Entry(parser, name);
}
parser.Push(parser.itemFactory.create('cell').setProperties({isEntry: true, name: name}));
//
// Make second column be in \text{...}
//
const tex = parser.string;
let braces = 0, i = parser.i, m = tex.length;
//
// Look through the string character by character...
//
while (i < m) {
const c = tex.charAt(i);
if (c === '{') {
//
// Increase the nested brace count and go on
//
braces++;
i++;
} else if (c === '}') {
//
// If there are too many close braces, just end (we will get an
// error message later when the rest of the string is parsed)
// Otherwise
// decrease the nested brace count,
// go on to the next character.
//
if (braces === 0) {
break;
} else {
braces--;
i++;
}
} else if (c === '&' && braces === 0) {
//
// Extra alignment tabs are not allowed in cases
//
throw new TexError('ExtraCasesAlignTab', 'Extra alignment tab in text for numcase environment');
} else if (c === '\\' && braces === 0) {
//
// If the macro is \cr or \\, end the search, otherwise skip the macro
// (multi-letter names don't matter, as we will skip the rest of the
// characters in the main loop)
//
const cs = (tex.slice(i + 1).match(/^[a-z]+|./i) || [])[0];
if (cs === '\\' || cs === 'cr' || cs === 'end' || cs === 'label') {
break;
} else {
i += cs.length;
}
} else {
//
// Go on to the next character
//
i++;
}
}
//
// Process the second column as text and continue parsing from there,
//
const text = tex.substr(parser.i, i - parser.i).replace(/^\s*/, '');
parser.PushAll(ParseUtil.internalMath(parser, text, 0));
parser.i = i;
}
};
/**
* The environments for this package
*/
new EnvironmentMap('cases-env', EmpheqUtil.environment, {
numcases: ['NumCases', 'cases'],
subnumcases: ['NumCases', 'cases']
}, CasesMethods);
/**
* The macros for this package
*/
new MacroMap('cases-macros', {
'&': 'Entry'
}, CasesMethods);
//
// Define the package for our new environment
//
export const CasesConfiguration = Configuration.create('cases', {
handler: {
environment: ['cases-env'],
character: ['cases-macros']
},
items: {
[CasesBeginItem.prototype.kind]: CasesBeginItem
},
tags: {'cases': CasesTags}
});

View File

@@ -0,0 +1,81 @@
/*************************************************************
*
* Copyright (c) 2021-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Configuration file for the centernot package.
*
* @author dpvc@mathjax.org (Davide P. Cervone)
*/
import {Configuration} from '../Configuration.js';
import ParseOptions from '../ParseOptions.js';
import TexParser from '../TexParser.js';
import NodeUtil from '../NodeUtil.js';
import {CommandMap} from '../SymbolMap.js';
import {MmlNode} from '../../../core/MmlTree/MmlNode.js';
import BaseMethods from '../base/BaseMethods.js';
new CommandMap('centernot', {
centerOver: 'CenterOver',
centernot: ['Macro', '\\centerOver{#1}{{\u29F8}}', 1]
}, {
/**
* Implements \centerOver{base}{symbol}
*
* @param {TexParser} parser The active tex parser.
* @param {string} name The name of the macro being processed.
*/
CenterOver(parser: TexParser, name: string) {
const arg = '{' + parser.GetArgument(name) + '}';
const over = parser.ParseArg(name);
const base = new TexParser(arg, parser.stack.env, parser.configuration).mml();
let mml = parser.create('node', 'TeXAtom', [
new TexParser(arg, parser.stack.env, parser.configuration).mml(),
parser.create('node', 'mpadded', [
parser.create('node', 'mpadded', [over], {width: 0, lspace: '-.5width'}),
parser.create('node', 'mphantom', [base])
], {width: 0, lspace: '-.5width'})
]);
parser.configuration.addNode('centerOver', base);
parser.Push(mml);
},
Macro: BaseMethods.Macro
});
/**
* Filter to copy texClass to the surrounding TeXAtom so that the negated
* item has the same class of the base.
*
* @param {ParseOptions} data The active tex parser.
*/
export function filterCenterOver({data}: {data: ParseOptions}) {
for (const base of data.getList('centerOver')) {
const texClass = NodeUtil.getTexClass(base.childNodes[0].childNodes[0] as MmlNode);
if (texClass !== null) {
NodeUtil.setProperties(base.parent.parent.parent.parent.parent.parent, {texClass});
}
}
}
export const CenternotConfiguration = Configuration.create(
'centernot', {
handler: {macro: ['centernot']},
postprocessors: [filterCenterOver]
}
);

View File

@@ -0,0 +1,68 @@
/*************************************************************
*
* Copyright (c) 2018-2022 Omar Al-Ithawi and The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Configuration file for the color package.
*
* @author i@omardo.com (Omar Al-Ithawi)
*/
import {CommandMap} from '../SymbolMap.js';
import {Configuration, ParserConfiguration} from '../Configuration.js';
import {ColorMethods} from './ColorMethods.js';
import {ColorModel} from './ColorUtil.js';
import {TeX} from '../../tex.js';
/**
* The color macros
*/
new CommandMap('color', {
color: 'Color',
textcolor: 'TextColor',
definecolor: 'DefineColor',
colorbox: 'ColorBox',
fcolorbox: 'FColorBox'
}, ColorMethods);
/**
* Config method for Color package.
*
* @param {Configuration} config The current configuration.
* @param {TeX} jax The TeX jax having that configuration
*/
const config = function(_config: ParserConfiguration, jax: TeX<any, any, any>) {
jax.parseOptions.packageData.set('color', {model: new ColorModel()});
};
/**
* The configuration for the color macros
*/
export const ColorConfiguration = Configuration.create(
'color', {
handler: {
macro: ['color'],
},
options: {
color: {
padding: '5px',
borderWidth: '2px'
}
},
config: config
}
);

View File

@@ -0,0 +1,93 @@
/*************************************************************
*
* Copyright (c) 2018-2022 Omar Al-Ithawi and The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Constants file for the color package.
*
* @author i@omardo.com (Omar Al-Ithawi)
*/
export const COLORS: Map<string, string> = new Map<string, string>([
['Apricot', '#FBB982'],
['Aquamarine', '#00B5BE'],
['Bittersweet', '#C04F17'],
['Black', '#221E1F'],
['Blue', '#2D2F92'],
['BlueGreen', '#00B3B8'],
['BlueViolet', '#473992'],
['BrickRed', '#B6321C'],
['Brown', '#792500'],
['BurntOrange', '#F7921D'],
['CadetBlue', '#74729A'],
['CarnationPink', '#F282B4'],
['Cerulean', '#00A2E3'],
['CornflowerBlue', '#41B0E4'],
['Cyan', '#00AEEF'],
['Dandelion', '#FDBC42'],
['DarkOrchid', '#A4538A'],
['Emerald', '#00A99D'],
['ForestGreen', '#009B55'],
['Fuchsia', '#8C368C'],
['Goldenrod', '#FFDF42'],
['Gray', '#949698'],
['Green', '#00A64F'],
['GreenYellow', '#DFE674'],
['JungleGreen', '#00A99A'],
['Lavender', '#F49EC4'],
['LimeGreen', '#8DC73E'],
['Magenta', '#EC008C'],
['Mahogany', '#A9341F'],
['Maroon', '#AF3235'],
['Melon', '#F89E7B'],
['MidnightBlue', '#006795'],
['Mulberry', '#A93C93'],
['NavyBlue', '#006EB8'],
['OliveGreen', '#3C8031'],
['Orange', '#F58137'],
['OrangeRed', '#ED135A'],
['Orchid', '#AF72B0'],
['Peach', '#F7965A'],
['Periwinkle', '#7977B8'],
['PineGreen', '#008B72'],
['Plum', '#92268F'],
['ProcessBlue', '#00B0F0'],
['Purple', '#99479B'],
['RawSienna', '#974006'],
['Red', '#ED1B23'],
['RedOrange', '#F26035'],
['RedViolet', '#A1246B'],
['Rhodamine', '#EF559F'],
['RoyalBlue', '#0071BC'],
['RoyalPurple', '#613F99'],
['RubineRed', '#ED017D'],
['Salmon', '#F69289'],
['SeaGreen', '#3FBC9D'],
['Sepia', '#671800'],
['SkyBlue', '#46C5DD'],
['SpringGreen', '#C6DC67'],
['Tan', '#DA9D76'],
['TealBlue', '#00AEB3'],
['Thistle', '#D883B7'],
['Turquoise', '#00B4CE'],
['Violet', '#58429B'],
['VioletRed', '#EF58A0'],
['White', '#FFFFFF'],
['WildStrawberry', '#EE2967'],
['Yellow', '#FFF200'],
['YellowGreen', '#98CC70'],
['YellowOrange', '#FAA21A'],
]);

View File

@@ -0,0 +1,156 @@
/*************************************************************
*
* Copyright (c) 2018-2022 Omar Al-Ithawi and The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Parse methods and helper functtions for the color package.
*
* @author i@omardo.com (Omar Al-Ithawi)
*/
import NodeUtil from '../NodeUtil.js';
import {ParseMethod} from '../Types.js';
import {PropertyList} from '../../../core/Tree/Node.js';
import ParseUtil from '../ParseUtil.js';
import TexParser from '../TexParser.js';
import {ColorModel} from './ColorUtil.js';
/**
* Build PropertyList from padding value.
*
* @param {string} colorPadding: Padding for \colorbox and \fcolorbox.
* @return {PropertyList} The padding properties.
*/
function padding(colorPadding: string): PropertyList {
const pad = `+${colorPadding}`;
const unit = colorPadding.replace(/^.*?([a-z]*)$/, '$1');
const pad2 = 2 * parseFloat(pad);
return {
width: `+${pad2}${unit}`,
height: pad,
depth: pad,
lspace: colorPadding,
};
}
export const ColorMethods: Record<string, ParseMethod> = {};
/**
* Override \color macro definition.
*
* @param {TexParser} parser The calling parser.
* @param {string} name The name of the control sequence.
*/
ColorMethods.Color = function (parser: TexParser, name: string) {
const model = parser.GetBrackets(name, '');
const colorDef = parser.GetArgument(name);
const colorModel: ColorModel = parser.configuration.packageData.get('color').model;
const color = colorModel.getColor(model, colorDef);
const style = parser.itemFactory.create('style')
.setProperties({styles: { mathcolor: color }});
parser.stack.env['color'] = color;
parser.Push(style);
};
/**
* Define the \textcolor macro.
*
* @param {TexParser} parser The calling parser.
* @param {string} name The name of the control sequence.
*/
ColorMethods.TextColor = function (parser: TexParser, name: string) {
const model = parser.GetBrackets(name, '');
const colorDef = parser.GetArgument(name);
const colorModel: ColorModel = parser.configuration.packageData.get('color').model;
const color = colorModel.getColor(model, colorDef);
const old = parser.stack.env['color'];
parser.stack.env['color'] = color;
const math = parser.ParseArg(name);
if (old) {
parser.stack.env['color'] = old;
} else {
delete parser.stack.env['color'];
}
const node = parser.create('node', 'mstyle', [math], {mathcolor: color});
parser.Push(node);
};
/**
* Define the \definecolor macro.
*
* @param {TexParser} parser The calling parser.
* @param {string} name The name of the control sequence.
*/
ColorMethods.DefineColor = function (parser: TexParser, name: string) {
const cname = parser.GetArgument(name);
const model = parser.GetArgument(name);
const def = parser.GetArgument(name);
const colorModel: ColorModel = parser.configuration.packageData.get('color').model;
colorModel.defineColor(model, cname, def);
};
/**
* Produce a text box with a colored background: `\colorbox`.
*
* @param {TexParser} parser The calling parser.
* @param {string} name The name of the control sequence.
*/
ColorMethods.ColorBox = function (parser: TexParser, name: string) {
const cname = parser.GetArgument(name);
const math = ParseUtil.internalMath(parser, parser.GetArgument(name));
const colorModel: ColorModel = parser.configuration.packageData.get('color').model;
const node = parser.create('node', 'mpadded', math, {
mathbackground: colorModel.getColor('named', cname)
});
NodeUtil.setProperties(node, padding(parser.options.color.padding));
parser.Push(node);
};
/**
* Produce a framed text box with a colored background: `\fcolorbox`.
*
* @param {TexParser} parser The calling parser.
* @param {string} name The name of the control sequence.
*/
ColorMethods.FColorBox = function (parser: TexParser, name: string) {
const fname = parser.GetArgument(name);
const cname = parser.GetArgument(name);
const math = ParseUtil.internalMath(parser, parser.GetArgument(name));
const options = parser.options.color;
const colorModel: ColorModel = parser.configuration.packageData.get('color').model;
const node = parser.create('node', 'mpadded', math, {
mathbackground: colorModel.getColor('named', cname),
style: `border: ${options.borderWidth} solid ${colorModel.getColor('named', fname)}`
});
NodeUtil.setProperties(node, padding(options.padding));
parser.Push(node);
};

View File

@@ -0,0 +1,218 @@
/*************************************************************
*
* Copyright (c) 2018-2022 Omar Al-Ithawi and The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Utility functions and classes for the color package.
*
* @author i@omardo.com (Omar Al-Ithawi)
*/
import TexError from '../TexError.js';
import {COLORS} from './ColorConstants.js';
type ColorModelProcessor = (def: string) => string;
const ColorModelProcessors: Map<string, ColorModelProcessor> = new Map<string, ColorModelProcessor>();
export class ColorModel {
/**
* User defined colors.
*
* This variable is local to the parser, so two parsers in the same
* JavaScript thread can have two different sets of user-defined colors.
*/
private userColors: Map<string, string> = new Map<string, string>();
/**
* Converts a color model from string representation to its CSS format `#44ff00`
*
* @param {string} model The coloring model type: `rgb` `RGB` or `gray`.
* @param {string} def The color definition: `0.5,0,1`, `128,0,255`, `0.5`.
* @return {string} The color definition in CSS format e.g. `#44ff00`.
*/
private normalizeColor(model: string, def: string): string {
if (!model || model === 'named') {
// Allow to define colors directly by using the CSS format e.g. `#888`
return def;
}
if (ColorModelProcessors.has(model)) {
const modelProcessor = ColorModelProcessors.get(model);
return modelProcessor(def);
}
throw new TexError('UndefinedColorModel', 'Color model \'%1\' not defined', model);
}
/**
* Look up a color based on its model and definition.
*
* @param {string} model The coloring model type: `named`, `rgb` `RGB` or `gray`.
* @param {string} def The color definition: `red, `0.5,0,1`, `128,0,255`, `0.5`.
* @return {string} The color definition in CSS format e.g. `#44ff00`.
*/
public getColor(model: string, def: string): string {
if (!model || model === 'named') {
return this.getColorByName(def);
}
return this.normalizeColor(model, def);
}
/**
* Get a named color.
*
* @param {string} name The color name e.g. `darkblue`.
* @return {string} The color definition in CSS format e.g. `#44ff00`.
*
* To retain backward compatilbity with MathJax v2 this method returns
* unknown as-is, this is useful for both passing through CSS format colors like `#ff0`,
* or even standard CSS color names that this plugin is unaware of.
*
* In TeX format, this would help to let `\textcolor{#f80}{\text{Orange}}` show an
* orange word.
*/
private getColorByName(name: string): string {
if (this.userColors.has(name)) {
return this.userColors.get(name);
}
if (COLORS.has(name)) {
return COLORS.get(name);
}
// Pass the color name as-is to CSS
return name;
}
/**
* Create a new user-defined color.
*
* This color is local to the parser, so another MathJax parser won't be poluted.
*
* @param {string} model The coloring model type: e.g. `rgb`, `RGB` or `gray`.
* @param {string} name The color name: `darkblue`.
* @param {string} def The color definition in the color model format: `128,0,255`.
*/
public defineColor(model: string, name: string, def: string) {
const normalized = this.normalizeColor(model, def);
this.userColors.set(name, normalized);
}
}
/**
* Get an rgb color.
*
* @param {OptionList} parserOptions The parser options object.
* @param {string} rgb The color definition in rgb: `0.5,0,1`.
* @return {string} The color definition in CSS format e.g. `#44ff00`.
*/
ColorModelProcessors.set('rgb', function (rgb: string): string {
const rgbParts: string[] = rgb.trim().split(/\s*,\s*/);
let RGB: string = '#';
if (rgbParts.length !== 3) {
throw new TexError('ModelArg1', 'Color values for the %1 model require 3 numbers', 'rgb');
}
for (const rgbPart of rgbParts) {
if (!rgbPart.match(/^(\d+(\.\d*)?|\.\d+)$/)) {
throw new TexError('InvalidDecimalNumber', 'Invalid decimal number');
}
const n = parseFloat(rgbPart);
if (n < 0 || n > 1) {
throw new TexError('ModelArg2',
'Color values for the %1 model must be between %2 and %3',
'rgb', '0', '1');
}
let pn = Math.floor(n * 255).toString(16);
if (pn.length < 2) {
pn = '0' + pn;
}
RGB += pn;
}
return RGB;
});
/**
* Get an RGB color.
*
* @param {OptionList} parserOptions The parser options object.
* @param {string} rgb The color definition in RGB: `128,0,255`.
* @return {string} The color definition in CSS format e.g. `#44ff00`.
*/
ColorModelProcessors.set('RGB', function (rgb: string): string {
const rgbParts: string[] = rgb.trim().split(/\s*,\s*/);
let RGB = '#';
if (rgbParts.length !== 3) {
throw new TexError('ModelArg1', 'Color values for the %1 model require 3 numbers', 'RGB');
}
for (const rgbPart of rgbParts) {
if (!rgbPart.match(/^\d+$/)) {
throw new TexError('InvalidNumber', 'Invalid number');
}
const n = parseInt(rgbPart);
if (n > 255) {
throw new TexError('ModelArg2',
'Color values for the %1 model must be between %2 and %3',
'RGB', '0', '255');
}
let pn = n.toString(16);
if (pn.length < 2) {
pn = '0' + pn;
}
RGB += pn;
}
return RGB;
});
/**
* Get a gray-scale value.
*
* @param {OptionList} parserOptions The parser options object.
* @param {string} gray The color definition in RGB: `0.5`.
* @return {string} The color definition in CSS format e.g. `#808080`.
*/
ColorModelProcessors.set('gray', function (gray: string): string {
if (!gray.match(/^\s*(\d+(\.\d*)?|\.\d+)\s*$/)) {
throw new TexError('InvalidDecimalNumber', 'Invalid decimal number');
}
const n: number = parseFloat(gray);
if (n < 0 || n > 1) {
throw new TexError('ModelArg2',
'Color values for the %1 model must be between %2 and %3',
'gray', '0', '1');
}
let pn = Math.floor(n * 255).toString(16);
if (pn.length < 2) {
pn = '0' + pn;
}
return `#${pn}${pn}${pn}`;
});

View File

@@ -0,0 +1,177 @@
/*************************************************************
*
* Copyright (c) 2021-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Configuration file for the colortbl package.
*
* @author dpvc@mathjax.org (Davide P. Cervone)
*/
import {ArrayItem} from '../base/BaseItems.js';
import {Configuration, ParserConfiguration, ConfigurationHandler} from '../Configuration.js';
import {CommandMap} from '../SymbolMap.js';
import TexParser from '../TexParser.js';
import TexError from '../TexError.js';
import {MmlNode} from '../../../core/MmlTree/MmlNode.js';
import {TeX} from '../../tex.js';
/**
* Information about table colors.
*/
export interface ColorData {
cell: string;
row: string;
col: string[];
}
//
// Sublcass the ArrayItem to handle colored entries
//
export class ColorArrayItem extends ArrayItem {
/**
* Store current color for cell, row, and columns.
*/
public color: ColorData = {
cell: '',
row: '',
col: []
};
/**
* True if any cell is colored (we will make sure the edge cells are full sized).
*/
public hasColor: boolean = false;
/**
* @override
*/
public EndEntry() {
super.EndEntry();
const cell = this.row[this.row.length - 1];
const color = this.color.cell || this.color.row || this.color.col[this.row.length - 1];
if (color) {
cell.attributes.set('mathbackground', color);
this.color.cell = '';
this.hasColor = true;
}
}
/**
* @override
*/
public EndRow() {
super.EndRow();
this.color.row = '';
}
/**
* @override
*/
public createMml() {
//
// If there is any color in the array, give it an empty frame,
// if there isn't one already. This will make sure the color
// in edge cells extends past their contents.
//
const mml = super.createMml();
let table = (mml.isKind('mrow') ? mml.childNodes[1] : mml) as MmlNode;
if (table.isKind('menclose')) {
table = table.childNodes[0].childNodes[0] as MmlNode;
}
if (this.hasColor && table.attributes.get('frame') === 'none') {
table.attributes.set('frame', '');
}
return mml;
}
}
//
// Define macros for table coloring.
//
new CommandMap('colortbl', {
cellcolor: ['TableColor', 'cell'],
rowcolor: ['TableColor', 'row'],
columncolor: ['TableColor', 'col']
}, {
/**
* Add color to a column, row, or cell.
*
* @param {TexParser} parser The active TeX parser
* @param {string} name The name of the macro that is being processed
* @param {keyof ColorData} type The type (col, row, cell) of color being added
*/
TableColor(parser: TexParser, name: string, type: keyof ColorData) {
const lookup = parser.configuration.packageData.get('color').model; // use the color extension's color model
const model = parser.GetBrackets(name, '');
const color = lookup.getColor(model, parser.GetArgument(name));
//
// Check that we are in a colorable array.
//
const top = parser.stack.Top() as ColorArrayItem;
if (!(top instanceof ColorArrayItem)) {
throw new TexError('UnsupportedTableColor', 'Unsupported use of %1', parser.currentCS);
}
//
// Check the position of the macro and save the color.
//
if (type === 'col') {
if (top.table.length) {
throw new TexError('ColumnColorNotTop', '%1 must be in the top row', name);
}
top.color.col[top.row.length] = color;
//
// Ignore the left and right overlap options.
//
if (parser.GetBrackets(name, '')) {
parser.GetBrackets(name, '');
}
} else {
top.color[type] = color;
if (type === 'row' && (top.Size() || top.row.length)) {
throw new TexError('RowColorNotFirst', '%1 must be at the beginning of a row', name);
}
}
}
});
/**
* The configuration function for colortbl.
*
* @param {ParserConfiguration} config The configuration being used.
* @param {Tex} jax The TeX jax using this configuration.
*/
const config = function (config: ParserConfiguration, jax: TeX<any, any, any>) {
//
// Make sure color is configured. (It doesn't have to be included in tex.packages.)
//
if (!jax.parseOptions.packageData.has('color')) {
ConfigurationHandler.get('color').config(config, jax);
}
};
//
// Create the color-table configuration.
//
export const ColortblConfiguration = Configuration.create('colortbl', {
handler: {macro: ['colortbl']},
items: {'array': ColorArrayItem}, // overrides original array class
priority: 10, // make sure we are processed after the base package (to override its array)
config: [config, 10] // make sure we configure after the color package, if it is used.
});

View File

@@ -0,0 +1,64 @@
/*************************************************************
*
* Copyright (c) 2019-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Configuration file for the v2-compatible color package.
*
* @author dpvc@mathjax.org (Davide P. Cervone)
*/
import {CommandMap} from '../SymbolMap.js';
import {Configuration} from '../Configuration.js';
import {ParseMethod} from '../Types.js';
import TexParser from '../TexParser.js';
export const ColorV2Methods: Record<string, ParseMethod> = {
/**
* Implements the v2 color macro
*
* @param {TexParser} parser The calling parser.
* @param {string} name The macro name.
*/
Color(parser: TexParser, name: string) {
// @test Color Frac
const color = parser.GetArgument(name);
const old = parser.stack.env['color'];
parser.stack.env['color'] = color;
const math = parser.ParseArg(name);
if (old) {
parser.stack.env['color'] = old;
} else {
delete parser.stack.env['color'];
}
const node = parser.create('node', 'mstyle', [math], {mathcolor: color});
parser.Push(node);
}
};
/**
* The color macros
*/
new CommandMap('colorv2', {color: 'Color'}, ColorV2Methods);
/**
* The configuration for the color macros
*/
export const ColorConfiguration = Configuration.create(
'colorv2', {handler: {macro: ['colorv2']}}
);

View File

@@ -0,0 +1,119 @@
/*************************************************************
*
* Copyright (c) 2019-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Configuration file for the configmacros package.
*
* @author dpvc@mathjax.org (Davide P. Cervone)
*/
import {Configuration, ParserConfiguration} from '../Configuration.js';
import {expandable} from '../../../util/Options.js';
import {CommandMap, EnvironmentMap} from '../SymbolMap.js';
import ParseMethods from '../ParseMethods.js';
import {Macro} from '../Symbol.js';
import NewcommandMethods from '../newcommand/NewcommandMethods.js';
import {BeginEnvItem} from '../newcommand/NewcommandItems.js';
import {TeX} from '../../tex.js';
type TEX = TeX<any, any, any>;
/**
* The name to use for the macros map
*/
const MACROSMAP = 'configmacros-map';
/**
* The name to use for the environment map
*/
const ENVIRONMENTMAP = 'configmacros-env-map';
/**
* Create the command map for the macros
*
* @param {Configuration} config The configuration object for the input jax
*/
function configmacrosInit(config: ParserConfiguration) {
new CommandMap(MACROSMAP, {}, {});
new EnvironmentMap(ENVIRONMENTMAP, ParseMethods.environment, {}, {});
config.append(Configuration.local({
handler: {
macro: [MACROSMAP],
environment: [ENVIRONMENTMAP]
},
priority: 3
}));
}
/**
* Create the user-defined macros and environments from their options
*
* @param {Configuration} config The configuration object for the input jax
* @param {TeX} jax The TeX input jax
*/
function configmacrosConfig(_config: ParserConfiguration, jax: TEX) {
configMacros(jax);
configEnvironments(jax);
}
/**
* Create user-defined macros from the macros option
*
* @param {TeX} jax The TeX input jax
*/
function configMacros(jax: TEX) {
const handler = jax.parseOptions.handlers.retrieve(MACROSMAP) as CommandMap;
const macros = jax.parseOptions.options.macros;
for (const cs of Object.keys(macros)) {
const def = (typeof macros[cs] === 'string' ? [macros[cs]] : macros[cs]);
const macro = Array.isArray(def[2]) ?
new Macro(cs, NewcommandMethods.MacroWithTemplate, def.slice(0, 2).concat(def[2])) :
new Macro(cs, NewcommandMethods.Macro, def);
handler.add(cs, macro);
}
}
/**
* Create user-defined environments from the environments option
*
* @param {TeX} jax The TeX input jax
*/
function configEnvironments(jax: TEX) {
const handler = jax.parseOptions.handlers.retrieve(ENVIRONMENTMAP) as EnvironmentMap;
const environments = jax.parseOptions.options.environments;
for (const env of Object.keys(environments)) {
handler.add(env, new Macro(env, NewcommandMethods.BeginEnv, [true].concat(environments[env])));
}
}
/**
* The configuration object for configmacros
*/
export const ConfigMacrosConfiguration = Configuration.create(
'configmacros', {
init: configmacrosInit,
config: configmacrosConfig,
items: {
[BeginEnvItem.prototype.kind]: BeginEnvItem,
},
options: {
macros: expandable({}),
environments: expandable({})
}
}
);

View File

@@ -0,0 +1,180 @@
/*************************************************************
*
* Copyright (c) 2021-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Configuration file for the empheq package.
*
* @author dpvc@mathjax.org (Davide P. Cervone)
*/
import {Configuration} from '../Configuration.js';
import {CommandMap, EnvironmentMap} from '../SymbolMap.js';
import ParseUtil from '../ParseUtil.js';
import TexParser from '../TexParser.js';
import TexError from '../TexError.js';
import {BeginItem} from '../base/BaseItems.js';
import {StackItem} from '../StackItem.js';
import {EmpheqUtil} from './EmpheqUtil.js';
/**
* A StackItem for empheq environments.
*/
export class EmpheqBeginItem extends BeginItem {
/**
* @override
*/
public get kind() {
return 'empheq-begin';
}
/**
* @override
*/
public checkItem(item: StackItem) {
if (item.isKind('end') && item.getName() === this.getName()) {
this.setProperty('end', false);
}
return super.checkItem(item);
}
}
/**
* The methods that implement the empheq package.
*/
export const EmpheqMethods = {
/**
* Handle an empheq environment.
*
* @param {TexParser} parser The active tex parser.
* @param {EmpheqBeginItem} begin The begin item for this environment.
*/
Empheq(parser: TexParser, begin: EmpheqBeginItem) {
if (parser.stack.env.closing === begin.getName()) {
delete parser.stack.env.closing;
parser.Push(parser.itemFactory.create('end').setProperty('name', parser.stack.global.empheq));
parser.stack.global.empheq = '';
const empheq = parser.stack.Top() as EmpheqBeginItem;
EmpheqUtil.adjustTable(empheq, parser);
parser.Push(parser.itemFactory.create('end').setProperty('name', 'empheq'));
} else {
ParseUtil.checkEqnEnv(parser);
delete parser.stack.global.eqnenv;
const opts = parser.GetBrackets('\\begin{' + begin.getName() + '}') || '';
const [env, n] = (parser.GetArgument('\\begin{' + begin.getName() + '}') || '').split(/=/);
if (!EmpheqUtil.checkEnv(env)) {
throw new TexError('UnknownEnv', 'Unknown environment "%1"', env);
}
if (opts) {
begin.setProperties(EmpheqUtil.splitOptions(opts, {left: 1, right: 1}));
}
parser.stack.global.empheq = env;
parser.string = '\\begin{' + env + '}' + (n ? '{' + n + '}' : '') + parser.string.slice(parser.i);
parser.i = 0;
parser.Push(begin);
}
},
/**
* Create an <mo> with a given content
*
* @param {TexParser} parser The active tex parser.
* @param {string} name The name of the macro being processed.
* @param {string} c The character for the <mo>
*/
EmpheqMO(parser: TexParser, _name: string, c: string) {
parser.Push(parser.create('token', 'mo', {}, c));
},
/**
* Create a delimiter <mo> with a given character
*
* @param {TexParser} parser The active tex parser.
* @param {string} name The name of the macro being processed.
*/
EmpheqDelim(parser: TexParser, name: string) {
const c = parser.GetDelimiter(name);
parser.Push(parser.create('token', 'mo', {stretchy: true, symmetric: true}, c));
}
};
//
// Define an environment map to add the new empheq environment
//
new EnvironmentMap('empheq-env', EmpheqUtil.environment, {
empheq: ['Empheq', 'empheq'],
}, EmpheqMethods);
//
// Define the empheq characters
//
new CommandMap('empheq-macros', {
empheqlbrace: ['EmpheqMO', '{'],
empheqrbrace: ['EmpheqMO', '}'],
empheqlbrack: ['EmpheqMO', '['],
empheqrbrack: ['EmpheqMO', ']'],
empheqlangle: ['EmpheqMO', '\u27E8'],
empheqrangle: ['EmpheqMO', '\u27E9'],
empheqlparen: ['EmpheqMO', '('],
empheqrparen: ['EmpheqMO', ')'],
empheqlvert: ['EmpheqMO', '|'],
empheqrvert: ['EmpheqMO', '|'],
empheqlVert: ['EmpheqMO', '\u2016'],
empheqrVert: ['EmpheqMO', '\u2016'],
empheqlfloor: ['EmpheqMO', '\u230A'],
empheqrfloor: ['EmpheqMO', '\u230B'],
empheqlceil: ['EmpheqMO', '\u2308'],
empheqrceil: ['EmpheqMO', '\u2309'],
empheqbiglbrace: ['EmpheqMO', '{'],
empheqbigrbrace: ['EmpheqMO', '}'],
empheqbiglbrack: ['EmpheqMO', '['],
empheqbigrbrack: ['EmpheqMO', ']'],
empheqbiglangle: ['EmpheqMO', '\u27E8'],
empheqbigrangle: ['EmpheqMO', '\u27E9'],
empheqbiglparen: ['EmpheqMO', '('],
empheqbigrparen: ['EmpheqMO', ')'],
empheqbiglvert: ['EmpheqMO', '|'],
empheqbigrvert: ['EmpheqMO', '|'],
empheqbiglVert: ['EmpheqMO', '\u2016'],
empheqbigrVert: ['EmpheqMO', '\u2016'],
empheqbiglfloor: ['EmpheqMO', '\u230A'],
empheqbigrfloor: ['EmpheqMO', '\u230B'],
empheqbiglceil: ['EmpheqMO', '\u2308'],
empheqbigrceil: ['EmpheqMO', '\u2309'],
empheql: 'EmpheqDelim',
empheqr: 'EmpheqDelim',
empheqbigl: 'EmpheqDelim',
empheqbigr: 'EmpheqDelim'
}, EmpheqMethods);
//
// Define the package for our new environment
//
export const EmpheqConfiguration = Configuration.create('empheq', {
handler: {
macro: ['empheq-macros'],
environment: ['empheq-env'],
},
items: {
[EmpheqBeginItem.prototype.kind]: EmpheqBeginItem
}
});

View File

@@ -0,0 +1,228 @@
/*************************************************************
*
* Copyright (c) 2021-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Utilities file for the empheq package.
*
* @author dpvc@mathjax.org (Davide P. Cervone)
*/
import ParseUtil from '../ParseUtil.js';
import TexParser from '../TexParser.js';
import {EnvList} from '../StackItem.js';
import {AbstractTags} from '../Tags.js';
import {MmlNode} from '../../../core/MmlTree/MmlNode.js';
import {MmlMtable} from '../../../core/MmlTree/MmlNodes/mtable.js';
import {MmlMtd} from '../../../core/MmlTree/MmlNodes/mtd.js';
import {EmpheqBeginItem} from './EmpheqConfiguration.js';
export const EmpheqUtil = {
/**
* Create the needed envinronment and process it by the give function.
*
* @param {TexParser} parser The active tex parser.
* @param {string} env The environment to create.
* @param {Function} func A function to process the environment.
* @param {any[]} args The arguments for func.
*/
environment(parser: TexParser, env: string, func: Function, args: any[]) {
const name = args[0];
const item = parser.itemFactory.create(name + '-begin').setProperties({name: env, end: name});
parser.Push(func(parser, item, ...args.slice(1)));
},
/**
* Parse an options string.
*
* @param {string} text The string to parse.
* @param {{[key:string]:number} allowed Object containing options to allow
* @return {EnvList} The parsed keys
*/
splitOptions(text: string, allowed: {[key: string]: number} = null): EnvList {
return ParseUtil.keyvalOptions(text, allowed, true);
},
/**
* Find the number of columns in the table.
*
* @param {MmlMtable} table The table whose columns to count.
* @return {number} The number of columns in the table.
*/
columnCount(table: MmlMtable): number {
let m = 0;
for (const row of table.childNodes) {
const n = row.childNodes.length - (row.isKind('mlabeledtr') ? 1 : 0);
if (n > m) m = n;
}
return m;
},
/**
* Create an mpadded element with no height and depth, but whose
* content is the given TeX code with a phantom that is the height and
* depth of the given table.
*
* @param {string} tex The TeX code to put in the box.
* @param {MmlTable} table The table used to size the box.
* @param {TexParser} parser The active tex parser.
* @param {string} env The name of the current environment.
* @return {MmlNode} The mpadded element.
*/
cellBlock(tex: string, table: MmlMtable, parser: TexParser, env: string): MmlNode {
const mpadded = parser.create('node', 'mpadded', [], {height: 0, depth: 0, voffset: '-1height'});
const result = new TexParser(tex, parser.stack.env, parser.configuration);
const mml = result.mml();
if (env && result.configuration.tags.label) {
(result.configuration.tags.currentTag as any).env = env;
(result.configuration.tags as AbstractTags).getTag(true);
}
for (const child of (mml.isInferred ? mml.childNodes : [mml])) {
mpadded.appendChild(child);
}
mpadded.appendChild(parser.create('node', 'mphantom', [
parser.create('node', 'mpadded', [table], {width: 0})
]));
return mpadded;
},
/**
* Make a copy of the table with only the first row and create a phantom element
* that has its height and depth.
*
* @param {MmlMtable} original The original table.
* @param {TexParser} parser The active tex parser.
* @return {MmlNode} The resulting mphantom element.
*/
topRowTable(original: MmlMtable, parser: TexParser): MmlNode {
const table = ParseUtil.copyNode(original, parser);
table.setChildren(table.childNodes.slice(0, 1));
table.attributes.set('align', 'baseline 1');
return original.factory.create('mphantom', {}, [parser.create('node', 'mpadded', [table], {width: 0})]);
},
/**
* Add an mpadded element that has zero height and depth but whose content is
* the cell block for the given TeX code followed by a struct the size of the top row.
*
* @param {MmlMtd} mtd The mtd to add content to.
* @param {string} tex The TeX string to put into the cell.
* @param {MmlMtable} table The reference table used for its various heights.
* @param {TexParser} parser The active tex parser.
* @param {srting} env The current environment.
*/
rowspanCell(mtd: MmlMtd, tex: string, table: MmlMtable, parser: TexParser, env: string) {
mtd.appendChild(
parser.create('node', 'mpadded', [
this.cellBlock(tex, ParseUtil.copyNode(table, parser), parser, env),
this.topRowTable(table, parser)
], {height: 0, depth: 0, voffset: 'height'})
);
},
/**
* Add something on the left of the original table.
*
* @param {MmlMtable} table The table to modify.
* @param {MmlMtable} original The original table.
* @param {string} left The TeX code to add to the left.
* @param {TexParser} parser The active tex parser.
* @param {string} env The current environment.
*/
left(table: MmlMtable, original: MmlMtable, left: string, parser: TexParser, env: string = '') {
table.attributes.set('columnalign', 'right ' + (table.attributes.get('columnalign') || ''));
table.attributes.set('columnspacing', '0em ' + (table.attributes.get('columnspacing') || ''));
let mtd;
for (const row of table.childNodes.slice(0).reverse()) {
mtd = parser.create('node', 'mtd');
row.childNodes.unshift(mtd);
mtd.parent = row;
if (row.isKind('mlabeledtr')) {
row.childNodes[0] = row.childNodes[1];
row.childNodes[1] = mtd;
}
}
this.rowspanCell(mtd, left, original, parser, env);
},
/**
* Add something on the right of the original table.
*
* @param {MmlMtable} table The table to modify.
* @param {MmlMtable} original The original table.
* @param {string} right The TeX code to add to the right.
* @param {TexParser} parser The active tex parser.
* @param {string} env The current environment.
*/
right(table: MmlMtable, original: MmlMtable, right: string, parser: TexParser, env: string = '') {
if (table.childNodes.length === 0) {
table.appendChild(parser.create('node', 'mtr'));
}
const m = EmpheqUtil.columnCount(table);
const row = table.childNodes[0];
while (row.childNodes.length < m) row.appendChild(parser.create('node', 'mtd'));
const mtd = row.appendChild(parser.create('node', 'mtd')) as MmlMtd;
EmpheqUtil.rowspanCell(mtd, right, original, parser, env);
table.attributes.set(
'columnalign',
(table.attributes.get('columnalign') as string || '').split(/ /).slice(0, m).join(' ') + ' left'
);
table.attributes.set(
'columnspacing',
(table.attributes.get('columnspacing') as string || '').split(/ /).slice(0, m - 1).join(' ') + ' 0em'
);
},
/**
* Add the left- and right-hand material to the table.
*/
adjustTable(empheq: EmpheqBeginItem, parser: TexParser) {
const left = empheq.getProperty('left');
const right = empheq.getProperty('right');
if (left || right) {
const table = empheq.Last;
const original = ParseUtil.copyNode(table, parser);
if (left) this.left(table, original, left, parser);
if (right) this.right(table, original, right, parser);
}
},
/**
* The environments allowed to be used in the empheq environment.
*/
allowEnv: {
equation: true,
align: true,
gather: true,
flalign: true,
alignat: true,
multline: true
},
/**
* Checks to see if the given environment is one of the allowed ones.
*
* @param {string} env The environment to check.
* @return {boolean} True if the environment is allowed.
*/
checkEnv(env: string): boolean {
return this.allowEnv.hasOwnProperty(env.replace(/\*$/, '')) || false;
}
};

View File

@@ -0,0 +1,74 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Configuration file for the enclose package.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {Configuration} from '../Configuration.js';
import TexParser from '../TexParser.js';
import {CommandMap} from '../SymbolMap.js';
import {ParseMethod} from '../Types.js';
import ParseUtil from '../ParseUtil.js';
/**
* The attributes allowed in \enclose{notation}[attributes]{math}
* @type {{[key: string]: number}}
*/
export const ENCLOSE_OPTIONS: {[key: string]: number} = {
'data-arrowhead': 1,
color: 1,
mathcolor: 1,
background: 1,
mathbackground: 1,
'data-padding': 1,
'data-thickness': 1
};
// Namespace
export let EncloseMethods: Record<string, ParseMethod> = {};
/**
* Implements \enclose{notation}[attr]{math}
* (create <menclose notation="notation">math</menclose>)
* @param {TexParser} parser The current tex parser.
* @param {string} name The name of the calling macro.
*/
EncloseMethods.Enclose = function(parser: TexParser, name: string) {
let notation = parser.GetArgument(name).replace(/,/g, ' ');
const attr = parser.GetBrackets(name, '');
const math = parser.ParseArg(name);
const def = ParseUtil.keyvalOptions(attr, ENCLOSE_OPTIONS);
def.notation = notation;
parser.Push(parser.create('node', 'menclose', [math], def));
};
new CommandMap('enclose', {enclose: 'Enclose'}, EncloseMethods);
export const EncloseConfiguration = Configuration.create(
'enclose', {handler: {macro: ['enclose']}}
);

View File

@@ -0,0 +1,92 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Configuration file for the extpfeil package. Note that this is
* based on AMS package and Newcommand utilities.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {Configuration, ParserConfiguration} from '../Configuration.js';
import TexParser from '../TexParser.js';
import {CommandMap} from '../SymbolMap.js';
import {ParseMethod} from '../Types.js';
import {AmsMethods} from '../ams/AmsMethods.js';
import NewcommandUtil from '../newcommand/NewcommandUtil.js';
import {NewcommandConfiguration} from '../newcommand/NewcommandConfiguration.js';
import TexError from '../TexError.js';
// Namespace
export let ExtpfeilMethods: Record<string, ParseMethod> = {};
ExtpfeilMethods.xArrow = AmsMethods.xArrow;
/**
* Implements \Newextarrow to define a new arrow.
* @param {TexParser} parser The current tex parser.
* @param {string} name The name of the calling macro.
*/
ExtpfeilMethods.NewExtArrow = function(parser: TexParser, name: string) {
let cs = parser.GetArgument(name);
const space = parser.GetArgument(name);
const chr = parser.GetArgument(name);
if (!cs.match(/^\\([a-z]+|.)$/i)) {
throw new TexError('NewextarrowArg1',
'First argument to %1 must be a control sequence name', name);
}
if (!space.match(/^(\d+),(\d+)$/)) {
throw new TexError(
'NewextarrowArg2',
'Second argument to %1 must be two integers separated by a comma',
name);
}
if (!chr.match(/^(\d+|0x[0-9A-F]+)$/i)) {
throw new TexError(
'NewextarrowArg3',
'Third argument to %1 must be a unicode character number',
name);
}
cs = cs.substr(1);
let spaces = space.split(',');
NewcommandUtil.addMacro(parser, cs, ExtpfeilMethods.xArrow,
[parseInt(chr), parseInt(spaces[0]), parseInt(spaces[1])]);
};
new CommandMap('extpfeil', {
xtwoheadrightarrow: ['xArrow', 0x21A0, 12, 16],
xtwoheadleftarrow: ['xArrow', 0x219E, 17, 13],
xmapsto: ['xArrow', 0x21A6, 6, 7],
xlongequal: ['xArrow', 0x003D, 7, 7],
xtofrom: ['xArrow', 0x21C4, 12, 12],
Newextarrow: 'NewExtArrow'
}, ExtpfeilMethods);
let init = function(config: ParserConfiguration) {
NewcommandConfiguration.init(config);
};
export const ExtpfeilConfiguration = Configuration.create(
'extpfeil', {
handler: {macro: ['extpfeil']},
init: init
}
);

View File

@@ -0,0 +1,63 @@
/*************************************************************
*
* Copyright (c) 2021-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Configuration file for the gensymb package.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {Configuration} from '../Configuration.js';
import {Symbol} from '../Symbol.js';
import {TexConstant} from '../TexConstants.js';
import {CharacterMap} from '../SymbolMap.js';
import TexParser from '../TexParser.js';
/**
* Handle characters that are known units.
* @param {TexParser} parser The current tex parser.
* @param {Symbol} mchar The parsed symbol.
*/
function mathcharUnit(parser: TexParser, mchar: Symbol) {
const def = mchar.attributes || {};
def.mathvariant = TexConstant.Variant.NORMAL;
def.class = 'MathML-Unit';
const node = parser.create('token', 'mi', def, mchar.char);
parser.Push(node);
}
/**
* gensymb units.
*/
new CharacterMap('gensymb-symbols', mathcharUnit, {
ohm: '\u2126',
degree: '\u00B0',
celsius: '\u2103',
perthousand: '\u2030',
micro: '\u00B5'
});
export const GensymbConfiguration = Configuration.create(
'gensymb', {
handler: {macro: ['gensymb-symbols']},
}
);

View File

@@ -0,0 +1,39 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Configuration file for the Html package.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import {Configuration} from '../Configuration.js';
import {CommandMap} from '../SymbolMap.js';
import HtmlMethods from './HtmlMethods.js';
new CommandMap('html_macros', {
href: 'Href',
'class': 'Class',
style: 'Style',
cssId: 'Id'
}, HtmlMethods);
export const HtmlConfiguration = Configuration.create(
'html', {handler: { macro: ['html_macros']}}
);

View File

@@ -0,0 +1,124 @@
/*************************************************************
*
* Copyright (c) 2018-2022 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Methods for the Html package.
*
* @author v.sorge@mathjax.org (Volker Sorge)
*/
import TexParser from '../TexParser.js';
import {ParseMethod} from '../Types.js';
import NodeUtil from '../NodeUtil.js';
import {MmlNode} from '../../../core/MmlTree/MmlNode.js';
// Namespace
let HtmlMethods: Record<string, ParseMethod> = {};
/**
* Implements \href{url}{math}
* @param {TexParser} parser The calling parser.
* @param {string} name The macro name.
*/
HtmlMethods.Href = function(parser: TexParser, name: string) {
const url = parser.GetArgument(name);
const arg = GetArgumentMML(parser, name);
NodeUtil.setAttribute(arg, 'href', url);
parser.Push(arg);
};
/**
* Implements \class{name}{math}
* @param {TexParser} parser The calling parser.
* @param {string} name The macro name.
*/
HtmlMethods.Class = function(parser: TexParser, name: string) {
let CLASS = parser.GetArgument(name);
const arg = GetArgumentMML(parser, name);
let oldClass = NodeUtil.getAttribute(arg, 'class');
if (oldClass) {
CLASS = oldClass + ' ' + CLASS;
}
NodeUtil.setAttribute(arg, 'class', CLASS);
parser.Push(arg);
};
/**
* Implements \style{style-string}{math}
* @param {TexParser} parser The calling parser.
* @param {string} name The macro name.
*/
HtmlMethods.Style = function(parser: TexParser, name: string) {
let style = parser.GetArgument(name);
const arg = GetArgumentMML(parser, name);
// check that it looks like a style string
let oldStyle = NodeUtil.getAttribute(arg, 'style');
if (oldStyle) {
if (style.charAt(style.length - 1) !== ';') {
style += ';';
}
style = oldStyle + ' ' + style;
}
NodeUtil.setAttribute(arg, 'style', style);
parser.Push(arg);
};
/**
* Implements \cssId{id}{math}
* @param {TexParser} parser The calling parser.
* @param {string} name The macro name.
*/
HtmlMethods.Id = function(parser: TexParser, name: string) {
const ID = parser.GetArgument(name);
const arg = GetArgumentMML(parser, name);
NodeUtil.setAttribute(arg, 'id', ID);
parser.Push(arg);
};
/**
* Parses the math argument of the above commands and returns it as single
* node (in an mrow if necessary). The HTML attributes are then
* attached to this element.
* @param {TexParser} parser The calling parser.
* @param {string} name The calling macro name.
* @return {MmlNode} The math node.
*/
let GetArgumentMML = function(parser: TexParser, name: string): MmlNode {
let arg = parser.ParseArg(name);
if (!NodeUtil.isInferred(arg)) {
return arg;
}
let children = NodeUtil.getChildren(arg);
if (children.length === 1) {
return children[0];
}
const mrow = parser.create('node', 'mrow');
NodeUtil.copyChildren(arg, mrow);
NodeUtil.copyAttributes(arg, mrow);
return mrow;
};
export default HtmlMethods;

View File

@@ -0,0 +1,134 @@
/*************************************************************
* Copyright (c) 2020-2022 MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Configuration file for the mathtools package.
*
* @author v.sorge@mathjax.org (Volker Sorge)
* @author dpvc@mathjax.org (Davide P. Cervone)
*/
import {Configuration} from '../Configuration.js';
import {CommandMap} from '../SymbolMap.js';
import NodeUtil from '../NodeUtil.js';
import {expandable} from '../../../util/Options.js';
import {ParserConfiguration} from '../Configuration.js';
import {TeX} from '../../tex.js';
import ParseOptions from '../ParseOptions.js';
import './MathtoolsMappings.js';
import {MathtoolsUtil} from './MathtoolsUtil.js';
import {MathtoolsTagFormat} from './MathtoolsTags.js';
import {MultlinedItem} from './MathtoolsItems.js';
/**
* The name of the paried-delimiters command map.
*/
export const PAIREDDELIMS = 'mathtools-paired-delims';
/**
* Create the paired-delimiters command map, and link it into the configuration.
* @param {ParserConfiguration} config The current configuration.
*/
function initMathtools(config: ParserConfiguration) {
new CommandMap(PAIREDDELIMS, {}, {});
config.append(Configuration.local({handler: {macro: [PAIREDDELIMS]}, priority: -5}));
}
/**
* Add any pre-defined paired delimiters, and subclass the configured tag format.
* @param {ParserConfiguration} config The current configuration.
* @param {TeX} jac The TeX input jax
*/
function configMathtools(config: ParserConfiguration, jax: TeX<any, any, any>) {
const parser = jax.parseOptions;
const pairedDelims = parser.options.mathtools.pairedDelimiters;
for (const cs of Object.keys(pairedDelims)) {
MathtoolsUtil.addPairedDelims(parser, cs, pairedDelims[cs]);
}
MathtoolsTagFormat(config, jax);
}
/**
* A filter to fix up mmultiscripts elements.
* @param {ParseOptions} data The parse options.
*/
export function fixPrescripts({data}: {data: ParseOptions}) {
for (const node of data.getList('mmultiscripts')) {
if (!node.getProperty('fixPrescript')) continue;
const childNodes = NodeUtil.getChildren(node);
let n = 0;
for (const i of [1, 2]) {
if (!childNodes[i]) {
NodeUtil.setChild(node, i, data.nodeFactory.create('node', 'none'));
n++;
}
}
for (const i of [4, 5]) {
if (NodeUtil.isType(childNodes[i], 'mrow') && NodeUtil.getChildren(childNodes[i]).length === 0) {
NodeUtil.setChild(node, i, data.nodeFactory.create('node', 'none'));
}
}
if (n === 2) {
childNodes.splice(1, 2);
}
}
}
/**
* The configuration for the mathtools package
*/
export const MathtoolsConfiguration = Configuration.create(
'mathtools', {
handler: {
macro: ['mathtools-macros', 'mathtools-delimiters'],
environment: ['mathtools-environments'],
delimiter: ['mathtools-delimiters'],
character: ['mathtools-characters']
},
items: {
[MultlinedItem.prototype.kind]: MultlinedItem
},
init: initMathtools,
config: configMathtools,
postprocessors: [[fixPrescripts, -6]],
options: {
mathtools: {
'multlinegap': '1em', // horizontal space for multlined environments
'multlined-pos': 'c', // default alignment for multlined environments
'firstline-afterskip': '', // space for first line of multlined (overrides multlinegap)
'lastline-preskip': '', // space for last line of multlined (overrides multlinegap)
'smallmatrix-align': 'c', // default alignment for smallmatrix environments
'shortvdotsadjustabove': '.2em', // space to remove above \shortvdots
'shortvdotsadjustbelow': '.2em', // space to remove below \shortvdots
'centercolon': false, // true to have colon automatically centered
'centercolon-offset': '.04em', // vertical adjustment for centered colons
'thincolon-dx': '-.04em', // horizontal adjustment for thin colons (e.g., \coloneqq)
'thincolon-dw': '-.08em', // width adjustment for thin colons
'use-unicode': false, // true to use unicode characters rather than multi-character
// version for \coloneqq, etc., when possible
'prescript-sub-format': '', // format for \prescript subscript
'prescript-sup-format': '', // format for \prescript superscript
'prescript-arg-format': '', // format for \prescript base
'allow-mathtoolsset': true, // true to allow \mathtoolsset to change settings
pairedDelimiters: expandable({}), // predefined paired delimiters
// name: [left, right, body, argcount, pre, post]
tagforms: expandable({}), // tag form definitions
// name: [left, right, format]
}
}
}
);

View File

@@ -0,0 +1,70 @@
/*************************************************************
* Copyright (c) 2020-2022 MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Implementation of items for the mathtools package.
*
* @author v.sorge@mathjax.org (Volker Sorge)
* @author dpvc@mathjax.org (Davide P. Cervone)
*/
import {MultlineItem} from '../ams/AmsItems.js';
import NodeUtil from '../NodeUtil.js';
import {TexConstant} from '../TexConstants.js';
/**
* The StackItem for the multlined environment
*/
export class MultlinedItem extends MultlineItem {
/**
* @override
*/
get kind() {
return 'multlined';
}
/**
* @override
*/
public EndTable() {
if (this.Size() || this.row.length) {
this.EndEntry();
this.EndRow();
}
if (this.table.length > 1) {
const options = this.factory.configuration.options.mathtools;
const gap = options.multlinegap;
const firstskip = options['firstline-afterskip'] || gap;
const lastskip = options['lastline-preskip'] || gap;
const first = NodeUtil.getChildren(this.table[0])[0];
if (NodeUtil.getAttribute(first, 'columnalign') !== TexConstant.Align.RIGHT) {
first.appendChild(this.create('node', 'mspace', [], {width: firstskip}));
}
const last = NodeUtil.getChildren(this.table[this.table.length - 1])[0];
if (NodeUtil.getAttribute(last, 'columnalign') !== TexConstant.Align.LEFT) {
const top = NodeUtil.getChildren(last)[0];
top.childNodes.unshift(null);
const space = this.create('node', 'mspace', [], {width: lastskip});
NodeUtil.setChild(top, 0, space);
}
}
super.EndTable.call(this);
}
}

View File

@@ -0,0 +1,206 @@
/*************************************************************
* Copyright (c) 2020-2022 MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Macro and environment mappings for the mathtools package.
*
* @author v.sorge@mathjax.org (Volker Sorge)
* @author dpvc@mathjax.org (Davide P. Cervone)
*/
import ParseMethods from '../ParseMethods.js';
import {CommandMap, EnvironmentMap, DelimiterMap} from '../SymbolMap.js';
import {TexConstant} from '../TexConstants.js';
import {MathtoolsMethods} from './MathtoolsMethods.js';
//
// Mathtools macros that are not implemented:
//
// \smashoperator[〈pos〉]{〈operator with limits〉}
// \SwapAboveDisplaySkip
// \noeqref{〈label,label,. . . 〉}
// \intertext{〈text 〉}
// \shortintertext{〈text 〉}
// \reDeclarePairedDelimiterInnerWrapper{〈macro name〉}{〈star or nostarnonscaled or nostarscaled〉}{〈code〉}
// \DeclareMathSizes{〈dimen〉}{〈dimen〉}{〈dimen〉}{〈dimen〉}
// \newgathered{〈name〉}{〈pre_line〉}{〈post_line〉}{〈after〉}
// \renewgathered{〈name〉}{〈pre_line〉}{〈post_line〉}{〈after〉}
//
/**
* The macros for this package.
*/
new CommandMap('mathtools-macros', {
shoveleft: ['HandleShove', TexConstant.Align.LEFT], // override AMS version
shoveright: ['HandleShove', TexConstant.Align.RIGHT], // override AMS version
xleftrightarrow: ['xArrow', 0x2194, 10, 10],
xLeftarrow: ['xArrow', 0x21D0, 12, 7],
xRightarrow: ['xArrow', 0x21D2, 7, 12],
xLeftrightarrow: ['xArrow', 0x21D4, 12, 12],
xhookleftarrow: ['xArrow', 0x21A9, 10, 5],
xhookrightarrow: ['xArrow', 0x21AA, 5, 10],
xmapsto: ['xArrow', 0x21A6, 10, 10],
xrightharpoondown: ['xArrow', 0x21C1, 5, 10],
xleftharpoondown: ['xArrow', 0x21BD, 10, 5],
xrightleftharpoons: ['xArrow', 0x21CC, 10, 10],
xrightharpoonup: ['xArrow', 0x21C0, 5, 10],
xleftharpoonup: ['xArrow', 0x21BC, 10, 5],
xleftrightharpoons: ['xArrow', 0x21CB, 10, 10],
mathllap: ['MathLap', 'l', false],
mathrlap: ['MathLap', 'r', false],
mathclap: ['MathLap', 'c', false],
clap: ['MtLap', 'c'],
textllap: ['MtLap', 'l'],
textrlap: ['MtLap', 'r'],
textclap: ['MtLap', 'c'],
cramped: 'Cramped',
crampedllap: ['MathLap', 'l', true],
crampedrlap: ['MathLap', 'r', true],
crampedclap: ['MathLap', 'c', true],
crampedsubstack: ['Macro', '\\begin{crampedsubarray}{c}#1\\end{crampedsubarray}', 1],
mathmbox: 'MathMBox',
mathmakebox: 'MathMakeBox',
overbracket: 'UnderOverBracket',
underbracket: 'UnderOverBracket',
refeq: 'HandleRef',
MoveEqLeft: ['Macro', '\\hspace{#1em}&\\hspace{-#1em}', 1, '2'],
Aboxed: 'Aboxed',
ArrowBetweenLines: 'ArrowBetweenLines',
vdotswithin: 'VDotsWithin',
shortvdotswithin: 'ShortVDotsWithin',
MTFlushSpaceAbove: 'FlushSpaceAbove',
MTFlushSpaceBelow: 'FlushSpaceBelow',
DeclarePairedDelimiter: 'DeclarePairedDelimiter',
DeclarePairedDelimiterX: 'DeclarePairedDelimiterX',
DeclarePairedDelimiterXPP: 'DeclarePairedDelimiterXPP',
//
// Typos from initial release -- kept for backward compatibility for now
//
DeclarePairedDelimiters: 'DeclarePairedDelimiter',
DeclarePairedDelimitersX: 'DeclarePairedDelimiterX',
DeclarePairedDelimitersXPP: 'DeclarePairedDelimiterXPP',
centercolon: ['CenterColon', true, true],
ordinarycolon: ['CenterColon', false],
MTThinColon: ['CenterColon', true, true, true],
coloneqq: ['Relation', ':=', '\u2254'],
Coloneqq: ['Relation', '::=', '\u2A74'],
coloneq: ['Relation', ':-'],
Coloneq: ['Relation', '::-'],
eqqcolon: ['Relation', '=:', '\u2255'],
Eqqcolon: ['Relation', '=::'],
eqcolon: ['Relation', '-:', '\u2239'],
Eqcolon: ['Relation', '-::'],
colonapprox: ['Relation', ':\\approx'],
Colonapprox: ['Relation', '::\\approx'],
colonsim: ['Relation', ':\\sim'],
Colonsim: ['Relation', '::\\sim'],
dblcolon: ['Relation', '::', '\u2237'],
nuparrow: ['NArrow', '\u2191', '.06em'],
ndownarrow: ['NArrow', '\u2193', '.25em'],
bigtimes: ['Macro', '\\mathop{\\Large\\kern-.1em\\boldsymbol{\\times}\\kern-.1em}'],
splitfrac: ['SplitFrac', false],
splitdfrac: ['SplitFrac', true],
xmathstrut: 'XMathStrut',
prescript: 'Prescript',
newtagform: ['NewTagForm', false],
renewtagform: ['NewTagForm', true],
usetagform: 'UseTagForm',
adjustlimits: [
'MacroWithTemplate',
'\\mathop{{#1}\\vphantom{{#3}}}_{{#2}\\vphantom{{#4}}}\\mathop{{#3}\\vphantom{{#1}}}_{{#4}\\vphantom{{#2}}}',
4, , '_', , '_'
],
mathtoolsset: 'SetOptions'
}, MathtoolsMethods);
/**
* The environments for this package.
*/
new EnvironmentMap('mathtools-environments', ParseMethods.environment, {
dcases: ['Array', null, '\\{', '', 'll', null, '.2em', 'D'],
rcases: ['Array', null, '', '\\}', 'll', null, '.2em'],
drcases: ['Array', null, '', '\\}', 'll', null, '.2em', 'D'],
'dcases*': ['Cases', null, '{', '', 'D'],
'rcases*': ['Cases', null, '', '}'],
'drcases*': ['Cases', null, '', '}', 'D'],
'cases*': ['Cases', null, '{', ''],
'matrix*': ['MtMatrix', null, null, null],
'pmatrix*': ['MtMatrix', null, '(', ')'],
'bmatrix*': ['MtMatrix', null, '[', ']'],
'Bmatrix*': ['MtMatrix', null, '\\{', '\\}'],
'vmatrix*': ['MtMatrix', null, '\\vert', '\\vert'],
'Vmatrix*': ['MtMatrix', null, '\\Vert', '\\Vert'],
'smallmatrix*': ['MtSmallMatrix', null, null, null],
psmallmatrix: ['MtSmallMatrix', null, '(', ')', 'c'],
'psmallmatrix*': ['MtSmallMatrix', null, '(', ')'],
bsmallmatrix: ['MtSmallMatrix', null, '[', ']', 'c'],
'bsmallmatrix*': ['MtSmallMatrix', null, '[', ']'],
Bsmallmatrix: ['MtSmallMatrix', null, '\\{', '\\}', 'c'],
'Bsmallmatrix*': ['MtSmallMatrix', null, '\\{', '\\}'],
vsmallmatrix: ['MtSmallMatrix', null, '\\vert', '\\vert', 'c'],
'vsmallmatrix*': ['MtSmallMatrix', null, '\\vert', '\\vert'],
Vsmallmatrix: ['MtSmallMatrix', null, '\\Vert', '\\Vert', 'c'],
'Vsmallmatrix*': ['MtSmallMatrix', null, '\\Vert', '\\Vert'],
crampedsubarray: ['Array', null, null, null, null, '0em', '0.1em', 'S\'', 1],
multlined: 'MtMultlined',
spreadlines: ['SpreadLines', true],
lgathered: ['AmsEqnArray', null, null, null, 'l', null, '.5em', 'D'],
rgathered: ['AmsEqnArray', null, null, null, 'r', null, '.5em', 'D'],
}, MathtoolsMethods);
/**
* The delimiters for this package.
*/
new DelimiterMap('mathtools-delimiters', ParseMethods.delimiter, {
'\\lparen': '(',
'\\rparen': ')'
});
/**
* The special characters for this package.
*/
new CommandMap('mathtools-characters', {
':' : ['CenterColon', true]
}, MathtoolsMethods);

Some files were not shown because too many files have changed in this diff Show More