-
Notifications
You must be signed in to change notification settings - Fork 213
/
Copy pathParseOptions.ts
241 lines (206 loc) · 6.47 KB
/
ParseOptions.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
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;
}
}