123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232 |
- /*************************************************************
- *
- * 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);
- }
- }
|