JavaScriptDocument

Document

Python

Construct, query, edit, and serialize the editable TeXForm document tree.

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.

TypeScript
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.

ParameterType
options{ knowledgeBase?: KnowledgeBase; mode?: RuntimeContentMode; } | undefined

fromSyntax#

fromSyntax(    node: SyntaxNode,    options: { knowledgeBase?: KnowledgeBase } | undefined,): Document

Build 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.

ParameterTypeDescription
nodeSyntaxNode
  • A SyntaxNode object, typically produced by toSyntax().
options{ knowledgeBase?: KnowledgeBase } | undefined—
Returns
Document —

The reconstructed editable document.

TypeScript
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);

clone#

clone(): Document

Deep-copy the tree into a new document with new node identities, sharing this document's knowledge base.

Returns

Queries#

root#

root(): Node

Return 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.

Returns
Node —

The root node handle.

TypeScript
const doc = new Parser().parse(String.raw`\frac{x}{y}`).document;
doc.root().kind; // 'root'
See also

hasErrors#

hasErrors(): boolean

Whether 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.

Returns
boolean —

true if any Error node is present.

TypeScript
new Parser().parse(String.raw`\sqrt[`).document.hasErrors(); // true

isReadOnly#

isReadOnly(): boolean

Whether 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.

Returns
boolean —

true if every editing method will throw.

errors#

errors(): Node[]

Return the Error placeholder Node handles in the tree.

Returns
Node[] —

An array of the Error nodes; empty when hasErrors() is false.

See also

findCommands#

findCommands(name: string): Node[]

Return every command Node in the tree whose name equals name.

ParameterTypeDescription
namestring
  • The command name to match, without the leading backslash.
Returns
Node[] —

The matching command node handles.

TypeScript
const doc = new Parser().parse(String.raw`\frac{x}{y} + \frac{a}{b}`).document;
doc.findCommands('frac').length; // 2
See also

findEnvironments#

findEnvironments(name: string): Node[]

Return every environment Node in the tree whose name equals name.

ParameterTypeDescription
namestring
  • The environment name to match.
Returns
Node[] —

The matching environment node handles.

See also

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.

Returns
NodeSpanEntry[] —

The span entries in tree order.

nodeAt#

nodeAt(path: string): Node

Resolve 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.

ParameterType
pathstring
Returns

knowledgeBase#

knowledgeBase(): KnowledgeBase

The immutable knowledge base bound to this document. Construction and edits are checked against it; toLatex is not.

Output#

toLatex#

toLatex(options: SerializeOptions | null | undefined): string

Serialize 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.

ParameterTypeDescription
optionsSerializeOptions | null | undefined
Returns
string —

The serialized LaTeX string.

TypeScript
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): TokenizedLatex

Serialize 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.

ParameterTypeDescription
optionsSerializeOptions | null | undefined
Returns
TokenizedLatex —

Serialized LaTeX plus typed fragments from the same traversal.

TypeScript
const tok = new Parser().parse('x^2').document!.toTokenizedLatex();
tok.latex; // 'x ^ { 2 }'
tok.tokens[0].kind; // 'character'

toSyntax#

toSyntax(): SyntaxNode

Convert the tree to a SyntaxNode object for serde and transport.

This is the structured-data channel, distinct from the LaTeX text channel Document.toLatex.

Returns
SyntaxNode —

The lossless snapshot of the tree.

TypeScript
doc.toSyntax(); // { Root: { ... } }

toColumnar#

toColumnar(): ColumnarTree

Flatten 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,): Node

Create 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.

ParameterTypeDescription
valuestring
  • The single character. "&" is a literal ampersand written \&.
optionsConstructionOptions | undefined—
Returns
Node —

The detached node handle.

createText#

createText(    value: string,    options: ConstructionOptions | undefined,): Node

Create a detached text node. Throws TexformConformanceError if the text cannot be written in the mode.

