A world-class math input for the web
at main 56 lines 1.8 kB view raw
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}