(
expression: AnyParseNode[],
options: Options,
isRealGroup: boolean | "root",
surrounding: [DomType | null | undefined, DomType | null | undefined] = [null, null],
)
| 57 | * consisting type of nodes that will be added to the left and right. |
| 58 | */ |
| 59 | export const buildExpression = function( |
| 60 | expression: AnyParseNode[], |
| 61 | options: Options, |
| 62 | isRealGroup: boolean | "root", |
| 63 | surrounding: [DomType | null | undefined, DomType | null | undefined] = [null, null], |
| 64 | ): HtmlDomNode[] { |
| 65 | // Parse expressions into `groups`. |
| 66 | const groups: HtmlDomNode[] = []; |
| 67 | for (let i = 0; i < expression.length; i++) { |
| 68 | const output = buildGroup(expression[i], options); |
| 69 | if (output instanceof DocumentFragment) { |
| 70 | const children: ReadonlyArray<HtmlDomNode> = output.children; |
| 71 | groups.push(...children); |
| 72 | } else { |
| 73 | groups.push(output); |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | // Combine consecutive domTree.symbolNodes into a single symbolNode. |
| 78 | tryCombineChars(groups); |
| 79 | |
| 80 | // If `expression` is a partial group, let the parent handle spacings |
| 81 | // to avoid processing groups multiple times. |
| 82 | if (!isRealGroup) { |
| 83 | return groups; |
| 84 | } |
| 85 | |
| 86 | let glueOptions = options; |
| 87 | if (expression.length === 1) { |
| 88 | const node = expression[0]; |
| 89 | if (node.type === "sizing") { |
| 90 | glueOptions = options.havingSize(node.size); |
| 91 | } else if (node.type === "styling") { |
| 92 | glueOptions = options.havingStyle(styleMap[node.style]); |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | // Dummy spans for determining spacings between surrounding atoms. |
| 97 | // If `expression` has no atoms on the left or right, class "leftmost" |
| 98 | // or "rightmost", respectively, is used to indicate it. |
| 99 | const dummyPrev = makeSpan([surrounding[0] || "leftmost"], [], options); |
| 100 | const dummyNext = makeSpan([surrounding[1] || "rightmost"], [], options); |
| 101 | |
| 102 | // TODO: These code assumes that a node's math class is the first element |
| 103 | // of its `classes` array. A later cleanup should ensure this, for |
| 104 | // instance by changing the signature of `makeSpan`. |
| 105 | |
| 106 | // Before determining what spaces to insert, perform bin cancellation. |
| 107 | // Binary operators change to ordinary symbols in some contexts. |
| 108 | const isRoot = (isRealGroup === "root"); |
| 109 | traverseNonSpaceNodes(groups, (node, prev): void => { |
| 110 | const prevType = prev.classes[0]; |
| 111 | const type = node.classes[0]; |
| 112 | if (prevType === "mbin" && binRightCanceller.has(type)) { |
| 113 | prev.classes[0] = "mord"; |
| 114 | } else if (type === "mbin" && binLeftCanceller.has(prevType)) { |
| 115 | node.classes[0] = "mord"; |
| 116 | } |
no test coverage detected
searching dependent graphs…