> For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt.

# Template Expansion

The default pipeline does not execute templates. When you need template output, use `/expand` to expand supported templates and parser functions before parsing. The library makes no network requests; the host's `resolveTemplate` supplies template source.

## Basic usage

```tsx
import { expandWikitext } from "react-wikitext/expand";
import { prepareWikitext } from "react-wikitext/hast";
import { WikitextView } from "react-wikitext/view";
import "react-wikitext/styles.css";

const expanded = await expandWikitext(source, {
  pageName: "Example",
  resolveTemplate: async ({ title }) => {
    const response = await fetch(`/api/templates/${encodeURIComponent(title)}`);
    return response.ok ? await response.text() : null;
  },
});

const prepared = prepareWikitext(expanded.document);
const view = <WikitextView document={prepared} lang="en" />;
```

`expandWikitext`:

1. Parses the original source into `original`.
2. Evaluates templates and functions by call structure and records `records`.
3. Parses the expanded source into `document`.
4. Returns `expansion.status`: `"complete"`, `"partial"`, or `"fallback"`.

The expanded document is already parsed. **Do not parse it again**; pass it directly to `prepareWikitext`.

## Resolver requirements

```ts
type WikitextTemplateResolver = (
  request: WikitextTemplateRequest,
) => string | null | undefined | Promise<string | null | undefined>;
```

- `null` / `undefined` means the template is missing; an empty string is a valid template.
- A title is parsed once per expansion; the resolver must return stable source for the same `title`.
- `request.pageName` is the original page; `request.callerTitle` is the template that contains the current call and is omitted for calls on the original page.
- `request.invocation` points at the top-level call range in `original.source`; nested requests reuse that top-level range.
- The library handles newline normalization, include filtering, and parsing; the resolver only fetches source.

## Supported syntax

- Template transclusion and parameter substitution, including anonymous, named, and default values.
- `noinclude` / `includeonly` / `onlyinclude`.
- `#if`, `#ifeq`, `#switch`, `#iferror`.
- `{{!}}` and `{{=}}`.
- Implicit newlines around template and function output.

Values are computed only when needed: template names, parameter names, and conditions are evaluated in their own scope. Unselected branches, unread parameters, and unused defaults do not call the resolver or count toward the invocation budget.

The following calls are preserved with diagnostics by default:

- `#invoke` and Lua.
- Transclusion modifiers such as `subst`.
- Functions that depend on site state or an external runtime, such as `#ifexist` and `#time`.

## Budgets and errors

| Option              | Default                                     | Description                          |
| ------------------- | ------------------------------------------- | ------------------------------------ |
| `maxDepth`          | 40                                          | Nested expansion depth               |
| `maxInvocations`    | 1,000                                       | Calls per expansion                  |
| `maxExpandedLength` | Same as the original source limit (100,000) | Expanded source length               |
| `strict`            | `false`                                     | Throw on any recoverable failure     |
| `signal`            | —                                           | Cancellation; rejects with `ABORTED` |

- A single over-long call is preserved with `LENGTH_BUDGET_EXCEEDED`.
- If even the preserved source exceeds `maxExpandedLength`, the library throws `EXPANSION_TOO_LARGE`.
- With `strict: true`, budget overruns throw `EXPANSION_BUDGET_EXCEEDED`.
- By default, a final parse failure returns the original snapshot with `status: "fallback"`.
- Cancellation is delivered through `AbortSignal`; the original reason is stored in `cause`.

All errors are `WikitextExpandError`. Common codes include `TEMPLATE_NOT_FOUND`, `TEMPLATE_LOOP`, `UNSUPPORTED_CALL`, `FINAL_PARSE_FAILED`, and `ABORTED`.

## Results and diagnostics

```ts
const {
  original, // original parse snapshot
  document, // expanded parse snapshot
  expansion, // status / records / diagnostics
} = expanded;
```

- `expansion.records` records each call's `kind`, name, original range, expanded range, and status (`expanded` / `preserved`).
- `expansion.diagnostics` coordinates are based on `original.source`.
- `document.diagnostics` merges final parse diagnostics with expansion diagnostics mapped onto the expanded source.
- `prepareWikitext(document)` carries these diagnostics into the render result.

Nested calls map only to their top-level record; there is no precise source mapping inside templates.

## How preserved calls render

Templates, functions, and arguments preserved after a failed expansion continue to render as [placeholders](/guide/rendering.md#templates-functions-and-arguments). They are never presented as evaluated content. Template source and expansion results are treated as untrusted wikitext and still go through semantic normalization, HAST conversion, and final sanitization.

## Limitations

- Include filtering is a single pass; nested `noinclude` / `onlyinclude` inside `includeonly` content is not recognized again.
- Lua is not executed and no site API client is built in.
- There is no cross-request template cache; implement caching in the resolver.
- Categories, references, and tables of contents in expanded output follow the normal rendering rules.
