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

# 展开 `/expand`

```ts
import { expandWikitext, WikitextExpandError } from "react-wikitext/expand";
```

`/expand` 在解析前展开受支持的模板与纯 wikitext 解析器函数。它加载解析器，不加载 React。展开是异步阶段。

## 签名

```ts
function expandWikitext(
  source: string,
  options: WikitextExpandOptions,
): Promise<WikitextExpandedDocument>;
```

```ts
interface WikitextExpandOptions {
  parser?: WikitextParser;
  pageName?: string;
  parseOptions?: Omit<WikitextParseOptions, "pageName">;
  resolveTemplate: WikitextTemplateResolver;
  maxDepth?: number;
  maxInvocations?: number;
  maxExpandedLength?: number;
  strict?: boolean;
  signal?: AbortSignal;
}
```

| 选项                  | 默认值                  | 说明                           |
| ------------------- | -------------------- | ---------------------------- |
| `parser`            | 默认解析器                | 可注入自定义解析器                    |
| `pageName`          | —                    | 原始页面名                        |
| `parseOptions`      | —                    | 原始与最终解析共用，`pageName` 由顶层字段提供 |
| `resolveTemplate`   | 必填                   | 模板源码解析函数                     |
| `maxDepth`          | 40                   | 嵌套深度                         |
| `maxInvocations`    | 1,000                | 调用次数                         |
| `maxExpandedLength` | 与原始页面长度上限相同（100,000） | 展开后源码长度                      |
| `strict`            | `false`              | 可恢复失败是否抛错                    |
| `signal`            | —                    | 取消信号                         |

## 解析函数

本节把 `resolveTemplate` 回调称为解析函数。

```ts
interface WikitextTemplateRequest {
  title: string;
  pageName?: string;
  callerTitle?: string;
  invocation: WikitextRange;
  signal?: AbortSignal;
}

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

- `null` / `undefined` 表示模板不存在；空字符串是合法模板。
- 同一标题在一次展开中只解析一次；同一 `title` 必须返回稳定源码。
- `callerTitle` 只作为上下文，不参与缓存键。
- `invocation` 指向 `original.source` 中的顶层调用范围；嵌套请求复用所属顶层范围。
- 远程获取由解析函数完成；库不发起网络请求。

## 结果

```ts
interface WikitextExpandedDocument {
  original: WikitextDocument;
  document: WikitextDocument;
  expansion: WikitextExpansionInfo;
}

interface WikitextExpansionInfo {
  status: "complete" | "partial" | "fallback";
  records: readonly WikitextExpansionRecord[];
  diagnostics: readonly WikitextExpansionDiagnostic[];
}

interface WikitextExpansionRecord {
  kind: "template" | "parserFunction" | "argument";
  name: string;
  originalRange: WikitextRange;
  expandedRange: WikitextRange;
  status: "expanded" | "preserved";
}
```

- `original` 是原始源码的解析快照。
- `document` 是展开后源码的解析快照，可直接交给 `prepareWikitext`。
- `status`：
  - `complete`：全部调用已展开。
  - `partial`：存在保留的调用或未解析依赖。
  - `fallback`：最终源码解析失败，返回原始快照。
- `expansion.diagnostics` 的坐标基于 `original.source`；`document.diagnostics` 合并最终解析诊断与换算后的展开诊断。

## 展开内容

支持模板嵌入与参数替换、include 标签、`#if`、`#ifeq`、`#switch`、`#iferror`、`{{!}}`、`{{=}}` 与隐式换行。

默认保留并产生诊断的调用：

- `#invoke` 与 Lua。
- `subst` 等嵌入修饰符。
- `#ifexist`、`#time` 等依赖站点状态或外部运行环境的函数。

细节见[模板展开指南](/zh/guide/templates.md)。

## 预算与失败

- 单次调用超长：保留调用并记录 `LENGTH_BUDGET_EXCEEDED`。
- 连保留源码都超过 `maxExpandedLength`：抛 `EXPANSION_TOO_LARGE`。
- `strict: true` 下预算超限：抛 `EXPANSION_BUDGET_EXCEEDED`。
- 默认模式下最终解析失败：退回原始有效快照，`status: "fallback"`。
- 取消时，Promise 以 `WikitextExpandError` 拒绝，错误码为 `ABORTED`，原始原因保存在 `cause` 中。

`parseOptions.maxSourceLength`、模板源码长度与 `maxExpandedLength` 分别生效；最终解析使用实际生效的 `maxExpandedLength`。

## 错误

```ts
class WikitextExpandError extends WikitextError {
  readonly templateTitle?: string;
  readonly range?: WikitextRange;
  constructor(
    code: WikitextExpandErrorCode,
    message: string,
    options?: { cause?: unknown; templateTitle?: string; range?: WikitextRange },
  );
}
```

常见错误码：

| 错误码                         | 触发条件               |
| --------------------------- | ------------------ |
| `INVALID_EXPAND_OPTIONS`    | 选项不合法              |
| `INCOMPATIBLE_PARSER`       | 注入的解析器不满足展开要求      |
| `TEMPLATE_NOT_FOUND`        | strict 模式下模板缺失     |
| `TEMPLATE_RESOLVE_FAILED`   | strict 模式下解析函数失败   |
| `TEMPLATE_PARSE_FAILED`     | strict 模式下模板源码解析失败 |
| `TEMPLATE_LOOP`             | strict 模式下检测到循环    |
| `UNSUPPORTED_CALL`          | strict 模式下遇到不支持的调用 |
| `UNRESOLVED_DEPENDENCY`     | strict 模式下依赖未解析    |
| `EXPANSION_BUDGET_EXCEEDED` | strict 模式下预算超限     |
| `EXPANSION_TOO_LARGE`       | 展开结果或保留源码超过长度上限    |
| `FINAL_PARSE_FAILED`        | strict 模式下最终解析失败   |
| `ABORTED`                   | 通过 `signal` 取消     |

## 与视图组合

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

const expanded = await expandWikitext(source, { resolveTemplate });
const prepared = prepareWikitext(expanded.document);
const view = <WikitextView document={prepared} />;
```

展开后的文档已经是解析结果，不必再次解析。未展开而保留的调用仍按模板、函数或参数占位渲染。