ParameterType
valuestring
optionsConstructionOptions | undefined
Returns

createActiveSpace#

createActiveSpace(options: ConstructionOptions | undefined): Node

Create a detached active-space node.

ParameterType
optionsConstructionOptions | undefined
Returns

createGroup#

createGroup(    mode: RuntimeContentMode,    children: (Node | string)[] | undefined,    options: ConstructionOptions | undefined,): Node

Create 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.

ParameterTypeDescription
modeRuntimeContentMode
  • The group's content mode and context.
children(Node | string)[] | undefined
  • Detached nodes or source strings. A string is parsed in mode and its nodes are spliced into the list, so one string may yield several children.
optionsConstructionOptions | undefined—
Returns
TypeScript
const group = doc.createGroup('math', ['x^2', doc.createChar('y')]);

createCommand#

createCommand(    name: string,    args: Arg[] | null | undefined,    options: ConstructionOptions | undefined,): Node

Create 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.

ParameterTypeDescription
namestring
  • The command name without the leading backslash. A name missing from the knowledge base creates an unknown command without arguments.
argsArg[] | null | undefined
  • Values for every signature slot, or only the required slots to omit optional and star slots. See Arg.
optionsConstructionOptions | undefined—
Returns
TypeScript
doc.appendChild(doc.root(), doc.createCommand('sqrt', ['x']));
doc.toLatex(); // '\\sqrt { x }'

createDeclarative#

createDeclarative(    name: string,    args: Arg[] | null | undefined,    options: ConstructionOptions | undefined,): Node

Create a detached declarative command such as \bf. Same conditions as Document.createCommand, except the record must be declarative.

ParameterType
namestring
argsArg[] | null | undefined
optionsConstructionOptions | undefined
Returns

createEnvironment#

createEnvironment(    name: string,    args: Arg[] | null | undefined,    body: Node | string | (Node | string)[] | null | undefined,    options: ConstructionOptions | undefined,): Node

Create 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.

ParameterTypeDescription
namestring
  • The environment name. An unknown environment takes no arguments and uses the surrounding mode.
argsArg[] | null | undefined
bodyNode | string | (Node | string)[] | null | undefined
  • A detached group in the body mode, a source string parsed in the recorded body mode, a list whose source strings are spliced as in Document.createGroup, or null for an empty body.
optionsConstructionOptions | undefined—
Returns

createAlignmentTab#

createAlignmentTab(options: ConstructionOptions | undefined): Node

Create a detached unescaped & cell separator. Use createChar("&") for a literal ampersand.

ParameterType
optionsConstructionOptions | undefined
Returns

createDelimitedGroup#

createDelimitedGroup(    left: string,    right: string,    children: (Node | string)[] | undefined,    options: ConstructionOptions | undefined,): Node

Create 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.

ParameterTypeDescription
leftstring
  • The left delimiter source, such as "(" or "\\langle".
rightstring
  • The right delimiter source.
children(Node | string)[] | undefined
optionsConstructionOptions | undefined—
Returns

createInlineMath#

createInlineMath(    children: (Node | string)[] | undefined,    options: ConstructionOptions | undefined,): Node

Create a detached $...$ group of math children, in a text context by default.

Same failure conditions as createGroup.

ParameterTypeDescription
children(Node | string)[] | undefined
optionsConstructionOptions | undefined—
Returns

createScripted#

createScripted(    base: Node | string,    sub: Node | string | null | undefined,    sup: Node | string | null | undefined,    options: ConstructionOptions | undefined,): Node

Create 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.

ParameterTypeDescription
baseNode | string
  • The base node or source.
subNode | string | null | undefined
  • The subscript node or source, or null for none.
supNode | string | null | undefined
  • The superscript node or source, or null for none.
optionsConstructionOptions | undefined—
Returns
TypeScript
doc.appendChild(doc.root(), doc.createScripted('x', null, '2'));

