A world-class math input for the web
1import { CaretNode, h, t, TokensTag, VNode } from "@caret-js/core";
2import { FunctionCallNode } from "./functionCall";
3import { FunctionDefinitionNode } from "./functionDefinition";
4import { VariableNode } from "./variable";
5
6export class EquationNode extends CaretNode {
7 constructor(public expressions: CaretNode[]) {
8 super();
9 }
10
11 static from(expressions: CaretNode[]): EquationNode | FunctionDefinitionNode {
12 const flattenedExpressions: CaretNode[] = expressions.flatMap((node) =>
13 node instanceof EquationNode
14 ? node.expressions
15 : node instanceof FunctionDefinitionNode
16 ? [new FunctionCallNode(node.name, node.args), node.body]
17 : [node]
18 );
19
20 if (flattenedExpressions.length === 2) {
21 if (flattenedExpressions[0] instanceof FunctionCallNode) {
22 const funcCall = flattenedExpressions[0] as FunctionCallNode;
23 const name = funcCall.name;
24 const args = funcCall.args;
25 if (args.every((arg) => arg instanceof VariableNode)) {
26 const body = flattenedExpressions[1];
27 return FunctionDefinitionNode.from(
28 name,
29 args as VariableNode[],
30 body
31 ).addTag(
32 new TokensTag([...(funcCall.getTag(TokensTag)?.ownTokens ?? [])])
33 );
34 }
35 }
36 }
37
38 return new EquationNode(flattenedExpressions).mergeTagsFromNodes(
39 expressions.filter(
40 (node) =>
41 node instanceof EquationNode || node instanceof FunctionDefinitionNode
42 )
43 );
44 }
45
46 toDebugMathML(): VNode {
47 return h(
48 "mrow",
49 {},
50 ...this.expressions.flatMap((expr, index) => [
51 expr.toDebugMathML(),
52 index < this.expressions.length - 1 ? h("mo", {}, t("=")) : null,
53 ])
54 );
55 }
56}