# Node

Navigate the document tree and read node content through read-only Node handles.

https://texform.dev/api/python/node

## `Node`

Kind: class

A read-only handle into a ``Document`` for navigation and reading.

A ``Node`` is a cheap reference — a shared pointer into the owning document
plus an identity, never a copy of the subtree. It carries no editing methods;
all mutation goes through the owning ``Document``. Accessors return content
only for the node kinds that carry it and ``None`` otherwise, so the same
handle works uniformly across kinds.

You obtain handles from ``Document.root()``, ``Document.errors()``,
``Document.find_commands()``, the ``create_*`` staging constructors, and the
navigation methods here.

```python
doc = texform.Parser().parse(r"\frac{x}{y}")["document"]
cmd = doc.root().children()[0]
cmd.kind()  # 'Command'
cmd.is_command("frac")  # True
```

- [Document](https://texform.dev/api/python/document.md#Document)

### Kind

#### `kind`

```python
kind() -> NodeKind
```

Return the node kind as a string.

**Returns** `NodeKind` One of the ``NodeKind`` values, such as ``"Root"``, ``"Command"``, or ``"Char"``.

```python
doc = texform.Parser().parse(r"\frac{x}{y}")["document"]
doc.root().kind()  # 'Root'
```

### Predicates

#### `is_command`

```python
is_command(name: str | None = None) -> bool
```

Report whether the node is a command, optionally a specific one.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `name` | str | None | None | A command name to match, or ``None`` to match any command. |

**Returns** `bool` ``True`` if the node is a command (and matches ``name`` when given).

```python
node.is_command()        # any command
node.is_command("frac")  # specifically \frac
```

#### `is_char`

```python
is_char(value: str | None = None) -> bool
```

Report whether the node is a char, optionally a specific one.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | str | None | None | A character to match, or ``None`` to match any char. |

**Returns** `bool` ``True`` if the node is a char (and holds ``value`` when given).

```python
node.is_char("+")
```

#### `is_error`

```python
is_error() -> bool
```

Report whether the node is an ``Error`` placeholder.

**Returns** `bool` ``True`` for an ``Error`` node.

#### `is_known`

```python
is_known() -> bool | None
```

Report whether the document's knowledge base knows this command or environment.

**Returns** `bool | None` ``True`` or ``False`` for command-like nodes and environments, ``None`` for other kinds.

### Navigation

#### `parent`

```python
parent() -> Node | None
```

Return the parent node, or ``None`` for the root.

**Returns** `Node | None` The parent handle, or ``None``.

#### `children`

```python
children() -> list[Node]
```

Return the node's direct children.

**Returns** `list[Node]` The child handles in order.

```python
doc = texform.Parser().parse(r"\frac{x}{y} + a")["document"]
[n.kind() for n in doc.root().children()]  # ['Command', 'Char', 'Char']
```

#### `next_sibling`

```python
next_sibling() -> Node | None
```

Return the following sibling, or ``None`` if this is the last child.

**Returns** `Node | None` The next sibling handle, or ``None``.

#### `prev_sibling`

```python
prev_sibling() -> Node | None
```

Return the preceding sibling, or ``None`` if this is the first child.

**Returns** `Node | None` The previous sibling handle, or ``None``.

#### `ancestors`

```python
ancestors() -> list[Node]
```

Return the node's ancestors from the parent upward.

**Returns** `list[Node]` The ancestor handles, nearest first.

#### `descendants`

```python
descendants() -> list[Node]
```

Return every descendant of the node.

**Returns** `list[Node]` The descendant handles in document order.

#### `path`

```python
path() -> str | None
```

Return the node's current path from the root, or ``None`` if detached.

The path reflects the tree now and changes after edits; ``Document.node_at`` resolves it.

**Returns** `str | None`

#### `slot`

```python
slot() -> NodeSlot | None
```

Return the slot this node fills in its parent, or ``None`` for the root and detached nodes.

**Returns** `NodeSlot | None` A dict with the slot ``kind`` and, for indexed slots such as children and arguments, its ``index``.

### Content accessors

#### `command_name`

```python
command_name() -> str | None
```

Return the command name for a ``Command`` / ``Declarative`` node.

**Returns** `str | None` The name without the leading backslash, or ``None`` for other kinds.

#### `env_name`

```python
env_name() -> str | None
```

Return the environment name for an ``Environment`` node.

**Returns** `str | None` The environment name, or ``None`` for other kinds.

#### `text`

```python
text() -> str | None
```

Return the value of a ``Text`` node.

**Returns** `str | None` The text string, or ``None`` for other kinds.

#### `char`

```python
char() -> str | None
```

Return the character of a ``Char`` node.

**Returns** `str | None` The single character, or ``None`` for other kinds.

#### `prime_count`

```python
prime_count() -> int | None
```

Return the symbol count of a math ``Prime`` node.

``Scripted`` determines whether these symbols form a superscript.

**Returns** `int | None` The count (greater than zero), or ``None`` for other kinds.

```python
doc = texform.Parser().parse(r"f''")["document"]
prime = next(n for n in doc.root().descendants() if n.kind() == "Prime")
prime.prime_count()  # 2
```

#### `error_parts`

```python
error_parts() -> ErrorParts | None
```

Return the decomposed content of an ``Error`` node.

**Returns** `ErrorParts | None` A dict ``{"message": str, "snippet": str}``, or ``None`` for other kinds.

```python
doc = texform.Parser().parse(r"\sqrt[")["document"]
err = next(n for n in doc.root().descendants() if n.is_error())
err.error_parts()  # {'message': '...', 'snippet': '\sqrt['}
```

#### `content_mode`

```python
content_mode() -> RuntimeContentMode | None
```

Return the runtime content mode where applicable.

**Returns** `RuntimeContentMode | None` ``"math"`` or ``"text"`` for nodes that carry a mode, or ``None``.

### Groups

#### `group_kind`

```python
group_kind() -> GroupKindRef | None
```

Return the group kind for a ``Group`` node.

**Returns** `GroupKindRef | None` A dict with a ``kind`` discriminator (``Explicit``, ``Implicit``, ``InlineMath``, or ``Delimited``); a ``Delimited`` group also carries ``left`` and ``right`` delimiter values. ``None`` for other kinds.

```python
doc = texform.Parser().parse(r"{x}")["document"]
group = next(n for n in doc.root().descendants() if n.kind() == "Group")
group.group_kind()  # {'kind': 'Explicit'}
```

### Command arguments

#### `arg_count`

```python
arg_count() -> int
```

Return the number of argument slots for a command-like node.

**Returns** `int` The slot count (zero for nodes that take no arguments).

#### `arg`

```python
arg(index: int) -> ArgRef | None
```

Return the argument at ``index``, or ``None`` if the slot is empty.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `index` | int | — | The zero-based slot index. |

**Returns** `ArgRef | None` An argument-value dict — content kinds (``Math``, ``Text``) carry a live ``node``; leaf kinds carry a ``value`` — or ``None`` for an empty slot.

```python
doc = texform.Parser().parse(r"\frac{x}{y}")["document"]
frac = next(n for n in doc.root().descendants() if n.is_command("frac"))
frac.arg_count()  # 2
frac.arg(0)       # {'kind': 'Math', 'node': <Node>}
```

#### `arg_slots`

```python
arg_slots() -> list[ArgRef | None]
```

Return all argument slots, with ``None`` for any empty slot.

**Returns** `list[ArgRef | None]` The list of argument-value dicts and ``None`` placeholders.

### Scripts and infix

#### `script_base`

```python
script_base() -> Node | None
```

Return the base of a ``Scripted`` node.

**Returns** `Node | None` The base node handle, or ``None`` for other kinds.

#### `subscript`

```python
subscript() -> Node | None
```

Return the subscript slot of a ``Scripted`` node.

**Returns** `Node | None` The subscript node handle, or ``None`` if absent or another kind.

```python
doc = texform.Parser().parse(r"x_i^2")["document"]
sc = next(n for n in doc.root().descendants() if n.kind() == "Scripted")
sc.subscript().kind(), sc.superscript().kind()  # ('Char', 'Char')
```

#### `superscript`

```python
superscript() -> Node | None
```

Return the superscript slot of a ``Scripted`` node.

**Returns** `Node | None` The superscript node handle, or ``None`` if absent or another kind.

#### `infix_left`

```python
infix_left() -> Node | None
```

Return the left operand of an ``Infix`` node.

**Returns** `Node | None` The left operand handle, or ``None`` for other kinds.

#### `infix_right`

```python
infix_right() -> Node | None
```

Return the right operand of an ``Infix`` node.

**Returns** `Node | None` The right operand handle, or ``None`` for other kinds.

#### `env_body`

```python
env_body() -> Node | None
```

Return the body group of an ``Environment`` node.

**Returns** `Node | None` The body node handle, or ``None`` for other kinds.

### Spans

#### `span`

```python
span() -> Span | None
```

Return the source byte span of the node.

**Returns** `Span | None` A ``{"start": int, "end": int}`` dict, or ``None`` if the node has no recorded span.

```python
doc = texform.Parser().parse(r"a + b")["document"]
doc.root().children()[0].span()  # {'start': 0, 'end': 1}
```

### Identity

#### `document`

```python
document() -> Document
```

Return the ``Document`` that owns this handle.

**Returns** `Document`

#### `__eq__`

```python
__eq__(other: object) -> bool
```

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `other` | object | — |  |

**Returns** `bool`

#### `__hash__`

```python
__hash__() -> int
```

**Returns** `int`

#### `__repr__`

```python
__repr__() -> str
```

**Returns** `str`

## `NodeKind`

Kind: typeAlias

```python
Literal['Root', 'Group', 'Command', 'Infix', 'Declarative', 'Environment', 'Scripted', 'Prime', 'Text', 'Char', 'ActiveSpace', 'AlignmentTab', 'Error']
```

Node kind as reported by ``Node.kind()``. Python uses PascalCase (``"Root"``, ``"Command"``, ``"ActiveSpace"``).

## `RuntimeContentMode`

Kind: typeAlias

```python
Literal['math', 'text']
```

Runtime content mode reported by the tree API: ``"math"`` or ``"text"``.

## `ErrorParts`

Kind: typedDict

The decomposed content of an ``Error`` placeholder node.

| Name | Type | Description |
| --- | --- | --- |
| `message` | str | The reason the fragment failed to parse. |
| `snippet` | str | The captured source text, re-emitted verbatim on serialization. |

## `GroupKindExplicit`

Kind: typedDict

A group written with explicit braces ``{ ... }``.

| Name | Type | Description |
| --- | --- | --- |
| `kind` | Literal['Explicit'] | Discriminator; always ``"Explicit"``. |

## `GroupKindImplicit`

Kind: typedDict

A group with no surrounding braces, inferred from structure.

| Name | Type | Description |
| --- | --- | --- |
| `kind` | Literal['Implicit'] | Discriminator; always ``"Implicit"``. |

## `GroupKindDelimited`

Kind: typedDict

A group bounded by a delimiter pair, such as ``\left( ... \right)``.

| Name | Type | Description |
| --- | --- | --- |
| `kind` | Literal['Delimited'] | Discriminator; always ``"Delimited"``. |
| `left` | DelimiterValue | The opening delimiter value. |
| `right` | DelimiterValue | The closing delimiter value. |

## `GroupKindInlineMath`

Kind: typedDict

A group introduced by inline math shift, such as ``$ ... $`` in text mode.

| Name | Type | Description |
| --- | --- | --- |
| `kind` | Literal['InlineMath'] | Discriminator; always ``"InlineMath"``. |

## `GroupKindRef`

Kind: typeAlias

```python
GroupKindExplicit | GroupKindImplicit | GroupKindDelimited | GroupKindInlineMath
```

The kind of a ``Group`` node: explicit, implicit, delimited, or inline-math.

## `DelimiterValue`

Kind: typeAlias

```python
str
```

A delimiter string: a character, a backslash-prefixed control, or a dot.

## `MathArg`

Kind: typedDict

A command argument carrying math-mode content.

| Name | Type | Description |
| --- | --- | --- |
| `kind` | Literal['Math'] | Discriminator; always ``"Math"``. node: The live argument-body ``Node``. |
| `node` | Node |  |

## `TextArg`

Kind: typedDict

A command argument carrying text-mode content.

| Name | Type | Description |
| --- | --- | --- |
| `kind` | Literal['Text'] | Discriminator; always ``"Text"``. node: The live argument-body ``Node``. |
| `node` | Node |  |

## `DelimiterArg`

Kind: typedDict

A command argument that is a single delimiter token.

| Name | Type | Description |
| --- | --- | --- |
| `kind` | Literal['Delimiter'] | Discriminator; always ``"Delimiter"``. value: The delimiter value. |
| `value` | DelimiterValue |  |

## `CSNameArg`

Kind: typedDict

A command argument that is a control-sequence name.

| Name | Type | Description |
| --- | --- | --- |
| `kind` | Literal['CSName'] | Discriminator; always ``"CSName"``. value: The control-sequence name without the leading backslash. |
| `value` | str |  |

## `DimensionArg`

Kind: typedDict

A command argument that is a TeX dimension, such as ``2pt``.

| Name | Type | Description |
| --- | --- | --- |
| `kind` | Literal['Dimension'] | Discriminator; always ``"Dimension"``. value: The dimension as written. |
| `value` | str |  |

## `IntegerArg`

Kind: typedDict

A command argument that is an integer literal.

| Name | Type | Description |
| --- | --- | --- |
| `kind` | Literal['Integer'] | Discriminator; always ``"Integer"``. value: The integer as written. |
| `value` | str |  |

## `KeyValArg`

Kind: typedDict

A command argument that is a ``key=value`` list.

| Name | Type | Description |
| --- | --- | --- |
| `kind` | Literal['KeyVal'] | Discriminator; always ``"KeyVal"``. value: The raw key-value text. |
| `value` | str |  |

## `ColumnArg`

Kind: typedDict

A command argument that is a tabular column specification.

| Name | Type | Description |
| --- | --- | --- |
| `kind` | Literal['Column'] | Discriminator; always ``"Column"``. value: The column specification as written. |
| `value` | str |  |

## `BooleanArg`

Kind: typedDict

A command argument that is a star flag, modeled as a boolean.

| Name | Type | Description |
| --- | --- | --- |
| `kind` | Literal['Boolean'] | Discriminator; always ``"Boolean"``. value: ``True`` when the star was present. |
| `value` | bool |  |

## `ArgRef`

Kind: typeAlias

```python
MathArg | TextArg | DelimiterArg | OperatorNameArg | CSNameArg | DimensionArg | IntegerArg | KeyValArg | ColumnArg | BooleanArg
```

A read command argument: one of the discriminated argument-value dicts.

## `ArgFormKind`

Kind: typeAlias

```python
Literal['mandatory', 'optional', 'star', 'group', 'until', 'delimited', 'paired']
```

## `NodeSlotKind`

Kind: typeAlias

```python
Literal['child', 'arg', 'script_base', 'subscript', 'superscript', 'infix_left', 'infix_right', 'env_body']
```

## `ArgForm`

Kind: typedDict

| Name | Type | Description |
| --- | --- | --- |
| `kind` | ArgFormKind |  |
| `open` | NotRequired[str] |  |
| `close` | NotRequired[str] |  |

## `OperatorNameArg`

Kind: typedDict

| Name | Type | Description |
| --- | --- | --- |
| `form` | ArgForm |  |
| `kind` | Literal['OperatorName'] |  |
| `node` | Node |  |

## `Paired`

Kind: class

```python
Paired(value: Node | str, open: str, close: str) -> None
```

Immutable content and delimiter pair for an argspec Paired slot.

Pass it as a slot value to select an explicit delimiter pair. ``value`` is a detached node or source written between ``open`` and ``close``. Instances compare and hash by value.

```python
doc.create_command("sqrt", [texform.Paired("x", "[", "]"), "y"])
```

#### `Paired`

```python
Paired(value: Node | str, open: str, close: str) -> None
```

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | Node | str | — |  |
| `open` | str | — |  |
| `close` | str | — |  |

#### `value`

```python
value() -> Node | str
```

**Returns** `Node | str`

#### `open`

```python
open() -> str
```

**Returns** `str`

#### `close`

```python
close() -> str
```

**Returns** `str`

#### `__eq__`

```python
__eq__(other: object) -> bool
```

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `other` | object | — |  |

**Returns** `bool`

#### `__hash__`

```python
__hash__() -> int
```

**Returns** `int`

## `Arg`

Kind: typeAlias

```python
Node | str | bool | None | Paired
```

Slot input: source written inside the slot, a detached content node, a star flag, absence, or an explicit ``Paired`` delimiter pair.

## `NodeSlot`

Kind: typedDict

| Name | Type | Description |
| --- | --- | --- |
| `kind` | NodeSlotKind |  |
| `index` | int | None |  |