createPrime#

createPrime(    count: number,    options: ConstructionOptions | undefined,): Node

Create a detached run of count primes, built in math mode by default.

Throws TexformConformanceError if count is not positive.

ParameterType
countnumber
optionsConstructionOptions | undefined
Returns

createInfix#

createInfix(    name: string,    left: Node | string,    right: Node | string,    args: Arg[] | null | undefined,    options: ConstructionOptions | undefined,): Node

Create 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.

ParameterTypeDescription
namestring—
leftNode | string
  • The left operand node or source.
rightNode | string
  • The right operand node or source.
argsArg[] | null | undefined
  • Values for extra slots, such as the dimension of \above.
optionsConstructionOptions | undefined—
Returns

parseFragment#

parseFragment(    source: string,    options: ConstructionOptions | undefined,): Node

Parse 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.

ParameterType
sourcestring
optionsConstructionOptions | undefined
Returns

cloneNode#

cloneNode(node: Node): Node

Deep-copy a subtree of this document as a detached node.

ParameterType
nodeNode
Returns

importNode#

importNode(node: Node): Node

Copy 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.

ParameterType
nodeNode
Returns

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): void

Append 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.

ParameterTypeDescription
parentNode
  • The container node to append into.
childNode
  • The node to append.

insertChild#

insertChild(parent: Node, index: number, child: Node): void

Insert 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.

ParameterTypeDescription
parentNode
  • The container node.
indexnumber
  • The zero-based insertion index.
childNode
  • The node to insert.

insertBefore#

insertBefore(anchor: Node, node: Node): void

Insert 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.

ParameterTypeDescription
anchorNode
  • The sibling to insert before.
nodeNode
  • The node to insert.

insertAfter#

insertAfter(anchor: Node, node: Node): void

Insert node immediately after the sibling anchor.

Same failure conditions as Document.insertBefore.

ParameterTypeDescription
anchorNode
  • The sibling to insert after.
nodeNode
  • The node to insert.

replaceWith#

replaceWith(target: Node, replacement: Node): void

Replace 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.

ParameterTypeDescription
targetNode
  • The node to replace.
replacementNode
  • The node to put in its place.

wrap#

wrap(target: Node, wrapper: Node): Node

Wrap 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.

ParameterTypeDescription
targetNode
  • The node to wrap.
wrapperNode
  • The container node to wrap it in.
Returns
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.

ParameterTypeDescription
groupNode
  • The group node to dissolve.
Returns
Node[] —

The freed child node handles, now in the parent.

TypeScript
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): Node

Detach 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.

ParameterTypeDescription
nodeNode
  • The subtree root to detach.
Returns
Node —

The detached node.

remove#

remove(node: Node): void

Remove the subtree rooted at node and discard it.

Throws TexformEditError if the document is read-only, or node is foreign, missing, or the root.

ParameterTypeDescription
nodeNode
  • The subtree root to remove.

clear#

clear(node: Node): void

Remove every child of the container node.

Throws TexformEditError if the document is read-only, or node is foreign, missing, or not a container.

ParameterTypeDescription
nodeNode
  • The container to empty.

setText#

setText(node: Node, value: string): void

Set the content of a text node.

Throws TexformEditError if the document is read-only, or node is foreign, missing, or not a text node.

ParameterTypeDescription
nodeNode
  • The text node to update.
valuestring
  • The new text content.

setChar#

setChar(node: Node, value: string): void

Set the character of a char node.

Throws TexformEditError if the document is read-only, or node is foreign, missing, or not a char node.

ParameterTypeDescription
nodeNode
  • The char node to update.
valuestring
  • The new single character.

setCommandName#

setCommandName(node: Node, name: string): void

Rename a command node.

Throws TexformEditError if the document is read-only, or node is foreign, missing, or not a command node.

ParameterTypeDescription
nodeNode
  • The command node to rename.
namestring
  • The new command name.

