kmap-term-tree 0.9.21 → 0.9.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/demo/index.html +124 -10
- package/dist/src/KmapTermTree.d.ts +29 -46
- package/dist/src/KmapTermTree.js +536 -221
- package/dist/src/KmapTermTree.js.map +1 -1
- package/dist/src/asciimath-parser.d.ts +17 -0
- package/dist/src/asciimath-parser.js +472 -0
- package/dist/src/asciimath-parser.js.map +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/katex-css.d.ts +2 -0
- package/dist/src/katex-css.js +7 -0
- package/dist/src/katex-css.js.map +1 -0
- package/dist/src/model.d.ts +30 -0
- package/dist/src/model.js +26 -0
- package/dist/src/model.js.map +1 -0
- package/dist/src/parser.js.map +1 -1
- package/dist/src/tokenizer.js.map +1 -1
- package/dist/stories/index.stories.d.ts +20 -0
- package/dist/stories/index.stories.js +26 -2
- package/dist/stories/index.stories.js.map +1 -1
- package/dist/test/asciimath-parser.test.d.ts +1 -0
- package/dist/test/asciimath-parser.test.js +45 -0
- package/dist/test/asciimath-parser.test.js.map +1 -0
- package/dist/test/kmap-term-tree.test.js +30 -7
- package/dist/test/kmap-term-tree.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +16 -50
- package/src/KmapTermTree.ts +557 -235
- package/src/asciimath-parser.ts +554 -0
- package/src/index.ts +2 -0
- package/src/katex-css.ts +7 -0
- package/src/model.ts +57 -0
- package/stories/index.stories.ts +35 -2
- package/test/asciimath-parser.test.ts +50 -0
- package/test/kmap-term-tree.test.ts +44 -7
|
@@ -0,0 +1,554 @@
|
|
|
1
|
+
import { TermNode, GERMAN_LABELS, OPERATOR_SYMBOLS } from './model.js';
|
|
2
|
+
|
|
3
|
+
const KNOWN_FUNCTIONS = new Set([
|
|
4
|
+
'sin',
|
|
5
|
+
'cos',
|
|
6
|
+
'tan',
|
|
7
|
+
'cot',
|
|
8
|
+
'sec',
|
|
9
|
+
'csc',
|
|
10
|
+
'arcsin',
|
|
11
|
+
'arccos',
|
|
12
|
+
'arctan',
|
|
13
|
+
'sinh',
|
|
14
|
+
'cosh',
|
|
15
|
+
'tanh',
|
|
16
|
+
'exp',
|
|
17
|
+
'ln',
|
|
18
|
+
'log',
|
|
19
|
+
'sqrt',
|
|
20
|
+
'abs',
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
const FUNCTION_MAP: Record<string, string> = {
|
|
24
|
+
sin: 'Sin',
|
|
25
|
+
cos: 'Cos',
|
|
26
|
+
tan: 'Tan',
|
|
27
|
+
cot: 'Cot',
|
|
28
|
+
arcsin: 'Arcsin',
|
|
29
|
+
arccos: 'Arccos',
|
|
30
|
+
arctan: 'Arctan',
|
|
31
|
+
sinh: 'Sinh',
|
|
32
|
+
cosh: 'Cosh',
|
|
33
|
+
tanh: 'Tanh',
|
|
34
|
+
ln: 'Ln',
|
|
35
|
+
log: 'Log',
|
|
36
|
+
sqrt: 'Sqrt',
|
|
37
|
+
abs: 'Abs',
|
|
38
|
+
exp: 'Exp',
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const GREEK_LETTERS = new Set([
|
|
42
|
+
'alpha',
|
|
43
|
+
'beta',
|
|
44
|
+
'gamma',
|
|
45
|
+
'delta',
|
|
46
|
+
'epsilon',
|
|
47
|
+
'zeta',
|
|
48
|
+
'eta',
|
|
49
|
+
'theta',
|
|
50
|
+
'iota',
|
|
51
|
+
'kappa',
|
|
52
|
+
'lambda',
|
|
53
|
+
'mu',
|
|
54
|
+
'nu',
|
|
55
|
+
'xi',
|
|
56
|
+
'pi',
|
|
57
|
+
'rho',
|
|
58
|
+
'sigma',
|
|
59
|
+
'tau',
|
|
60
|
+
'upsilon',
|
|
61
|
+
'phi',
|
|
62
|
+
'chi',
|
|
63
|
+
'psi',
|
|
64
|
+
'omega',
|
|
65
|
+
]);
|
|
66
|
+
|
|
67
|
+
type TokenType =
|
|
68
|
+
| 'NUMBER'
|
|
69
|
+
| 'VARIABLE'
|
|
70
|
+
| 'FUNCTION'
|
|
71
|
+
| 'OPERATOR'
|
|
72
|
+
| 'LPAREN'
|
|
73
|
+
| 'RPAREN'
|
|
74
|
+
| 'COMMA'
|
|
75
|
+
| 'EOF';
|
|
76
|
+
|
|
77
|
+
interface Token {
|
|
78
|
+
type: TokenType;
|
|
79
|
+
value: string;
|
|
80
|
+
implicit?: boolean;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
class Tokenizer {
|
|
84
|
+
private input: string;
|
|
85
|
+
private pos = 0;
|
|
86
|
+
|
|
87
|
+
constructor(input: string) {
|
|
88
|
+
this.input = input.trim();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
tokenize(): Token[] {
|
|
92
|
+
const rawTokens: Token[] = [];
|
|
93
|
+
|
|
94
|
+
while (this.pos < this.input.length) {
|
|
95
|
+
const ch = this.input[this.pos];
|
|
96
|
+
|
|
97
|
+
if (/\s/.test(ch)) {
|
|
98
|
+
this.pos++;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Numbers: integer or floating point
|
|
103
|
+
if (/\d/.test(ch)) {
|
|
104
|
+
let num = '';
|
|
105
|
+
while (
|
|
106
|
+
this.pos < this.input.length &&
|
|
107
|
+
/[\d.]/.test(this.input[this.pos])
|
|
108
|
+
) {
|
|
109
|
+
num += this.input[this.pos++];
|
|
110
|
+
}
|
|
111
|
+
rawTokens.push({ type: 'NUMBER', value: num });
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Words: functions, greek letters, or sequences of variable characters
|
|
116
|
+
if (/[a-zA-Z]/.test(ch)) {
|
|
117
|
+
let word = '';
|
|
118
|
+
while (
|
|
119
|
+
this.pos < this.input.length &&
|
|
120
|
+
/[a-zA-Z]/.test(this.input[this.pos])
|
|
121
|
+
) {
|
|
122
|
+
word += this.input[this.pos++];
|
|
123
|
+
}
|
|
124
|
+
const lower = word.toLowerCase();
|
|
125
|
+
|
|
126
|
+
if (KNOWN_FUNCTIONS.has(lower)) {
|
|
127
|
+
rawTokens.push({ type: 'FUNCTION', value: lower });
|
|
128
|
+
} else if (GREEK_LETTERS.has(lower)) {
|
|
129
|
+
rawTokens.push({ type: 'VARIABLE', value: lower });
|
|
130
|
+
} else {
|
|
131
|
+
// In school mathematics, "2ab" or "xy" means 2 * a * b or x * y
|
|
132
|
+
for (const char of word) {
|
|
133
|
+
rawTokens.push({ type: 'VARIABLE', value: char });
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// 'xx' or '·' or '*' as multiplication
|
|
140
|
+
if (ch === 'x' && this.input[this.pos + 1] === 'x') {
|
|
141
|
+
rawTokens.push({ type: 'OPERATOR', value: '*' });
|
|
142
|
+
this.pos += 2;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (ch === '·' || ch === '*') {
|
|
146
|
+
rawTokens.push({ type: 'OPERATOR', value: '*' });
|
|
147
|
+
this.pos++;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Division: '/' or ':'
|
|
152
|
+
if (ch === '/' || ch === ':') {
|
|
153
|
+
rawTokens.push({ type: 'OPERATOR', value: ch });
|
|
154
|
+
this.pos++;
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Other operators
|
|
159
|
+
if (ch === '+' || ch === '-' || ch === '^') {
|
|
160
|
+
rawTokens.push({ type: 'OPERATOR', value: ch });
|
|
161
|
+
this.pos++;
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Parentheses & brackets
|
|
166
|
+
if (ch === '(' || ch === '[') {
|
|
167
|
+
rawTokens.push({ type: 'LPAREN', value: ch });
|
|
168
|
+
this.pos++;
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
if (ch === ')' || ch === ']') {
|
|
172
|
+
rawTokens.push({ type: 'RPAREN', value: ch });
|
|
173
|
+
this.pos++;
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (ch === ',') {
|
|
178
|
+
rawTokens.push({ type: 'COMMA', value: ch });
|
|
179
|
+
this.pos++;
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Fallback: skip unrecognized characters
|
|
184
|
+
this.pos++;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Insert implicit multiplication between operands where appropriate
|
|
188
|
+
const tokens: Token[] = [];
|
|
189
|
+
for (let i = 0; i < rawTokens.length; i++) {
|
|
190
|
+
const cur = rawTokens[i];
|
|
191
|
+
tokens.push(cur);
|
|
192
|
+
|
|
193
|
+
if (i < rawTokens.length - 1) {
|
|
194
|
+
const next = rawTokens[i + 1];
|
|
195
|
+
const curEndsOperand =
|
|
196
|
+
cur.type === 'NUMBER' ||
|
|
197
|
+
cur.type === 'VARIABLE' ||
|
|
198
|
+
cur.type === 'RPAREN';
|
|
199
|
+
const nextStartsOperand =
|
|
200
|
+
next.type === 'NUMBER' ||
|
|
201
|
+
next.type === 'VARIABLE' ||
|
|
202
|
+
next.type === 'FUNCTION' ||
|
|
203
|
+
next.type === 'LPAREN';
|
|
204
|
+
|
|
205
|
+
if (curEndsOperand && nextStartsOperand) {
|
|
206
|
+
tokens.push({ type: 'OPERATOR', value: '*', implicit: true });
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
tokens.push({ type: 'EOF', value: '' });
|
|
212
|
+
return tokens;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
let nodeIdCounter = 1;
|
|
217
|
+
|
|
218
|
+
export function resetNodeIdCounter() {
|
|
219
|
+
nodeIdCounter = 1;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
class PrattParser {
|
|
223
|
+
private tokens: Token[];
|
|
224
|
+
private pos = 0;
|
|
225
|
+
|
|
226
|
+
constructor(tokens: Token[]) {
|
|
227
|
+
this.tokens = tokens;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
private current(): Token {
|
|
231
|
+
return this.tokens[this.pos];
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
private consume(expectedType?: TokenType): Token {
|
|
235
|
+
const token = this.current();
|
|
236
|
+
if (expectedType && token.type !== expectedType) {
|
|
237
|
+
throw new Error(
|
|
238
|
+
`Erwartet ${expectedType}, aber erhalten: ${token.type} (${token.value})`
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
this.pos++;
|
|
242
|
+
return token;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
parse(precedence = 0): TermNode {
|
|
246
|
+
let left = this.parsePrefix();
|
|
247
|
+
|
|
248
|
+
while (true) {
|
|
249
|
+
const token = this.current();
|
|
250
|
+
if (token.type !== 'OPERATOR') break;
|
|
251
|
+
|
|
252
|
+
const opPrec = this.getInfixPrecedence(token.value);
|
|
253
|
+
if (opPrec <= precedence) break;
|
|
254
|
+
|
|
255
|
+
this.pos++;
|
|
256
|
+
left = this.parseInfix(left, token, opPrec);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return left;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
private parsePrefix(): TermNode {
|
|
263
|
+
const token = this.current();
|
|
264
|
+
|
|
265
|
+
if (token.type === 'NUMBER') {
|
|
266
|
+
this.pos++;
|
|
267
|
+
const val = parseFloat(token.value);
|
|
268
|
+
return {
|
|
269
|
+
id: `n${nodeIdCounter++}`,
|
|
270
|
+
type: 'literal',
|
|
271
|
+
value: val,
|
|
272
|
+
raw: token.value,
|
|
273
|
+
symbol: token.value,
|
|
274
|
+
label: `Zahl ${token.value}`,
|
|
275
|
+
mathJson: val,
|
|
276
|
+
children: [],
|
|
277
|
+
depth: 0,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (token.type === 'VARIABLE') {
|
|
282
|
+
this.pos++;
|
|
283
|
+
return {
|
|
284
|
+
id: `n${nodeIdCounter++}`,
|
|
285
|
+
type: 'variable',
|
|
286
|
+
raw: token.value,
|
|
287
|
+
symbol: token.value,
|
|
288
|
+
label: `Variable ${token.value}`,
|
|
289
|
+
mathJson: token.value,
|
|
290
|
+
children: [],
|
|
291
|
+
depth: 0,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (token.type === 'FUNCTION') {
|
|
296
|
+
this.pos++;
|
|
297
|
+
const fnName = FUNCTION_MAP[token.value] || token.value;
|
|
298
|
+
let arg: TermNode;
|
|
299
|
+
|
|
300
|
+
if (this.current().type === 'LPAREN') {
|
|
301
|
+
this.consume('LPAREN');
|
|
302
|
+
arg = this.parse(0);
|
|
303
|
+
this.consume('RPAREN');
|
|
304
|
+
} else {
|
|
305
|
+
arg = this.parse(35); // higher than *, /, ^
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const symbol = token.value === 'sqrt' ? '√' : token.value;
|
|
309
|
+
|
|
310
|
+
return {
|
|
311
|
+
id: `n${nodeIdCounter++}`,
|
|
312
|
+
type: 'function',
|
|
313
|
+
op: fnName,
|
|
314
|
+
symbol,
|
|
315
|
+
label: GERMAN_LABELS[fnName] || fnName,
|
|
316
|
+
mathJson: [fnName, arg.mathJson],
|
|
317
|
+
children: [arg],
|
|
318
|
+
depth: 0,
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Unary plus or minus
|
|
323
|
+
if (
|
|
324
|
+
token.type === 'OPERATOR' &&
|
|
325
|
+
(token.value === '-' || token.value === '+')
|
|
326
|
+
) {
|
|
327
|
+
this.pos++;
|
|
328
|
+
const op = token.value;
|
|
329
|
+
const operand = this.parse(30); // Prefix unary precedence
|
|
330
|
+
|
|
331
|
+
if (op === '-') {
|
|
332
|
+
return {
|
|
333
|
+
id: `n${nodeIdCounter++}`,
|
|
334
|
+
type: 'operator',
|
|
335
|
+
isUnary: true,
|
|
336
|
+
op: 'Negate',
|
|
337
|
+
symbol: '−',
|
|
338
|
+
label: GERMAN_LABELS['Negate'],
|
|
339
|
+
mathJson: ['Negate', operand.mathJson],
|
|
340
|
+
children: [operand],
|
|
341
|
+
depth: 0,
|
|
342
|
+
};
|
|
343
|
+
} else {
|
|
344
|
+
return operand;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Parentheses
|
|
349
|
+
if (token.type === 'LPAREN') {
|
|
350
|
+
this.pos++;
|
|
351
|
+
const expr = this.parse(0);
|
|
352
|
+
this.consume('RPAREN');
|
|
353
|
+
expr.isParenthesized = true;
|
|
354
|
+
return expr;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
throw new Error(`Unerwartetes Zeichen: ${token.value || token.type}`);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
private getInfixPrecedence(op: string): number {
|
|
361
|
+
switch (op) {
|
|
362
|
+
case '+':
|
|
363
|
+
case '-':
|
|
364
|
+
return 10;
|
|
365
|
+
case '*':
|
|
366
|
+
case '/':
|
|
367
|
+
case ':':
|
|
368
|
+
return 20;
|
|
369
|
+
case '^':
|
|
370
|
+
return 40;
|
|
371
|
+
default:
|
|
372
|
+
return 0;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
private parseInfix(
|
|
377
|
+
left: TermNode,
|
|
378
|
+
token: Token,
|
|
379
|
+
precedence: number
|
|
380
|
+
): TermNode {
|
|
381
|
+
const op = token.value;
|
|
382
|
+
const isRightAssoc = op === '^';
|
|
383
|
+
const nextPrec = isRightAssoc ? precedence - 1 : precedence;
|
|
384
|
+
const right = this.parse(nextPrec);
|
|
385
|
+
|
|
386
|
+
let opName = 'Add';
|
|
387
|
+
if (op === '-') opName = 'Subtract';
|
|
388
|
+
else if (op === '*') opName = 'Multiply';
|
|
389
|
+
else if (op === '/' || op === ':') opName = 'Divide';
|
|
390
|
+
else if (op === '^') opName = 'Power';
|
|
391
|
+
|
|
392
|
+
const symbol = OPERATOR_SYMBOLS[opName] || op;
|
|
393
|
+
const label = GERMAN_LABELS[opName] || opName;
|
|
394
|
+
|
|
395
|
+
return {
|
|
396
|
+
id: `n${nodeIdCounter++}`,
|
|
397
|
+
type: 'operator',
|
|
398
|
+
op: opName,
|
|
399
|
+
symbol,
|
|
400
|
+
label,
|
|
401
|
+
implicit: token.implicit,
|
|
402
|
+
mathJson: [opName, left.mathJson, right.mathJson],
|
|
403
|
+
children: [left, right],
|
|
404
|
+
depth: 0,
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Calculates depths bottom-up:
|
|
411
|
+
* Leaves have depth 0.
|
|
412
|
+
* A parent node has depth = max(children.depth) + 1.
|
|
413
|
+
* Returns the maximum depth of the tree.
|
|
414
|
+
*/
|
|
415
|
+
export function calculateDepths(node: TermNode): number {
|
|
416
|
+
if (node.children.length === 0) {
|
|
417
|
+
node.depth = 0;
|
|
418
|
+
return 0;
|
|
419
|
+
}
|
|
420
|
+
let maxChild = 0;
|
|
421
|
+
for (const child of node.children) {
|
|
422
|
+
maxChild = Math.max(maxChild, calculateDepths(child));
|
|
423
|
+
}
|
|
424
|
+
node.depth = maxChild + 1;
|
|
425
|
+
return node.depth;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Parses an AsciiMath string into a TermNode AST with Math-JSON support.
|
|
430
|
+
*/
|
|
431
|
+
export function parseAsciiMath(input: string): TermNode {
|
|
432
|
+
resetNodeIdCounter();
|
|
433
|
+
const tokenizer = new Tokenizer(input);
|
|
434
|
+
const tokens = tokenizer.tokenize();
|
|
435
|
+
const parser = new PrattParser(tokens);
|
|
436
|
+
const root = parser.parse(0);
|
|
437
|
+
calculateDepths(root);
|
|
438
|
+
return root;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function getOperatorPrecedence(node: TermNode): number {
|
|
442
|
+
if (node.type !== 'operator') return 999;
|
|
443
|
+
if (node.isUnary) return 30;
|
|
444
|
+
switch (node.op) {
|
|
445
|
+
case 'Add':
|
|
446
|
+
case 'Subtract':
|
|
447
|
+
return 10;
|
|
448
|
+
case 'Multiply':
|
|
449
|
+
case 'Divide':
|
|
450
|
+
return 20;
|
|
451
|
+
case 'Power':
|
|
452
|
+
return 40;
|
|
453
|
+
default:
|
|
454
|
+
return 0;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
function needsParens(
|
|
459
|
+
parent: TermNode,
|
|
460
|
+
child: TermNode,
|
|
461
|
+
isLeft: boolean
|
|
462
|
+
): boolean {
|
|
463
|
+
if (child.isParenthesized) return true;
|
|
464
|
+
if (child.type !== 'operator') return false;
|
|
465
|
+
|
|
466
|
+
const pPrec = getOperatorPrecedence(parent);
|
|
467
|
+
const cPrec = getOperatorPrecedence(child);
|
|
468
|
+
|
|
469
|
+
if (cPrec < pPrec) return true;
|
|
470
|
+
if (cPrec === pPrec) {
|
|
471
|
+
// Subtraction and division are left-associative, right operand needs parentheses
|
|
472
|
+
if (!isLeft && (parent.op === 'Subtract' || parent.op === 'Divide'))
|
|
473
|
+
return true;
|
|
474
|
+
}
|
|
475
|
+
return false;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Generates LaTeX from the AST with embedded `\htmlId{...}` for KaTeX.
|
|
480
|
+
*/
|
|
481
|
+
export function astToAnnotatedLatex(node: TermNode): string {
|
|
482
|
+
if (node.type === 'literal') {
|
|
483
|
+
return `\\htmlId{${node.id}}{${node.raw}}`;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
if (node.type === 'variable') {
|
|
487
|
+
// Greek letters support (e.g. \pi, \alpha)
|
|
488
|
+
const varName = GREEK_LETTERS.has(node.symbol)
|
|
489
|
+
? `\\${node.symbol}`
|
|
490
|
+
: node.symbol;
|
|
491
|
+
return `\\htmlId{${node.id}}{${varName}}`;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
if (node.type === 'function') {
|
|
495
|
+
const childLatex = astToAnnotatedLatex(node.children[0]);
|
|
496
|
+
let fnSymbol: string;
|
|
497
|
+
if (node.op === 'Sqrt' || node.symbol === '√' || node.symbol === 'sqrt') {
|
|
498
|
+
fnSymbol = `\\sqrt{${childLatex}}`;
|
|
499
|
+
} else if (node.symbol === 'abs') {
|
|
500
|
+
fnSymbol = `\\left|${childLatex}\\right|`;
|
|
501
|
+
} else {
|
|
502
|
+
fnSymbol = `\\operatorname{${node.symbol}}\\left(${childLatex}\\right)`;
|
|
503
|
+
}
|
|
504
|
+
return `\\htmlId{${node.id}}{${fnSymbol}}`;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
if (node.type === 'operator') {
|
|
508
|
+
if (node.isUnary) {
|
|
509
|
+
const childLatex = astToAnnotatedLatex(node.children[0]);
|
|
510
|
+
return `\\htmlId{${node.id}}{-${childLatex}}`;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
const left = node.children[0];
|
|
514
|
+
const right = node.children[1];
|
|
515
|
+
|
|
516
|
+
let leftLatex = astToAnnotatedLatex(left);
|
|
517
|
+
let rightLatex = astToAnnotatedLatex(right);
|
|
518
|
+
|
|
519
|
+
if (needsParens(node, left, true)) {
|
|
520
|
+
leftLatex = `\\left(${leftLatex}\\right)`;
|
|
521
|
+
}
|
|
522
|
+
if (needsParens(node, right, false)) {
|
|
523
|
+
rightLatex = `\\left(${rightLatex}\\right)`;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
if (node.op === 'Add') {
|
|
527
|
+
return `\\htmlId{${node.id}}{${leftLatex} \\htmlId{op_${node.id}}{+} ${rightLatex}}`;
|
|
528
|
+
}
|
|
529
|
+
if (node.op === 'Subtract') {
|
|
530
|
+
return `\\htmlId{${node.id}}{${leftLatex} \\htmlId{op_${node.id}}{-} ${rightLatex}}`;
|
|
531
|
+
}
|
|
532
|
+
if (node.op === 'Multiply') {
|
|
533
|
+
// Implicit multiplication styling (e.g. 2a, 4ac, (2+a)(3-b))
|
|
534
|
+
const isImplicit =
|
|
535
|
+
node.implicit ||
|
|
536
|
+
(left.type === 'literal' &&
|
|
537
|
+
(right.type === 'variable' || right.type === 'function')) ||
|
|
538
|
+
(left.type === 'variable' && right.type === 'variable') ||
|
|
539
|
+
right.isParenthesized;
|
|
540
|
+
const opSymbol = isImplicit
|
|
541
|
+
? ''
|
|
542
|
+
: ' \\htmlId{op_' + node.id + '}{\\cdot} ';
|
|
543
|
+
return `\\htmlId{${node.id}}{${leftLatex}${opSymbol}${rightLatex}}`;
|
|
544
|
+
}
|
|
545
|
+
if (node.op === 'Divide') {
|
|
546
|
+
return `\\htmlId{${node.id}}{\\frac{${leftLatex}}{${rightLatex}}}`;
|
|
547
|
+
}
|
|
548
|
+
if (node.op === 'Power') {
|
|
549
|
+
return `\\htmlId{${node.id}}{${leftLatex}^{${rightLatex}}}`;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
return '';
|
|
554
|
+
}
|
package/src/index.ts
CHANGED
package/src/katex-css.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { css, CSSResult } from 'lit';
|
|
2
|
+
|
|
3
|
+
// language=CSS
|
|
4
|
+
export const katexStyles: CSSResult = css`
|
|
5
|
+
@font-face{font-display:block;font-family:KaTeX_AMS;font-style:normal;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_AMS-Regular.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_AMS-Regular.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_AMS-Regular.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Caligraphic;font-style:normal;font-weight:700;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Caligraphic-Bold.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Caligraphic-Bold.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Caligraphic-Bold.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Caligraphic;font-style:normal;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Caligraphic-Regular.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Caligraphic-Regular.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Caligraphic-Regular.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Fraktur;font-style:normal;font-weight:700;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Fraktur-Bold.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Fraktur-Bold.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Fraktur-Bold.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Fraktur;font-style:normal;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Fraktur-Regular.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Fraktur-Regular.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Fraktur-Regular.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Main;font-style:normal;font-weight:700;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Main-Bold.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Main-Bold.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Main-Bold.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Main;font-style:italic;font-weight:700;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Main-BoldItalic.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Main-BoldItalic.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Main-BoldItalic.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Main;font-style:italic;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Main-Italic.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Main-Italic.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Main-Italic.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Main;font-style:normal;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Main-Regular.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Main-Regular.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Main-Regular.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Math;font-style:italic;font-weight:700;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Math-BoldItalic.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Math-BoldItalic.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Math-BoldItalic.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Math;font-style:italic;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Math-Italic.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Math-Italic.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Math-Italic.ttf) format("truetype")}@font-face{font-display:block;font-family:"KaTeX_SansSerif";font-style:normal;font-weight:700;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_SansSerif-Bold.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_SansSerif-Bold.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_SansSerif-Bold.ttf) format("truetype")}@font-face{font-display:block;font-family:"KaTeX_SansSerif";font-style:italic;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_SansSerif-Italic.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_SansSerif-Italic.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_SansSerif-Italic.ttf) format("truetype")}@font-face{font-display:block;font-family:"KaTeX_SansSerif";font-style:normal;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_SansSerif-Regular.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_SansSerif-Regular.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_SansSerif-Regular.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Script;font-style:normal;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Script-Regular.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Script-Regular.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Script-Regular.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Size1;font-style:normal;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Size1-Regular.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Size1-Regular.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Size1-Regular.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Size2;font-style:normal;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Size2-Regular.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Size2-Regular.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Size2-Regular.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Size3;font-style:normal;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Size3-Regular.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Size3-Regular.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Size3-Regular.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Size4;font-style:normal;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Size4-Regular.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Size4-Regular.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Size4-Regular.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Typewriter;font-style:normal;font-weight:400;src:url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Typewriter-Regular.woff2) format("woff2"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Typewriter-Regular.woff) format("woff"),url(https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/fonts/KaTeX_Typewriter-Regular.ttf) format("truetype")}.katex{font:normal 1.21em KaTeX_Main,math,Times New Roman,serif;line-height:1.2;position:relative;text-indent:0;text-rendering:auto}.katex *{-ms-high-contrast-adjust:none!important;border-color:currentColor}.katex .katex-version:after{content:"0.19.1"}.katex .katex-mathml{border:0;-webkit-clip-path:inset(50%);clip-path:inset(50%);height:1px;overflow:hidden;padding:0;position:absolute;width:1px}.katex .katex-html>.katex-newline{display:block}.katex .katex-base{position:relative;white-space:nowrap;width:-webkit-min-content;width:-moz-min-content;width:min-content}.katex .katex-base,.katex .katex-strut{display:inline-block}.katex .textbf{font-weight:700}.katex .textit{font-style:italic}.katex .textrm{font-family:KaTeX_Main}.katex .textsf{font-family:KaTeX_SansSerif}.katex .texttt{font-family:KaTeX_Typewriter}.katex .mathnormal{font-family:KaTeX_Math;font-style:italic}.katex .mathit{font-family:KaTeX_Main;font-style:italic}.katex .mathrm{font-style:normal}.katex .mathbf{font-family:KaTeX_Main;font-weight:700}.katex .boldsymbol{font-family:KaTeX_Math;font-style:italic;font-weight:700}.katex .amsrm,.katex .mathbb,.katex .textbb{font-family:KaTeX_AMS}.katex .mathcal{font-family:KaTeX_Caligraphic}.katex .mathfrak,.katex .textfrak{font-family:KaTeX_Fraktur}.katex .mathboldfrak,.katex .textboldfrak{font-family:KaTeX_Fraktur;font-weight:700}.katex .mathtt{font-family:KaTeX_Typewriter}.katex .mathscr,.katex .textscr{font-family:KaTeX_Script}.katex .mathsf,.katex .textsf{font-family:KaTeX_SansSerif}.katex .mathboldsf,.katex .textboldsf{font-family:KaTeX_SansSerif;font-weight:700}.katex .mathitsf,.katex .mathsfit,.katex .textitsf{font-family:KaTeX_SansSerif;font-style:italic}.katex .mainrm{font-family:KaTeX_Main;font-style:normal}.katex .vlist-t{border-collapse:collapse;display:inline-table;table-layout:fixed}.katex .vlist-r{display:table-row}.katex .vlist{display:table-cell;position:relative;vertical-align:bottom}.katex .vlist>span{display:block;height:0;position:relative}.katex .vlist>span>span{display:inline-block}.katex .vlist>span>.pstrut{overflow:hidden;width:0}.katex .vlist-t2{margin-right:-2px}.katex .vlist-s{display:table-cell;font-size:1px;min-width:2px;vertical-align:bottom;width:2px}.katex .katex-vbox{align-items:baseline;display:inline-flex;flex-direction:column}.katex .katex-thinbox{display:inline-flex;flex-direction:row;max-width:0;width:0}.katex .msupsub{text-align:left}.katex .mfrac>span>span{text-align:center}.katex .mfrac .frac-line{border-bottom-style:solid;display:inline-block;width:100%}.katex .katex-hdashline,.katex .katex-hline,.katex .katex-overline .overline-line,.katex .katex-rule,.katex .katex-underline .underline-line,.katex .mfrac .frac-line{min-height:1px}.katex .mspace{display:inline-block}.katex .katex-smash{display:inline;line-height:0}.katex .clap,.katex .llap,.katex .rlap{position:relative;width:0}.katex .clap>.katex-inner,.katex .llap>.katex-inner,.katex .rlap>.katex-inner{position:absolute}.katex .clap>.katex-fix,.katex .llap>.katex-fix,.katex .rlap>.katex-fix{display:inline-block}.katex .llap>.katex-inner{right:0}.katex .clap>.katex-inner,.katex .rlap>.katex-inner{left:0}.katex .clap>.katex-inner>span{margin-left:-50%;margin-right:50%}.katex .katex-rule{border:0 solid;display:inline-block;position:relative}.katex .katex-hline,.katex .katex-overline .overline-line,.katex .katex-underline .underline-line{border-bottom-style:solid;display:inline-block;width:100%}.katex .katex-hdashline{border-bottom-style:dashed;display:inline-block;width:100%}.katex .sqrt>.katex-root{margin-left:.2777777778em;margin-right:-.5555555556em}.katex .fontsize-ensurer.reset-size1.size1,.katex .katex-sizing.reset-size1.size1{font-size:1em}.katex .fontsize-ensurer.reset-size1.size2,.katex .katex-sizing.reset-size1.size2{font-size:1.2em}.katex .fontsize-ensurer.reset-size1.size3,.katex .katex-sizing.reset-size1.size3{font-size:1.4em}.katex .fontsize-ensurer.reset-size1.size4,.katex .katex-sizing.reset-size1.size4{font-size:1.6em}.katex .fontsize-ensurer.reset-size1.size5,.katex .katex-sizing.reset-size1.size5{font-size:1.8em}.katex .fontsize-ensurer.reset-size1.size6,.katex .katex-sizing.reset-size1.size6{font-size:2em}.katex .fontsize-ensurer.reset-size1.size7,.katex .katex-sizing.reset-size1.size7{font-size:2.4em}.katex .fontsize-ensurer.reset-size1.size8,.katex .katex-sizing.reset-size1.size8{font-size:2.88em}.katex .fontsize-ensurer.reset-size1.size9,.katex .katex-sizing.reset-size1.size9{font-size:3.456em}.katex .fontsize-ensurer.reset-size1.size10,.katex .katex-sizing.reset-size1.size10{font-size:4.148em}.katex .fontsize-ensurer.reset-size1.size11,.katex .katex-sizing.reset-size1.size11{font-size:4.976em}.katex .fontsize-ensurer.reset-size2.size1,.katex .katex-sizing.reset-size2.size1{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size2.size2,.katex .katex-sizing.reset-size2.size2{font-size:1em}.katex .fontsize-ensurer.reset-size2.size3,.katex .katex-sizing.reset-size2.size3{font-size:1.1666666667em}.katex .fontsize-ensurer.reset-size2.size4,.katex .katex-sizing.reset-size2.size4{font-size:1.3333333333em}.katex .fontsize-ensurer.reset-size2.size5,.katex .katex-sizing.reset-size2.size5{font-size:1.5em}.katex .fontsize-ensurer.reset-size2.size6,.katex .katex-sizing.reset-size2.size6{font-size:1.6666666667em}.katex .fontsize-ensurer.reset-size2.size7,.katex .katex-sizing.reset-size2.size7{font-size:2em}.katex .fontsize-ensurer.reset-size2.size8,.katex .katex-sizing.reset-size2.size8{font-size:2.4em}.katex .fontsize-ensurer.reset-size2.size9,.katex .katex-sizing.reset-size2.size9{font-size:2.88em}.katex .fontsize-ensurer.reset-size2.size10,.katex .katex-sizing.reset-size2.size10{font-size:3.4566666667em}.katex .fontsize-ensurer.reset-size2.size11,.katex .katex-sizing.reset-size2.size11{font-size:4.1466666667em}.katex .fontsize-ensurer.reset-size3.size1,.katex .katex-sizing.reset-size3.size1{font-size:.7142857143em}.katex .fontsize-ensurer.reset-size3.size2,.katex .katex-sizing.reset-size3.size2{font-size:.8571428571em}.katex .fontsize-ensurer.reset-size3.size3,.katex .katex-sizing.reset-size3.size3{font-size:1em}.katex .fontsize-ensurer.reset-size3.size4,.katex .katex-sizing.reset-size3.size4{font-size:1.1428571429em}.katex .fontsize-ensurer.reset-size3.size5,.katex .katex-sizing.reset-size3.size5{font-size:1.2857142857em}.katex .fontsize-ensurer.reset-size3.size6,.katex .katex-sizing.reset-size3.size6{font-size:1.4285714286em}.katex .fontsize-ensurer.reset-size3.size7,.katex .katex-sizing.reset-size3.size7{font-size:1.7142857143em}.katex .fontsize-ensurer.reset-size3.size8,.katex .katex-sizing.reset-size3.size8{font-size:2.0571428571em}.katex .fontsize-ensurer.reset-size3.size9,.katex .katex-sizing.reset-size3.size9{font-size:2.4685714286em}.katex .fontsize-ensurer.reset-size3.size10,.katex .katex-sizing.reset-size3.size10{font-size:2.9628571429em}.katex .fontsize-ensurer.reset-size3.size11,.katex .katex-sizing.reset-size3.size11{font-size:3.5542857143em}.katex .fontsize-ensurer.reset-size4.size1,.katex .katex-sizing.reset-size4.size1{font-size:.625em}.katex .fontsize-ensurer.reset-size4.size2,.katex .katex-sizing.reset-size4.size2{font-size:.75em}.katex .fontsize-ensurer.reset-size4.size3,.katex .katex-sizing.reset-size4.size3{font-size:.875em}.katex .fontsize-ensurer.reset-size4.size4,.katex .katex-sizing.reset-size4.size4{font-size:1em}.katex .fontsize-ensurer.reset-size4.size5,.katex .katex-sizing.reset-size4.size5{font-size:1.125em}.katex .fontsize-ensurer.reset-size4.size6,.katex .katex-sizing.reset-size4.size6{font-size:1.25em}.katex .fontsize-ensurer.reset-size4.size7,.katex .katex-sizing.reset-size4.size7{font-size:1.5em}.katex .fontsize-ensurer.reset-size4.size8,.katex .katex-sizing.reset-size4.size8{font-size:1.8em}.katex .fontsize-ensurer.reset-size4.size9,.katex .katex-sizing.reset-size4.size9{font-size:2.16em}.katex .fontsize-ensurer.reset-size4.size10,.katex .katex-sizing.reset-size4.size10{font-size:2.5925em}.katex .fontsize-ensurer.reset-size4.size11,.katex .katex-sizing.reset-size4.size11{font-size:3.11em}.katex .fontsize-ensurer.reset-size5.size1,.katex .katex-sizing.reset-size5.size1{font-size:.5555555556em}.katex .fontsize-ensurer.reset-size5.size2,.katex .katex-sizing.reset-size5.size2{font-size:.6666666667em}.katex .fontsize-ensurer.reset-size5.size3,.katex .katex-sizing.reset-size5.size3{font-size:.7777777778em}.katex .fontsize-ensurer.reset-size5.size4,.katex .katex-sizing.reset-size5.size4{font-size:.8888888889em}.katex .fontsize-ensurer.reset-size5.size5,.katex .katex-sizing.reset-size5.size5{font-size:1em}.katex .fontsize-ensurer.reset-size5.size6,.katex .katex-sizing.reset-size5.size6{font-size:1.1111111111em}.katex .fontsize-ensurer.reset-size5.size7,.katex .katex-sizing.reset-size5.size7{font-size:1.3333333333em}.katex .fontsize-ensurer.reset-size5.size8,.katex .katex-sizing.reset-size5.size8{font-size:1.6em}.katex .fontsize-ensurer.reset-size5.size9,.katex .katex-sizing.reset-size5.size9{font-size:1.92em}.katex .fontsize-ensurer.reset-size5.size10,.katex .katex-sizing.reset-size5.size10{font-size:2.3044444444em}.katex .fontsize-ensurer.reset-size5.size11,.katex .katex-sizing.reset-size5.size11{font-size:2.7644444444em}.katex .fontsize-ensurer.reset-size6.size1,.katex .katex-sizing.reset-size6.size1{font-size:.5em}.katex .fontsize-ensurer.reset-size6.size2,.katex .katex-sizing.reset-size6.size2{font-size:.6em}.katex .fontsize-ensurer.reset-size6.size3,.katex .katex-sizing.reset-size6.size3{font-size:.7em}.katex .fontsize-ensurer.reset-size6.size4,.katex .katex-sizing.reset-size6.size4{font-size:.8em}.katex .fontsize-ensurer.reset-size6.size5,.katex .katex-sizing.reset-size6.size5{font-size:.9em}.katex .fontsize-ensurer.reset-size6.size6,.katex .katex-sizing.reset-size6.size6{font-size:1em}.katex .fontsize-ensurer.reset-size6.size7,.katex .katex-sizing.reset-size6.size7{font-size:1.2em}.katex .fontsize-ensurer.reset-size6.size8,.katex .katex-sizing.reset-size6.size8{font-size:1.44em}.katex .fontsize-ensurer.reset-size6.size9,.katex .katex-sizing.reset-size6.size9{font-size:1.728em}.katex .fontsize-ensurer.reset-size6.size10,.katex .katex-sizing.reset-size6.size10{font-size:2.074em}.katex .fontsize-ensurer.reset-size6.size11,.katex .katex-sizing.reset-size6.size11{font-size:2.488em}.katex .fontsize-ensurer.reset-size7.size1,.katex .katex-sizing.reset-size7.size1{font-size:.4166666667em}.katex .fontsize-ensurer.reset-size7.size2,.katex .katex-sizing.reset-size7.size2{font-size:.5em}.katex .fontsize-ensurer.reset-size7.size3,.katex .katex-sizing.reset-size7.size3{font-size:.5833333333em}.katex .fontsize-ensurer.reset-size7.size4,.katex .katex-sizing.reset-size7.size4{font-size:.6666666667em}.katex .fontsize-ensurer.reset-size7.size5,.katex .katex-sizing.reset-size7.size5{font-size:.75em}.katex .fontsize-ensurer.reset-size7.size6,.katex .katex-sizing.reset-size7.size6{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size7.size7,.katex .katex-sizing.reset-size7.size7{font-size:1em}.katex .fontsize-ensurer.reset-size7.size8,.katex .katex-sizing.reset-size7.size8{font-size:1.2em}.katex .fontsize-ensurer.reset-size7.size9,.katex .katex-sizing.reset-size7.size9{font-size:1.44em}.katex .fontsize-ensurer.reset-size7.size10,.katex .katex-sizing.reset-size7.size10{font-size:1.7283333333em}.katex .fontsize-ensurer.reset-size7.size11,.katex .katex-sizing.reset-size7.size11{font-size:2.0733333333em}.katex .fontsize-ensurer.reset-size8.size1,.katex .katex-sizing.reset-size8.size1{font-size:.3472222222em}.katex .fontsize-ensurer.reset-size8.size2,.katex .katex-sizing.reset-size8.size2{font-size:.4166666667em}.katex .fontsize-ensurer.reset-size8.size3,.katex .katex-sizing.reset-size8.size3{font-size:.4861111111em}.katex .fontsize-ensurer.reset-size8.size4,.katex .katex-sizing.reset-size8.size4{font-size:.5555555556em}.katex .fontsize-ensurer.reset-size8.size5,.katex .katex-sizing.reset-size8.size5{font-size:.625em}.katex .fontsize-ensurer.reset-size8.size6,.katex .katex-sizing.reset-size8.size6{font-size:.6944444444em}.katex .fontsize-ensurer.reset-size8.size7,.katex .katex-sizing.reset-size8.size7{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size8.size8,.katex .katex-sizing.reset-size8.size8{font-size:1em}.katex .fontsize-ensurer.reset-size8.size9,.katex .katex-sizing.reset-size8.size9{font-size:1.2em}.katex .fontsize-ensurer.reset-size8.size10,.katex .katex-sizing.reset-size8.size10{font-size:1.4402777778em}.katex .fontsize-ensurer.reset-size8.size11,.katex .katex-sizing.reset-size8.size11{font-size:1.7277777778em}.katex .fontsize-ensurer.reset-size9.size1,.katex .katex-sizing.reset-size9.size1{font-size:.2893518519em}.katex .fontsize-ensurer.reset-size9.size2,.katex .katex-sizing.reset-size9.size2{font-size:.3472222222em}.katex .fontsize-ensurer.reset-size9.size3,.katex .katex-sizing.reset-size9.size3{font-size:.4050925926em}.katex .fontsize-ensurer.reset-size9.size4,.katex .katex-sizing.reset-size9.size4{font-size:.462962963em}.katex .fontsize-ensurer.reset-size9.size5,.katex .katex-sizing.reset-size9.size5{font-size:.5208333333em}.katex .fontsize-ensurer.reset-size9.size6,.katex .katex-sizing.reset-size9.size6{font-size:.5787037037em}.katex .fontsize-ensurer.reset-size9.size7,.katex .katex-sizing.reset-size9.size7{font-size:.6944444444em}.katex .fontsize-ensurer.reset-size9.size8,.katex .katex-sizing.reset-size9.size8{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size9.size9,.katex .katex-sizing.reset-size9.size9{font-size:1em}.katex .fontsize-ensurer.reset-size9.size10,.katex .katex-sizing.reset-size9.size10{font-size:1.2002314815em}.katex .fontsize-ensurer.reset-size9.size11,.katex .katex-sizing.reset-size9.size11{font-size:1.4398148148em}.katex .fontsize-ensurer.reset-size10.size1,.katex .katex-sizing.reset-size10.size1{font-size:.2410800386em}.katex .fontsize-ensurer.reset-size10.size2,.katex .katex-sizing.reset-size10.size2{font-size:.2892960463em}.katex .fontsize-ensurer.reset-size10.size3,.katex .katex-sizing.reset-size10.size3{font-size:.337512054em}.katex .fontsize-ensurer.reset-size10.size4,.katex .katex-sizing.reset-size10.size4{font-size:.3857280617em}.katex .fontsize-ensurer.reset-size10.size5,.katex .katex-sizing.reset-size10.size5{font-size:.4339440694em}.katex .fontsize-ensurer.reset-size10.size6,.katex .katex-sizing.reset-size10.size6{font-size:.4821600771em}.katex .fontsize-ensurer.reset-size10.size7,.katex .katex-sizing.reset-size10.size7{font-size:.5785920926em}.katex .fontsize-ensurer.reset-size10.size8,.katex .katex-sizing.reset-size10.size8{font-size:.6943105111em}.katex .fontsize-ensurer.reset-size10.size9,.katex .katex-sizing.reset-size10.size9{font-size:.8331726133em}.katex .fontsize-ensurer.reset-size10.size10,.katex .katex-sizing.reset-size10.size10{font-size:1em}.katex .fontsize-ensurer.reset-size10.size11,.katex .katex-sizing.reset-size10.size11{font-size:1.1996142719em}.katex .fontsize-ensurer.reset-size11.size1,.katex .katex-sizing.reset-size11.size1{font-size:.2009646302em}.katex .fontsize-ensurer.reset-size11.size2,.katex .katex-sizing.reset-size11.size2{font-size:.2411575563em}.katex .fontsize-ensurer.reset-size11.size3,.katex .katex-sizing.reset-size11.size3{font-size:.2813504823em}.katex .fontsize-ensurer.reset-size11.size4,.katex .katex-sizing.reset-size11.size4{font-size:.3215434084em}.katex .fontsize-ensurer.reset-size11.size5,.katex .katex-sizing.reset-size11.size5{font-size:.3617363344em}.katex .fontsize-ensurer.reset-size11.size6,.katex .katex-sizing.reset-size11.size6{font-size:.4019292605em}.katex .fontsize-ensurer.reset-size11.size7,.katex .katex-sizing.reset-size11.size7{font-size:.4823151125em}.katex .fontsize-ensurer.reset-size11.size8,.katex .katex-sizing.reset-size11.size8{font-size:.578778135em}.katex .fontsize-ensurer.reset-size11.size9,.katex .katex-sizing.reset-size11.size9{font-size:.6945337621em}.katex .fontsize-ensurer.reset-size11.size10,.katex .katex-sizing.reset-size11.size10{font-size:.8336012862em}.katex .fontsize-ensurer.reset-size11.size11,.katex .katex-sizing.reset-size11.size11{font-size:1em}.katex .delimsizing.size1{font-family:KaTeX_Size1}.katex .delimsizing.size2{font-family:KaTeX_Size2}.katex .delimsizing.size3{font-family:KaTeX_Size3}.katex .delimsizing.size4{font-family:KaTeX_Size4}.katex .delimsizing.mult .delim-size1>span{font-family:KaTeX_Size1}.katex .delimsizing.mult .delim-size4>span{font-family:KaTeX_Size4}.katex .nulldelimiter{display:inline-block;width:.12em}.katex .delimcenter,.katex .op-symbol{position:relative}.katex .op-symbol.small-op{font-family:KaTeX_Size1}.katex .op-symbol.large-op{font-family:KaTeX_Size2}.katex .katex-accent>.vlist-t,.katex .op-limits>.vlist-t{text-align:center}.katex .katex-accent .accent-body{position:relative}.katex .katex-accent .accent-body:not(.accent-full){width:0}.katex .katex-overlay{display:block}.katex .mtable .vertical-separator{display:inline-block;min-width:1px}.katex .mtable .arraycolsep{display:inline-block}.katex .mtable .col-align-c>.vlist-t{text-align:center}.katex .mtable .col-align-l>.vlist-t{text-align:left}.katex .mtable .col-align-r>.vlist-t{text-align:right}.katex .svg-align{text-align:left}.katex svg{fill:currentColor;stroke:currentColor;display:block;height:inherit;position:absolute;width:100%}.katex svg path{stroke:none}.katex svg{fill-rule:nonzero;fill-opacity:1;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1}.katex img{border-style:none;max-height:none;max-width:none;min-height:0;min-width:0}.katex .katex-stretchy{display:block;overflow:hidden;position:relative;width:100%}.katex .katex-stretchy:after,.katex .katex-stretchy:before{content:""}.katex .hide-tail{overflow:hidden;position:relative;width:100%}.katex .halfarrow-left{left:0;overflow:hidden;position:absolute;width:50.2%}.katex .halfarrow-right{overflow:hidden;position:absolute;right:0;width:50.2%}.katex .brace-left{left:0;overflow:hidden;position:absolute;width:25.1%}.katex .brace-center{left:25%;overflow:hidden;position:absolute;width:50%}.katex .brace-right{overflow:hidden;position:absolute;right:0;width:25.1%}.katex .x-arrow-pad{padding:0 .5em}.katex .cd-arrow-pad{padding:0 .55556em 0 .27778em}.katex .mover,.katex .munder,.katex .x-arrow{text-align:center}.katex .boxpad{padding:0 .3em}.katex .fbox,.katex .fcolorbox{border:.04em solid;box-sizing:border-box}.katex .cancel-pad{padding:0 .2em}.katex .cancel-lap{margin-left:-.2em;margin-right:-.2em}.katex .katex-sout{border-bottom-style:solid;border-bottom-width:.08em}.katex .angl{border-right:.049em solid;border-top:.049em solid;box-sizing:border-box;margin-right:.03889em}.katex .anglpad{padding:0 .03889em}.katex .reflectbox{display:inline-block;transform:scaleX(-1)}.katex .eqn-num:before{content:"(" counter(katexEqnNo) ")";counter-increment:katexEqnNo}.katex .mml-eqn-num:before{content:"(" counter(mmlEqnNo) ")";counter-increment:mmlEqnNo}.katex .mtr-glue{width:50%}.katex .cd-vert-arrow{display:inline-block;position:relative}.katex .cd-label-left{display:inline-block;position:absolute;right:calc(50% + .3em);text-align:left}.katex .cd-label-right{display:inline-block;left:calc(50% + .3em);position:absolute;text-align:right}.katex-display{display:block;margin:1em 0;text-align:center}.katex-display>.katex{display:block;text-align:center;white-space:nowrap}.katex-display>.katex>.katex-html{display:block;position:relative}.katex-display>.katex>.katex-html>.katex-tag{position:absolute;right:0}.katex-display.leqno>.katex>.katex-html>.katex-tag{left:0;right:auto}.katex-display.fleqn>.katex{padding-left:2em;text-align:left}body{counter-reset:katexEqnNo mmlEqnNo}
|
|
6
|
+
|
|
7
|
+
`;
|
package/src/model.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export type NodeType = 'literal' | 'variable' | 'operator' | 'function';
|
|
2
|
+
|
|
3
|
+
export interface TermNode {
|
|
4
|
+
id: string;
|
|
5
|
+
type: NodeType;
|
|
6
|
+
op?: string;
|
|
7
|
+
symbol: string;
|
|
8
|
+
label: string;
|
|
9
|
+
raw?: string;
|
|
10
|
+
value?: number;
|
|
11
|
+
isUnary?: boolean;
|
|
12
|
+
isParenthesized?: boolean;
|
|
13
|
+
implicit?: boolean;
|
|
14
|
+
mathJson: any;
|
|
15
|
+
children: TermNode[];
|
|
16
|
+
depth: number;
|
|
17
|
+
x?: number;
|
|
18
|
+
y?: number;
|
|
19
|
+
width?: number;
|
|
20
|
+
height?: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface TreeEdge {
|
|
24
|
+
fromNodeId: string;
|
|
25
|
+
toNodeId: string;
|
|
26
|
+
fromX: number;
|
|
27
|
+
fromY: number;
|
|
28
|
+
toX: number;
|
|
29
|
+
toY: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const GERMAN_LABELS: Record<string, string> = {
|
|
33
|
+
Add: 'Summe',
|
|
34
|
+
Subtract: 'Differenz',
|
|
35
|
+
Multiply: 'Produkt',
|
|
36
|
+
Divide: 'Quotient',
|
|
37
|
+
Power: 'Potenz',
|
|
38
|
+
Negate: 'Gegenzahl (Negation)',
|
|
39
|
+
Sqrt: 'Quadratwurzel',
|
|
40
|
+
Sin: 'Sinus',
|
|
41
|
+
Cos: 'Kosinus',
|
|
42
|
+
Tan: 'Tangens',
|
|
43
|
+
Cot: 'Kotangens',
|
|
44
|
+
Ln: 'Natürlicher Logarithmus',
|
|
45
|
+
Log: 'Logarithmus',
|
|
46
|
+
Abs: 'Betrag',
|
|
47
|
+
Exp: 'Exponentialfunktion',
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const OPERATOR_SYMBOLS: Record<string, string> = {
|
|
51
|
+
Add: '+',
|
|
52
|
+
Subtract: '−',
|
|
53
|
+
Multiply: '·',
|
|
54
|
+
Divide: ':',
|
|
55
|
+
Power: '^',
|
|
56
|
+
Negate: '−',
|
|
57
|
+
};
|