site/node_modules/mathjax-full/ts/input/tex/ParseOptions.ts

242 lines
6.5 KiB
TypeScript
Raw Normal View History

2024-10-14 06:09:33 +00:00
/*************************************************************
*
* 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;
}
}