import {NonAtoms} from "./atoms"; import ParseError from "./ParseError"; import type {AnyParseNode, NodeType, ParseNode, SymbolParseNode} from "./types/nodes"; /** * Asserts that the node is of the given type and returns it with stricter * typing. Throws if the node's type does not match. */ export function assertNodeType( node: AnyParseNode | null | undefined, type: NODETYPE, ): ParseNode { if (!node || node.type !== type) { throw new Error( `Expected node of type ${type}, but got ` + (node ? `node of type ${node.type}` : String(node))); } return node as ParseNode; } /** * Returns the node more strictly typed iff it is of the given type. Otherwise, * returns null. */ export function assertSymbolNodeType(node: AnyParseNode): SymbolParseNode { const typedNode = checkSymbolNodeType(node); if (!typedNode) { throw new Error( `Expected node of symbol group type, but got ` + (node ? `node of type ${node.type}` : String(node))); } return typedNode; } /** * Returns the node more strictly typed if it is of the given type. Otherwise, * returns null. */ export function checkSymbolNodeType(node: AnyParseNode): SymbolParseNode | null { if (node.type === "atom" || NonAtoms.has(node.type)) { return node as SymbolParseNode; } return null; } /** * Returns the string spelled out by a group of plain characters, throwing the * given ParseError if the group holds anything else. With allowSpaces, a * literal space counts as a character; `~` and `\ ` do not. */ export function assertCharacterGroup( group: ParseNode<"ordgroup">, errorMessage: string, allowSpaces?: boolean, ): string { let text = ""; for (const node of group.body) { if (node.type === "textord") { text += node.text; } else if (allowSpaces && node.type === "spacing" && node.text === " ") { text += " "; } else { throw new ParseError(errorMessage, group); } } return text; }