Documentclass#
The editable LaTeX document tree — the working format you read, mutate, serialize, and transform.
Reads go through read-only Node handles; edits are validated eagerly and throw TexformEditError on misuse, so no internal failure ever corrupts the tree. A tree that Document.hasErrors is read-only and fixed that way at construction: every editing method then throws.
Document is a live WASM-backed class instance, not plain data. Documents
share an immutable KnowledgeBase with their parser or engine. Transform accepts any complete document with the same knowledge-base identity.
import { Document } from 'texform';
const doc = new Document();
doc.toLatex(); // ''Construction and copying#
Document#
Document(options: { knowledgeBase?: KnowledgeBase; mode?: RuntimeContentMode; } | undefined)Construct an empty math-mode document holding a single empty root.
This is a complete tree (hasErrors() is false) — the same legal state
an empty parse produces. The document is editable and serializable, and it
shares the default KnowledgeBase unless one is supplied.
| Parameter | Type |
|---|---|
options | { knowledge |
fromSyntax#
fromSyntax( node: SyntaxNode, options: { knowledgeBase?: KnowledgeBase } | undefined,): DocumentBuild a document from a SyntaxNode snapshot.
Invalid external syntax is rejected rather than corrupting the tree.
fromSyntax and Document.toSyntax are symmetric over every node
kind, including Error and Prime. A bare Prime is a symbol, not a
shorthand superscript. The imported document is
bound to the supplied KnowledgeBase or the shared default.
Throws TexformConformanceError if the snapshot does not conform to the knowledge base.
| Parameter | Type | Description |
|---|---|---|
node | Syntax |
|
options | { knowledge | — |
Document — The reconstructed editable document.
import { Document, Parser } from 'texform';
const result = new Parser().parse(String.raw`\frac{x}{y}`);
if (!result.document) throw new Error('parse failed');
const syntax = result.document.toSyntax();
const doc = Document.fromSyntax(syntax);Queries#
root#
root(): NodeReturn the root Node of the tree.
The root is unique and parentless; it is the document's top-level container
node — a Root node, not a Group — and its children are the top-level
content.
Node — The root node handle.
const doc = new Parser().parse(String.raw`\frac{x}{y}`).document;
doc.root().kind; // 'root'hasErrors#
hasErrors(): booleanWhether the tree contains any Error placeholder node.
This is a cheap O(1) signal, independent of the ParseConfig.abortOnError parse-strictness knob and separate from structural validity. A tree that has errors is read-only.
boolean — true if any Error node is present.
new Parser().parse(String.raw`\sqrt[`).document.hasErrors(); // trueisReadOnly#
isReadOnly(): booleanWhether the document rejects edits.
Read-only-ness is fixed at construction and is equivalent to Document.hasErrors: a tree containing error nodes cannot be edited, so its error count cannot change.
boolean — true if every editing method will throw.
errors#
errors(): Node[]Return the Error placeholder Node handles in the tree.
Node[] — An array of the Error nodes; empty when hasErrors() is false.
findCommands#
findCommands(name: string): Node[]Return every command Node in the tree whose name equals name.
| Parameter | Type | Description |
|---|---|---|
name | string |
|
Node[] — The matching command node handles.
const doc = new Parser().parse(String.raw`\frac{x}{y} + \frac{a}{b}`).document;
doc.findCommands('frac').length; // 2findEnvironments#
findEnvironments(name: string): Node[]Return every environment Node in the tree whose name equals name.
| Parameter | Type | Description |
|---|---|---|
name | string |
|
Node[] — The matching environment node handles.
nodeSpans#
nodeSpans(): NodeSpanEntry[]Export the parse-time span side table as a list of {id, span} entries.
Ids follow the parser's tree-path scheme rooted at root: .child.N for
container children, .arg.N.content for content-carrying argument slots,
.left / .right for infix operands, .body for environment bodies, and
.base / .sub / .sup for script slots. Nodes without a recorded span
are omitted. Spans reflect the original parse and are not updated by edits.
NodeSpanEntry[] — The span entries in tree order.
nodeAt#
nodeAt(path: string): NodeResolve a path to a node handle. Paths are rooted and use the scheme of Node.path; edits shift them, so use paths read from the current tree.
Throws TexformEditError if the path does not exist.
| Parameter | Type |
|---|---|
path | string |
knowledgeBase#
knowledgeBase(): KnowledgeBaseThe immutable knowledge base bound to this document. Construction and edits are checked against it; toLatex is not.
Output#
toLatex#
toLatex(options: SerializeOptions | null | undefined): stringSerialize the tree back to LaTeX text.
The serializer guarantees text idempotency: re-parsing and re-serializing
the output yields the same string. Error nodes round-trip their captured
source snippet verbatim, and pure prime superscripts serialize compactly as
f' or f''. There is intentionally no method named serialize on
Document. For the output styles, see the Serialization guide and
SerializeOptions.
| Parameter | Type | Description |
|---|---|---|
options | Serialize |
|
string — The serialized LaTeX string.
const doc = new Parser().parse(String.raw`x^2`).document;
doc.toLatex(); // 'x ^ { 2 }'
doc.toLatex({ style: 'compact' }); // 'x^2'toTokenizedLatex#
toTokenizedLatex(options: SerializeOptions | null | undefined): TokenizedLatexSerialize the tree to LaTeX together with typed output tokens.
Token spans use UTF-8 byte offsets, not JavaScript UTF-16 indices. Empty error snippets produce no zero-width token; use Document.hasErrors to detect whether the document contains error nodes.
| Parameter | Type | Description |
|---|---|---|
options | Serialize |
|
TokenizedLatex — Serialized LaTeX plus typed fragments from the same traversal.
const tok = new Parser().parse('x^2').document!.toTokenizedLatex();
tok.latex; // 'x ^ { 2 }'
tok.tokens[0].kind; // 'character'toSyntax#
toSyntax(): SyntaxNodeConvert the tree to a SyntaxNode object for serde and transport.
This is the structured-data channel, distinct from the LaTeX text channel Document.toLatex.
SyntaxNode — The lossless snapshot of the tree.
doc.toSyntax(); // { Root: { ... } }toColumnar#
toColumnar(): ColumnarTreeFlatten the tree into columns for bulk structural analysis with Arrow or DataFrame tools. Modes describe node contexts. Missing indices are -1; other missing values are null. Detached subtrees are excluded. Error documents are supported.
Staging constructors#
The create* methods, parseFragment, cloneNode, and importNode build detached subtrees owned by this document. A staged node is not in the tree until you attach it with an edit method.
createChar#
createChar( value: string, options: ConstructionOptions | undefined,): NodeCreate a detached single-character node owned by this document.
The node is not in the tree until attached with an edit method such as
Document.appendChild. Every create* method takes options.mode to construct in another context; see ConstructionOptions for the defaults.
Throws TexformConformanceError if the character cannot be
written in that mode, such as \, ^, ~, or a math-mode space, and
TexformEditError if the document is read-only.
| Parameter | Type | Description |
|---|---|---|
value | string |
|
options | Construction | — |
Node — The detached node handle.
createText#
createText( value: string, options: ConstructionOptions | undefined,): NodeCreate a detached text node. Throws TexformConformanceError if the text cannot be written in the mode.
| Parameter | Type |
|---|---|
value | string |
options | Construction |
createActiveSpace#
createActiveSpace(options: ConstructionOptions | undefined): NodeCreate a detached active-space node.
| Parameter | Type |
|---|---|
options | Construction |
createGroup#
createGroup( mode: RuntimeContentMode, children: (Node | string)[] | undefined, options: ConstructionOptions | undefined,): NodeCreate a detached brace group built in its own mode.
Throws TexformParseError for source that does not parse cleanly, TexformConformanceError for a child built in another mode or an infix with siblings, and TexformEditError for an attached, foreign, or repeated child.
| Parameter | Type | Description |
|---|---|---|
mode | Runtime |
|
children | (Node | |
|
options | Construction | — |
const group = doc.createGroup('math', ['x^2', doc.createChar('y')]);createCommand#
createCommand( name: string, args: Arg[] | null | undefined, options: ConstructionOptions | undefined,): NodeCreate a detached prefix command.
Throws TexformConformanceError if the name is not a prefix command (the message names the right constructor, such as createDeclarative for bf), the argument count is wrong, or an argument does not fit its slot; TexformParseError for invalid source arguments.
| Parameter | Type | Description |
|---|---|---|
name | string |
|
args | Arg[ |
|
options | Construction | — |
doc.appendChild(doc.root(), doc.createCommand('sqrt', ['x']));
doc.toLatex(); // '\\sqrt { x }'createDeclarative#
createDeclarative( name: string, args: Arg[] | null | undefined, options: ConstructionOptions | undefined,): NodeCreate a detached declarative command such as \bf. Same conditions as Document.createCommand, except the record must be declarative.
| Parameter | Type |
|---|---|
name | string |
args | Arg[ |
options | Construction |
createEnvironment#
createEnvironment( name: string, args: Arg[] | null | undefined, body: Node | string | (Node | string)[] | null | undefined, options: ConstructionOptions | undefined,): NodeCreate a detached environment.
Throws TexformConformanceError if an argument does not fit the signature or the body is not a group in the body mode, and TexformParseError for invalid source.
| Parameter | Type | Description |
|---|---|---|
name | string |
|
args | Arg[ |
|
body | Node | |
|
options | Construction | — |
createAlignmentTab#
createAlignmentTab(options: ConstructionOptions | undefined): NodeCreate a detached unescaped & cell separator. Use createChar("&") for a literal ampersand.
| Parameter | Type |
|---|---|
options | Construction |
createDelimitedGroup#
createDelimitedGroup( left: string, right: string, children: (Node | string)[] | undefined, options: ConstructionOptions | undefined,): NodeCreate a detached \left...\right group, built in math mode by default.
Throws TexformConformanceError for a delimiter that is neither . nor registered in the knowledge base, plus the conditions of createGroup.
| Parameter | Type | Description |
|---|---|---|
left | string |
|
right | string |
|
children | (Node | |
|
options | Construction | — |
createInlineMath#
createInlineMath( children: (Node | string)[] | undefined, options: ConstructionOptions | undefined,): NodeCreate a detached $...$ group of math children, in a text context by default.
Same failure conditions as createGroup.
| Parameter | Type | Description |
|---|---|---|
children | (Node | |
|
options | Construction | — |
createScripted#
createScripted( base: Node | string, sub: Node | string | null | undefined, sup: Node | string | null | undefined, options: ConstructionOptions | undefined,): NodeCreate a detached scripted node, built in math mode by default.
Throws TexformConformanceError if both scripts are absent or the base is a scripted node, an infix, or an alignment tab, and TexformParseError for invalid source.
| Parameter | Type | Description |
|---|---|---|
base | Node | |
|
sub | Node | |
|
sup | Node | |
|
options | Construction | — |
doc.appendChild(doc.root(), doc.createScripted('x', null, '2'));createPrime#
createPrime( count: number, options: ConstructionOptions | undefined,): NodeCreate a detached run of count primes, built in math mode by default.
Throws TexformConformanceError if count is not positive.
| Parameter | Type |
|---|---|
count | number |
options | Construction |
createInfix#
createInfix( name: string, left: Node | string, right: Node | string, args: Arg[] | null | undefined, options: ConstructionOptions | undefined,): NodeCreate a detached infix command such as \over, built in math mode by default.
Throws TexformConformanceError under the conditions of createCommand, except the record must be infix.
| Parameter | Type | Description |
|---|---|---|
name | string | — |
left | Node | |
|
right | Node | |
|
args | Arg[ |
|
options | Construction | — |
parseFragment#
parseFragment( source: string, options: ConstructionOptions | undefined,): NodeParse source into a detached implicit group, in options.mode or the root mode.
Throws TexformParseError with the diagnostics if the source does not parse cleanly.
| Parameter | Type |
|---|---|
source | string |
options | Construction |
cloneNode#
cloneNode(node: Node): NodeDeep-copy a subtree of this document as a detached node.
| Parameter | Type |
|---|---|
node | Node |
importNode#
importNode(node: Node): NodeCopy a subtree from another document into this one as a detached node, validating it against this document's knowledge base.
Throws TexformConformanceError if the subtree does not conform to this knowledge base.
| Parameter | Type |
|---|---|
node | Node |
Edit methods#
All edits are validated eagerly and throw TexformEditError on misuse. Nodes must belong to this document, the root cannot be detached, and a tree that hasErrors() is read-only.
appendChild#
appendChild(parent: Node, child: Node): voidAppend child as the last child of parent.
Throws TexformEditError if the document is read-only,
either node is foreign or missing, parent is not a container, or the move
would create a cycle.
| Parameter | Type | Description |
|---|---|---|
parent | Node |
|
child | Node |
|
insertChild#
insertChild(parent: Node, index: number, child: Node): voidInsert child at position index among parent's children.
Throws TexformEditError if the document is read-only,
either node is foreign or missing, parent is not a container, index is
out of range, or the move would create a cycle.
| Parameter | Type | Description |
|---|---|---|
parent | Node |
|
index | number |
|
child | Node |
|
insertBefore#
insertBefore(anchor: Node, node: Node): voidInsert node immediately before the sibling anchor.
Throws TexformEditError if the document is read-only,
either node is foreign or missing, anchor has no parent (such as the
root), or the move would create a cycle.
| Parameter | Type | Description |
|---|---|---|
anchor | Node |
|
node | Node |
|
insertAfter#
insertAfter(anchor: Node, node: Node): voidInsert node immediately after the sibling anchor.
Same failure conditions as Document.insertBefore.
| Parameter | Type | Description |
|---|---|---|
anchor | Node |
|
node | Node |
|
replaceWith#
replaceWith(target: Node, replacement: Node): voidReplace target in place with replacement.
Throws TexformEditError if the document is read-only,
either node is foreign or missing, target is the root, or the move would
create a cycle.
| Parameter | Type | Description |
|---|---|---|
target | Node |
|
replacement | Node |
|
wrap#
wrap(target: Node, wrapper: Node): NodeWrap target inside the container wrapper.
wrapper takes target's place in the tree and target becomes its
child.
Throws TexformEditError if the document is read-only,
either node is foreign or missing, wrapper is not a container, or
target is the root.
| Parameter | Type | Description |
|---|---|---|
target | Node |
|
wrapper | Node |
|
Node — The wrapper node, now positioned in the tree.
unwrap#
unwrap(group: Node): Node[]Unwrap a group, splicing its children into its parent in place.
Throws TexformEditError if the document is read-only, or
group is foreign, missing, not a group, or the root.
| Parameter | Type | Description |
|---|---|---|
group | Node |
|
Node[] — The freed child node handles, now in the parent.
const doc = new Parser().parse(String.raw`{x y}`).document;
const group = doc.root().descendants().find((n) => n.kind === 'group');
doc.unwrap(group);
doc.toLatex(); // 'x y'extract#
extract(node: Node): NodeDetach the subtree rooted at node and return it as a detached node.
The subtree is removed from its parent but kept alive, so it can be re-attached elsewhere.
Throws TexformEditError if the document is read-only, or
node is foreign, missing, or the root.
| Parameter | Type | Description |
|---|---|---|
node | Node |
|
Node — The detached node.
remove#
remove(node: Node): voidRemove the subtree rooted at node and discard it.
Throws TexformEditError if the document is read-only, or
node is foreign, missing, or the root.
| Parameter | Type | Description |
|---|---|---|
node | Node |
|
clear#
clear(node: Node): voidRemove every child of the container node.
Throws TexformEditError if the document is read-only, or
node is foreign, missing, or not a container.
| Parameter | Type | Description |
|---|---|---|
node | Node |
|
setText#
setText(node: Node, value: string): voidSet the content of a text node.
Throws TexformEditError if the document is read-only, or
node is foreign, missing, or not a text node.
| Parameter | Type | Description |
|---|---|---|
node | Node |
|
value | string |
|
setChar#
setChar(node: Node, value: string): voidSet the character of a char node.
Throws TexformEditError if the document is read-only, or
node is foreign, missing, or not a char node.
| Parameter | Type | Description |
|---|---|---|
node | Node |
|
value | string |
|
setCommandName#
setCommandName(node: Node, name: string): voidRename a command node.
Throws TexformEditError if the document is read-only, or
node is foreign, missing, or not a command node.
| Parameter | Type | Description |
|---|---|---|
node | Node |
|
name | string |
|
setEnvName#
setEnvName(node: Node, name: string): voidRename an environment, keeping its arguments and body.
Throws TexformConformanceError if the new name's signature or body mode does not fit the existing arguments and body.
| Parameter | Type |
|---|---|
node | Node |
name | string |
setArg#
setArg(node: Node, index: number, value: Arg): voidSet the argument at index of a command or environment node.
Throws TexformEditError if the document is read-only,
node is foreign or missing, there is no argument slot at index, or
value does not match the slot shape; TexformConformanceError if the value does not fit the slot; TexformParseError for invalid source.
| Parameter | Type | Description |
|---|---|---|
node | Node |
|
index | number |
|
value | Arg |
|
setArgDelimiters#
setArgDelimiters( node: Node, index: number, open: string, close: string,): voidChange only the boundaries of a filled paired argument. Throws TexformConformanceError if the slot is not a filled paired slot or the delimiters are not allowed.
| Parameter | Type |
|---|---|
node | Node |
index | number |
open | string |
close | string |
setDelimiters#
setDelimiters(node: Node, left: string, right: string): voidChange the delimiters of a \left...\right group. Throws TexformConformanceError for a delimiter that is neither . nor registered.
| Parameter | Type |
|---|---|
node | Node |
left | string |
right | string |
setSubscript#
setSubscript(node: Node, value: Arg | undefined): NodeSet or clear the subscript of node. A non-scripted node becomes the base of a new scripted node; an existing scripted base is resolved automatically.
Throws TexformConformanceError if the base cannot carry scripts and TexformParseError for invalid source.
| Parameter | Type | Description |
|---|---|---|
node | Node | — |
value | Arg | |
|
Node — The resulting scripted node, or the base when clearing the last script collapses the wrapper.
setSuperscript#
setSuperscript(node: Node, value: Arg | undefined): NodeSet or clear the superscript of node; behaves like Document.setSubscript.
| Parameter | Type |
|---|---|
node | Node |
value | Arg | |
setPrimeCount#
setPrimeCount(node: Node, count: number): voidSet the number of primes in a prime node. Throws TexformConformanceError if count is not positive.
| Parameter | Type |
|---|---|
node | Node |
count | number |
Lifecycle#
free#
free(): voidRelease the WASM handle for this document immediately.
Prefer a using declaration so [Symbol.dispose]() runs at scope exit.
After free(), further use is invalid. Skipping free() is safe:
garbage collection still reclaims the handle, just not at a determined
time. Call free() (or use using) when many short-lived documents
would otherwise accumulate WASM memory.
[Symbol.dispose]#
[Symbol.dispose](): voidRelease the WASM handle. Same as Document.free; used by using.
NodeSpanEntryinterface#
One entry of Document.nodeSpans: a node identifier paired with its recorded source Span.
| Field | Type | Description |
|---|---|---|
id | string | Tree path such as |
span | Span | The node's source byte span recorded by the parser. |
TokenizedLatexinterface#
Serialized LaTeX and tokens produced by the same serializer traversal.
| Field | Type | Description |
|---|---|---|
latex | string | Serialized LaTeX string, identical to Document.toLatex. |
tokens | Serialization | Ordered, non-overlapping, non-empty fragments. Gaps contain serializer-inserted spacing. Empty error snippets emit no token. |
SerializationTokeninterface#
One non-empty serialization fragment.
| Field | Type | Description |
|---|---|---|
text | string | Fragment text, decoded from bytes |
startByte | number | Inclusive UTF-8 byte offset into TokenizedLatex.latex, not a JavaScript UTF-16 index. |
endByte | number | Exclusive UTF-8 byte offset into TokenizedLatex.latex, not a JavaScript UTF-16 index. |
kind | Serialization | Semantic category of the fragment. |
mode | "math" | | Semantic math/text mode of the fragment, independent of spacing policy. |
SerializationTokenKindtype#
"control_sequence" | "character" | "delimiter" | "text" | "raw" | "error"Closed semantic categories emitted by tokenized serialization.
NodeTableinterface#
Preorder node columns; field names stay snake_case in both bindings.
| Field | Type |
|---|---|
kind | Array<"Root" | |
parent | number[ |
slot | Array<Node |
slot_index | number[ |
depth | number[ |
mode | Runtime |
name | Array<string | |
value | Array<string | |
known | Array<boolean | |
group_kind | Array<"explicit" | |
left | Array<string | |
right | Array<string | |
ArgumentTableinterface#
All argument slots, ordered by owner row and slot index.
| Field | Type |
|---|---|
owner | number[ |
index | number[ |
form | Array<Arg |
present | boolean[ |
value_kind | Array<"math" | |
value | Array<string | |
content | number[ |
open | Array<string | |
close | Array<string | |
ColumnarTreeinterface#
Tree columns for bulk structural analysis with Arrow or DataFrame tools.
| Field | Type |
|---|---|
nodes | Node |
args | Argument |