setEnvName#

setEnvName(node: Node, name: string): void

Rename 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.

ParameterType
nodeNode
namestring

setArg#

setArg(node: Node, index: number, value: Arg): void

Set 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.

ParameterTypeDescription
nodeNode
  • The command or environment node.
indexnumber
  • The zero-based argument slot index.
valueArg
  • The new argument value; see Arg. null clears an optional slot.

setArgDelimiters#

setArgDelimiters(    node: Node,    index: number,    open: string,    close: string,): void

Change 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.

ParameterType
nodeNode
indexnumber
openstring
closestring

setDelimiters#

setDelimiters(node: Node, left: string, right: string): void

Change the delimiters of a \left...\right group. Throws TexformConformanceError for a delimiter that is neither . nor registered.

ParameterType
nodeNode
leftstring
rightstring

setSubscript#

setSubscript(node: Node, value: Arg | undefined): Node

Set 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.

ParameterTypeDescription
nodeNode—
valueArg | undefined
  • The subscript node or source, or omit/null to clear it.
Returns
Node —

The resulting scripted node, or the base when clearing the last script collapses the wrapper.

setSuperscript#

setSuperscript(node: Node, value: Arg | undefined): Node

Set or clear the superscript of node; behaves like Document.setSubscript.

ParameterType
nodeNode
valueArg | undefined
Returns

setPrimeCount#

setPrimeCount(node: Node, count: number): void

Set the number of primes in a prime node. Throws TexformConformanceError if count is not positive.

ParameterType
nodeNode
countnumber

Lifecycle#

free#

free(): void

Release 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](): void

Release 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.

FieldTypeDescription
idstring

Tree path such as root.child.0.arg.1.content.

spanSpan

The node's source byte span recorded by the parser.

TokenizedLatexinterface#

Serialized LaTeX and tokens produced by the same serializer traversal.

FieldTypeDescription
latexstring

Serialized LaTeX string, identical to Document.toLatex.

tokensSerializationToken[]

Ordered, non-overlapping, non-empty fragments. Gaps contain serializer-inserted spacing. Empty error snippets emit no token.

SerializationTokeninterface#

One non-empty serialization fragment.

FieldTypeDescription
textstring

Fragment text, decoded from bytes [startByte, endByte) of the UTF-8 encoding of latex.

startBytenumber

Inclusive UTF-8 byte offset into TokenizedLatex.latex, not a JavaScript UTF-16 index.

endBytenumber

Exclusive UTF-8 byte offset into TokenizedLatex.latex, not a JavaScript UTF-16 index.

kindSerializationTokenKind

Semantic category of the fragment.

mode"math" | "text"

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.

FieldType
kindArray<"Root" | "Group" | "Command" | "Infix" | "Declarative" | "Environment" | "Scripted" | "Prime" | "Text" | "Char" | "ActiveSpace" | "AlignmentTab" | "Error">
parentnumber[]
slotArray<NodeSlot["kind"] | null>
slot_indexnumber[]
depthnumber[]
modeRuntimeContentMode[]
nameArray<string | null>
valueArray<string | null>
knownArray<boolean | null>
group_kindArray<"explicit" | "implicit" | "delimited" | "inline_math" | null>
leftArray<string | null>
rightArray<string | null>

ArgumentTableinterface#

All argument slots, ordered by owner row and slot index.

FieldType
ownernumber[]
indexnumber[]
formArray<ArgForm["kind"] | null>
presentboolean[]
value_kindArray<"math" | "text" | "operator_name" | "delimiter" | "cs_name" | "dimension" | "integer" | "key_val" | "column" | "boolean" | null>
valueArray<string | null>
contentnumber[]
openArray<string | null>
closeArray<string | null>

ColumnarTreeinterface#

Tree columns for bulk structural analysis with Arrow or DataFrame tools.

FieldType
nodesNodeTable
argsArgumentTable