# TSL API 文档标准

本文件是 TSL codegen API 文档的唯一标准，包含 markdown 存储格式、tsf 源码
文档格式、yaml/json 录入格式和统一索引格式。

适用范围：`references/codegen/**/*.md` 中的 function、class 和 unit API。

## 目录

- [TSL API 文档标准](#tsl-api-文档标准)
  - [目录](#目录)
  - [基本原则](#基本原则)
  - [markdown 存储格式](#markdown-存储格式)
    - [页面与统一顶级声明](#页面与统一顶级声明)
    - [function](#function)
    - [class](#class)
    - [unit](#unit)
    - [综合示例](#综合示例)
  - [tsf 源码文档格式](#tsf-源码文档格式)
    - [function](#function-1)
    - [class](#class-1)
    - [unit](#unit-1)
  - [录入数据结构](#录入数据结构)
    - [function](#function-2)
    - [class](#class-2)
    - [unit](#unit-2)
  - [录入文件格式](#录入文件格式)
    - [yaml](#yaml)
    - [json](#json)
  - [统一 API 索引](#统一-api-索引)

## 基本原则

- 发布的 API 文档使用本标准定义的 markdown 存储格式
- tsf 源码文档、yaml/json 录入数据与 markdown 的字段映射以本标准为准
- 一个录入文件对应一个 markdown 叶子页；录入根固定为
  `module`、`path`、`declarations`
- `declarations` 是非空有序列表，function、class、unit 可以混合；列表顺序即文档顺序
- function 调用签名只记录显式名称和参数名，不包含类型、默认值或语义推断内容
- API 标题的反引号内只写名称或调用签名，不写 function、class、property 等声明术语
- 每个 API 用独立的 `声明：...` 行记录声明种类
- 描述紧跟声明行；tags 是描述的检索补充，位于完整描述之后
- 描述末尾不写句号
- 示例输出必须全部写成 `//` 注释，不得把裸结果写成 TSL 语句
- 一个 `tsl` 代码块只放一个独立示例

## markdown 存储格式

### 页面与统一顶级声明

每个 markdown 叶子页使用一个 H1 模块标题，并包含一个或多个 H2 顶级声明。
function、class、unit 都是同级的顶级声明，可以出现在同一页面中；每个 H2 的声明
种类写在自身正文的 `声明：function|class|unit` 行中。

目录承担领域或模块分组，叶子页承担 API 主题分组，H2 承担顶级声明分组。markdown
不要求一个 class 对应一个 md；多个独立 class 声明可以进入同一叶子页，也可以在
内容过长或主题不同时拆到同一目录下的多个叶子页。例如
`OpenXmlAttribute` 和 `OpenXmlElement` 可以作为两个 H2 同处
`officexml/openxml/elements.md`。一个 markdown 叶子页可以收录多个对外顶级声明。

顶级声明和成员都按文档顺序存储，不按名称、种类或可见性重新排序。每个顶级声明
按以下共同顺序开始：

1. H2 标题：function 写调用签名，class 和 unit 写简单名称
2. 唯一且精确的 `声明：function`、`声明：class` 或 `声明：unit`
3. 描述，必填；声明行之后的首个非空正文必须是描述
4. `<!-- tags: 关键词1 关键词2 -->`，可选；位于完整描述之后

标题层级和声明值必须符合下表，不允许在其他层级使用这些声明值：

| 位置                         | 标题层级 | 允许的声明值                                                                               |
| ---------------------------- | -------- | ------------------------------------------------------------------------------------------ |
| 顶级声明                     | H2       | `function`、`class`、`unit`                                                                |
| 顶级 class 成员              | H3       | `function`、`class function`、`property`、`field`、`static field`、`const`、`static const` |
| unit interface direct member | H3       | `function`、`var`、`const`、`class`                                                        |
| unit interface class 成员    | H4       | 与顶级 class 成员相同                                                                      |

H2、H3、H4 中反引号包围的内容是 API 名称或调用签名。`function`、
`class function`、`property` 等声明术语只写在声明行中，不写进标题。

本标准中的“调用签名”只包含名称和参数名，例如 `abs(x)`，不是 TSL 声明语句
`function abs(x);`。声明行只参与文档结构识别，不属于名称、调用签名或调用语法。
例如 class 下的 H3 标题 `Save()` 紧跟 `声明：function`，表示实例 function；可调用
内容仍是 `Save()`，不能把两行拼成 `function Save()`。

每个 API 必须且只能写一行 `声明：...`，并将它作为标题后的第一条非空正文。
`声明` 后使用全角冒号，声明值使用本标准规定的小写形式。普通内容标题不包含
反引号，也不紧跟声明行，因此不进入 API 索引；普通 H2 同时结束前一个顶级声明的
正文范围。

同一所属范围和声明种类内，重复 class/unit 名称或重复 function 调用签名不允许；
function 重载和跨声明种类同名允许。

### function

#### 页面结构

顶级 function 使用 H2，function 的示例标题使用 H3。每个 function 声明按以下
顺序书写：

1. `## \`调用签名\``
2. `声明：function`
3. 函数描述，必填
4. `<!-- tags: 关键词1 关键词2 -->`，可选
5. 参数表，有参数时必填
6. 参数取值说明，可选
7. `返回：类型`
8. `### 示例`，可选；包含一个或多个“范例NN：说明”和独立的 `tsl` 代码块

#### 标签

标签位于完整函数描述之后，用空格分隔检索关键词：

```markdown
<!-- tags: 数组 排序 去重 -->
```

没有关键词时删除整行，不保留空标签。

#### 参数表

参数表固定为三列：

```markdown
| 参数 | 类型 | 说明 |
| --- | --- | --- |
| `src` | array | 待处理数组 |
```

规则：

- 参数名必须与 function 调用签名一致
- 必填参数说明直接写用途
- 可选参数说明以 `可选。` 开头，并说明默认值
- 多类型使用 `\|`，例如 `nil\|array`
- 变参使用 `...` 作为参数名
- 无参 function 省略参数表

#### 参数取值

枚举参数在参数表之后、返回类型之前列出：

```markdown
mode 取值

- `0` — 原样返回
- `1` — 去重
```

顶级 function 的参数取值使用上述普通文本行，不使用 H3、H4 或强调文本。class method 的参数取值使用 H4 标题，例如 `#### \`mode\` 取值`；unit interface class method 使用 H5 标题。参数取值标题不是 API 声明，不进入统一索引

#### 返回类型

每个顶层 function 必须包含非空返回类型：

```markdown
返回：array
```

#### 示例代码

- 每个示例以“范例NN：说明”开头，编号按出现顺序排列并至少保留两位
- 同一 function 只使用一个示例组标题；顶级 function 使用 `### 示例`，class method 使用 `#### 示例`，unit interface class method 使用 `##### 示例`
- “范例NN：说明”是示例组内的普通文本，不使用 H4 或 H5 标题
- 代码围栏使用 `tsl`
- 一个代码围栏只放一个独立示例
- 字符串使用直引号 `'` 或 `"`
- 注释使用 `//`，不使用 `(* *)`
- 每条语句保留分号
- 没有输出时可以省略输出注释
- 单行输出写成 `// 输出：<值>`
- 多行输出第一行写 `// 输出：`，后续每一行输出都以 `//` 开头

多行输出示例：

```tsl
return demoLines();
// 输出：
// 第一行
// 第二行
```

#### 完整页面示例

以下 API 仅用于说明存储格式，不代表真实 TSL API：

````markdown
# 示例 / 数组

## `demoFn(src, mode, factor, ...)`

声明：function

按指定模式处理数组并返回结果

<!-- tags: 示例 数组 -->

| 参数     | 类型       | 说明                             |
| -------- | ---------- | -------------------------------- |
| `src`    | array      | 待处理数组                       |
| `mode`   | integer    | 处理模式，取值见下               |
| `factor` | float      | 可选。默认 1.0，结果乘以该系数   |
| `...`    | nil\|array | 可选。需要追加处理的其他数组     |

mode 取值

- `0` — 原样返回
- `1` — 去重

返回：array

### 示例

范例01：指定处理模式和系数

```tsl
src := array(1, 1, 2);
return demoFn(src, 1, 2.0);
// 输出：array(2,4)
```

范例02：使用默认系数

```tsl
src := array(1, 1, 2);
return demoFn(src, 0);
```

## `demoNow()`

声明：function

返回示例值

返回：integer
````

### class

#### 页面结构

顶级 class 使用 H2，class 成员使用 H3，function 的参数取值或示例使用 H4。H2 正文
按以下顺序书写：

1. `## \`ClassName\``
2. `声明：class`
3. class 描述，必填
4. tags，可选；位于完整描述之后
5. `父类：BaseClass`，可选；多父类按声明顺序列出
6. class 成员，按声明顺序书写

#### 成员标题与正文

class 成员标题统一只写反引号包围的名称或调用签名，例如
`### \`Create(name)\``、`### \`Title\``。成员的声明种类由标题后的声明行表达：

- 实例方法：`声明：function`
- 类方法：`声明：class function`
- property：`声明：property`
- 实例/静态字段：`声明：field` / `声明：static field`
- 实例/静态常量：`声明：const` / `声明：static const`

每个成员都按“标题、声明行、描述、tags、成员数据”的共同顺序开始。function 的
正文结构与顶级 function 相同，实例 function 和 class function 都按描述、tags、
参数表、参数取值、返回类型、示例的顺序书写。源码声明了返回类型时必须写
`返回：类型`；没有返回类型时省略，不补写 `void`。位于 class 中时，
标题及其子标题整体下移一级：function 标题从 H2 变为 H3，参数取值和示例标题从 H3
变为 H4。成员另外必须写 `可见性：public|protected`，并可写 `修饰符`；类方法由
`声明：class function` 表达。

property 必须写访问方式；有类型时写 `类型：...`，没有类型时省略。field 必须写
类型，const 必须写值。

#### 完整页面示例

以下示例以 `OpenXmlAttribute` 的公开成员为基础，并加入一个 class function，用于
说明 class 的 markdown 存储格式：

```markdown
# OfficeXml / OpenXml

## `OpenXmlAttribute`

声明：class

表示一个 OpenXml 属性

<!-- tags: OpenXml XML 属性 -->

### `create(_prefix, _local_name)`

声明：function

创建不带初始值的 OpenXml 属性

<!-- tags: OpenXml 属性 创建 -->

可见性：`public`

修饰符：`overload`

| 参数          | 类型   | 说明         |
| ------------- | ------ | ------------ |
| `_prefix`     | string | 命名空间前缀 |
| `_local_name` | string | 本地名称     |

### `create(_prefix, _local_name, _value)`

声明：function

创建带初始值的 OpenXml 属性

<!-- tags: OpenXml 属性 创建 -->

可见性：`public`

修饰符：`overload`

| 参数          | 类型   | 说明         |
| ------------- | ------ | ------------ |
| `_prefix`     | string | 命名空间前缀 |
| `_local_name` | string | 本地名称     |
| `_value`      | any    | 属性值       |

### `CreateVirtual(position, row_index, _story)`

声明：class function

创建虚段落

可见性：`public`

| 参数        | 类型      | 说明     |
| ----------- | --------- | -------- |
| `position`  | integer   | 段落位置 |
| `row_index` | integer   | 行索引   |
| `_story`    | StoryNode | 故事节点 |

返回：ParagraphSegment

### `Prefix`

声明：property

命名空间前缀

可见性：`public`

类型：string

访问：read / write

### `LocalName`

声明：property

本地名称

可见性：`public`

类型：string

访问：read / write

### `ElementName`

声明：property

包含前缀的完整属性名称

可见性：`public`

类型：string

访问：read / write

### `Value`

声明：property

属性值

可见性：`public`

类型：any

访问：read / write

### `NamespaceUri`

声明：property

命名空间 URI

可见性：`public`

类型：string

访问：read / write
```

### unit

#### 页面结构

顶级 unit 使用 H2，interface direct member 使用 H3，interface class 的成员或
unit function 的参数取值/示例使用 H4，interface class function 的参数取值/示例
使用 H5。H2 正文按以下顺序书写：

1. `## \`UnitName\``
2. `声明：unit`
3. unit 描述，必填
4. tags，可选；位于完整描述之后
5. interface direct member，按声明顺序书写

#### 成员标题与正文

H3 direct member 标题只写名称或调用签名。标题后的声明行只允许：

- interface function：`声明：function`
- variable：`声明：var`
- constant：`声明：const`
- interface class：`声明：class`

每个 direct member 都按“标题、声明行、描述、tags、成员数据”的共同顺序开始。
unit direct member 都来自 interface，visibility 固定为 `public`，正文不重复记录。
unit function 复用顶级 function 格式并要求返回
类型，var 必须写类型，const 必须写值。interface class 的 H4 成员复用顶级
class 的成员格式，并显式写 `可见性：public|protected`。

#### 完整页面示例

```markdown
# 示例 / 文档运行时

## `DocumentUnit`

声明：unit

提供文档运行时接口

<!-- tags: 运行时 文档 -->

### `DefaultSize`

声明：const

默认缓冲区大小

值：`100`

### `CurrentDocument`

声明：var

当前文档

类型：Document

### `OpenDocument(path)`

声明：function

打开文档

| 参数   | 类型   | 说明     |
| ------ | ------ | -------- |
| `path` | string | 文档路径 |

返回：Document

### `Document`

声明：class

文档对象

父类：`BaseDocument`

#### `Save()`

声明：function

保存文档

可见性：`public`

返回：boolean
```

### 综合示例

同一叶子页可以按文档顺序混合三种顶级声明。以下 API 仅用于说明存储格式，不代表
真实 TSL API：

````markdown
# OfficeXml / OpenXml

## `OpenXmlAttribute`

声明：class

表示 OpenXml 属性

<!-- tags: OpenXml XML 属性 -->

### `create(_prefix, _local_name)`

声明：function

创建属性

<!-- tags: OpenXml 属性 创建 -->

可见性：`public`

| 参数          | 类型   | 说明         |
| ------------- | ------ | ------------ |
| `_prefix`     | string | 命名空间前缀 |
| `_local_name` | string | 本地名称     |

## `ParseOpenXml(xml)`

声明：function

解析 OpenXml 文本

<!-- tags: OpenXml XML 解析 -->

| 参数  | 类型   | 说明         |
| ----- | ------ | ------------ |
| `xml` | string | OpenXml 文本 |

返回：OpenXmlElement

### 示例

范例01：解析文本

```tsl
return ParseOpenXml('<root/>');
```

## `OpenXmlRuntime`

声明：unit

提供 OpenXml 运行时接口

<!-- tags: OpenXml 运行时 -->

### `OpenXmlElement`

声明：class

表示文档元素

<!-- tags: OpenXml XML 元素 -->

#### `Save()`

声明：function

保存元素

可见性：`public`

返回：boolean
````

## tsf 源码文档格式

tsf 主要使用 `function`、`unit` 和 `type` 三种顶层组织方式。本标准按这三种方式
分别定义源码文档格式。每个 tsf 源码文档对应一个对外顶级声明。

### function

独立顶层 `function` 可以在源码中记录函数级文档。签名、参数类型、默认参数和返回
类型由源码声明提供，描述、标签、参数说明、枚举值和示例由文档块提供。

- 一个 function tsf 文件只以第一个顶层 function 作为对外主函数；后续辅助函数不属于
  该文件的对外文档
- 顶层 `procedure` 不在本节规定的 function 文档格式范围内
- `module` 和 `path` 是页面级录入字段，不属于单个函数的文档块

#### 文档块位置

文档块必须是主函数 `begin` 之后的第一段非空内容，并且位于任何可执行语句、
编译指令或其他注释之前

文档块由连续的 `///` 行组成，并允许按照函数体缩进。`///` 之前的空白以及其后的
一个可选空格不属于文档内容。遇到第一行非 `///` 内容时，文档块结束；函数体后续
位置的注释是普通注释

TSL 解释器将 `///` 作为普通的 `//` 行注释；本标准使用第三个 `/` 区分文档行与普通
注释

#### 文档块结构

文档块按以下顺序书写：

1. 函数描述，一行或多行，必填
2. `@tags: 标签1 标签2`，可选，最多一行，标签使用空白分隔
3. 参数组，按声明顺序书写；每组先写 `@param: name 参数说明`，再按需紧跟一个
   `@values: name`
4. `@returns: 类型`，可选，最多一行
5. 示例组，可选，可以重复；所有示例组必须位于文档块末尾

空的 `///` 行可以在多行函数描述或示例中保留空行。指令名固定为小写；未知指令、
重复的 `@tags:`/`@returns:`、同一参数重复的 `@param:`/`@values:`，以及不符合上述
顺序的指令均不符合本标准。`@example:` 可以重复，`@output:` 在同一示例组内最多出现
一次。

| 写法                    | 必填     | json 映射                          | 规则                                                           |
| ----------------------- | -------- | ---------------------------------- | -------------------------------------------------------------- |
| 描述正文                | 是       | `declarations[].desc`              | 第一条指令之前的所有正文，保留换行                             |
| `@tags: 标签1 标签2`    | 否       | `declarations[].tags`              | 使用一个或多个空白字符分隔；忽略首尾空白；标签本身不得包含空白 |
| `@param: name 参数说明` | 有参时   | `declarations[].params[].desc`     | 第一个词是参数名，其余内容是说明；说明不得为空                 |
| `@values: name`         | 否       | `declarations[].params[].values`   | 值表规则见下；参数必须已经由 `@param:` 声明                    |
| `@returns: 类型`        | 否       | `declarations[].returns`           | 类型不得为空；与声明返回类型同时存在时必须一致                 |
| `@example: 示例说明`    | 否       | `declarations[].examples[].desc`   | 开始一个示例组；说明不得为空                                   |
| 示例代码                | 示例组内 | `declarations[].examples[].code`   | 内容行额外缩进两个空格；至少包含一个非空代码行                 |
| `@output:`              | 否       | `declarations[].examples[].output` | 原始输出额外缩进两个空格；存在时不得为空                       |

`@param:` 和 `@values:` 中的参数名与函数声明大小写无关地匹配；映射后的参数名保留
函数声明中的拼写。

#### 字段来源与映射

以下字段由主函数声明以及必要的文档指令确定：

| tsf 声明内容   | json 字段                          | 映射规则                                          |
| -------------- | ---------------------------------- | ------------------------------------------------- |
| 函数名         | `declarations[].name`              | 保留声明名称                                      |
| 函数名和参数名 | `declarations[].signature`         | 规范化为只含名称的调用形式，不复制类型或默认值    |
| 参数类型       | `declarations[].params[].type`     | 保留声明中的类型                                  |
| 参数默认值     | `declarations[].params[].optional` | 存在默认值时为 `true`，默认表达式不另建 json 字段 |
| 返回类型       | `declarations[].returns`           | 取自声明和 `@returns:`，按下述规则合并            |

完整录入数据必须包含每个参数的显式类型和非空说明，并通过函数声明或 `@returns:`
提供返回类型。
可选参数的说明仍应写清默认值含义；`optional: true` 只表达该参数可以省略。

返回类型按以下规则合并：

- 只有函数声明时，使用声明中的拼写
- 只有 `@returns:` 时，去除首尾空白后使用指令中的拼写
- 两处同时存在时，使用相同的词法规则拆分类型，忽略 token 之间的空白，并按 TSL
  标识符大小写无关的规则比较标识符 token；其他 token 必须一致。两处类型必须匹配，
  映射后使用声明中的拼写
- 两处都不存在时，不满足顶级 function 的 `returns` 必填要求

本标准只定义类型的词法一致性，不定义类型别名等语义等价关系。

#### 枚举值表

枚举值表使用分组格式，每一项在 `///` 标记后额外缩进两个空格：

```text
/// @param: mode 处理模式，默认 0
/// @values: mode
///   0: 原样返回
///   1: 去重
///   "auto": 自动判断
```

规则：

- 枚举值使用 json 标量写法：数字直接写，字符串使用双引号，布尔值使用
  `true`/`false`；`nil` 等符号值按字符串写成 `"nil"`
- 不接受数组、对象或 json `null`
- 值和说明以值后的第一个分隔冒号分开；说明不得为空
- 保留枚举项的声明顺序
- 同一参数最多有一个非空值表，不允许重复值；不同 json 类型的值不视为重复，
  例如数字 `1` 与字符串 `"1"` 是两个值
- `@values:` 引用的参数必须存在
- tsf 作者必须保证枚举值与参数类型在语义上兼容

#### 示例组

每个示例组以非空的 `@example: 示例说明` 开始。其后的代码行必须在 `///` 标记后
额外缩进两个空格。可选的 `@output:` 结束代码部分，其后的缩进行记录原始输出；下一个
`@example:` 开始新的示例组。第一个示例组出现后，不得再写参数、返回类型等其他函数
级指令。

映射到录入数据时，移除代码和输出的两个结构缩进，保留其余空白和换行。示例说明、
代码和输出分别映射为 `examples[].desc`、`examples[].code` 和 `examples[].output`。`desc` 与
`code` 必填且非空；`output` 可选，但出现时必须包含至少一个非空行。示例顺序保持
不变。

`code` 只记录示例源码，不得包含标准输出标记 `// 输出：`。`output` 只记录原始输出，
不写 `//` 注释标记。映射到 markdown 时：

- 所有示例共用一个 `### 示例` 标题
- 每项按顺序写为“范例01：说明”“范例02：说明”
- 每项使用一个独立的 `tsl` 代码块
- 没有 `output` 时，代码块只包含 `code`
- 单行 `output` 在代码末尾写为 `// 输出：<值>`
- 多行 `output` 先写 `// 输出：`，再为每个输出行添加 `//` 和一个空格；空输出行使用
  单独的 `//`

#### 完整 tsf 示例

以下内容应保存为 `Normalize.tsf`：

```tsl
function Normalize(mode: integer = 0): integer;
begin
    /// 按指定模式处理并返回模式值
    /// @tags: 示例 枚举
    /// @param: mode 处理模式，默认 0
    /// @values: mode
    ///   0: 原样返回
    ///   1: 去重
    ///   2: 排序
    /// @returns: integer
    /// @example: 使用默认模式
    ///   return Normalize();
    /// @output:
    ///   0
    /// @example: 指定模式
    ///   return Normalize(1);
    return mode;
end;
```

对应的顶级 function 录入对象为：

```json
{
  "kind": "function",
  "name": "Normalize",
  "signature": "Normalize(mode)",
  "desc": "按指定模式处理并返回模式值",
  "tags": ["示例", "枚举"],
  "params": [
    {
      "name": "mode",
      "type": "integer",
      "optional": true,
      "desc": "处理模式，默认 0",
      "values": [
        {"value": 0, "desc": "原样返回"},
        {"value": 1, "desc": "去重"},
        {"value": 2, "desc": "排序"}
      ]
    }
  ],
  "returns": "integer",
  "examples": [
    {
      "desc": "使用默认模式",
      "code": "return Normalize();",
      "output": "0"
    },
    {
      "desc": "指定模式",
      "code": "return Normalize(1);"
    }
  ]
}
```

### class

`Counter.tsf`

```tsl
type Counter = class
/// 表示计数器
/// @tags: 示例 计数
public
    /// 创建计数器
    /// @param: initial_value 初始值
    function create(initial_value: integer);

    /// 计算两个整数之和
    /// @tags: 示例 加法
    /// @param: x 第一个整数
    /// @param: y 第二个整数
    /// @returns: integer
    class function Add(x: integer; y: integer): integer;
    begin
        return x + y;
    end;

    /// 增加当前值
    /// @param: step 增量
    /// @returns: integer
    /// @example: 增加计数
    ///   counter := new Counter(1);
    ///   return counter.Increase(2);
    /// @output:
    ///   3
    function Increase(step: integer): integer;

    /// 当前值
    /// @tags: 状态
    property Value read value_ write value_;

    /// 显示名称
    Label: string;

    /// 最小值
    const Minimum = 0;

protected
    /// 已创建的计数器数量
    static CreatedCount: integer;

    /// 最大值
    static const Maximum = 100;

private
    /// 内部值
    value_: integer;
end;

type CounterState = class
/// 表示内部状态
public
    /// 状态码
    Code: integer;
end;

function Counter.create(initial_value: integer);
begin
    value_ := initial_value;
end;

function Counter.Increase(step: integer): integer;
begin
    value_ := value_ + step;
    return value_;
end;
```

对应的 class 录入对象为：

```json
{
  "kind": "class",
  "name": "Counter",
  "desc": "表示计数器",
  "tags": ["示例", "计数"],
  "members": [
    {
      "kind": "method",
      "name": "create",
      "visibility": "public",
      "binding": "instance",
      "signature": "create(initial_value)",
      "desc": "创建计数器",
      "params": [
        {
          "name": "initial_value",
          "type": "integer",
          "desc": "初始值"
        }
      ]
    },
    {
      "kind": "method",
      "name": "Add",
      "visibility": "public",
      "binding": "class",
      "signature": "Add(x, y)",
      "desc": "计算两个整数之和",
      "tags": ["示例", "加法"],
      "params": [
        {
          "name": "x",
          "type": "integer",
          "desc": "第一个整数"
        },
        {
          "name": "y",
          "type": "integer",
          "desc": "第二个整数"
        }
      ],
      "returns": "integer"
    },
    {
      "kind": "method",
      "name": "Increase",
      "visibility": "public",
      "binding": "instance",
      "signature": "Increase(step)",
      "desc": "增加当前值",
      "params": [
        {
          "name": "step",
          "type": "integer",
          "desc": "增量"
        }
      ],
      "returns": "integer",
      "examples": [
        {
          "desc": "增加计数",
          "code": "counter := new Counter(1);\nreturn counter.Increase(2);",
          "output": "3"
        }
      ]
    },
    {
      "kind": "property",
      "name": "Value",
      "visibility": "public",
      "desc": "当前值",
      "tags": ["状态"],
      "access": "readwrite"
    },
    {
      "kind": "field",
      "name": "Label",
      "visibility": "public",
      "desc": "显示名称",
      "type": "string"
    },
    {
      "kind": "constant",
      "name": "Minimum",
      "visibility": "public",
      "desc": "最小值",
      "value": "0"
    },
    {
      "kind": "field",
      "name": "CreatedCount",
      "visibility": "protected",
      "desc": "已创建的计数器数量",
      "type": "integer",
      "static": true
    },
    {
      "kind": "constant",
      "name": "Maximum",
      "visibility": "protected",
      "desc": "最大值",
      "value": "100",
      "static": true
    }
  ]
}
```

### unit

本标准的 unit 源码文档采用包含显式 `interface`、`implementation` 并以 `end.` 结束的
完整形态；简写 unit 不在本标准范围内。unit 名称必须与文件名大小写无关地一致。

unit 文档块位于 `unit Name;` 之后、`interface` 之前，只允许描述和可选
`@tags:`。对外文档按声明顺序包含 interface 中的 function、var、const 和 class；
`uses` 只表示依赖，不属于 API。interface class 完整复用独立 class 的成员规则，
interface 中的所有 class 均属于对外文档。每个 `///` 文档块必须绑定到 unit 或
interface 成员。

implementation 中的函数、类、变量、常量和 `///` 文档块不属于对外文档。interface
中的 procedure 和非 class type 不在本标准范围内。interface function 复用 function
文档指令并要求返回类型；var/const 只允许描述和可选 `@tags:`，且一项一条声明。

## 录入数据结构

一个录入文件对应一个 markdown 叶子页。录入根只允许 `module`、`path`、
`declarations`。`declarations` 必须是非空有序列表，function、class、unit 可以
任意混合；数组顺序即 markdown 中的 H2 声明顺序。

顶层字段：

| 字段           | 必填 | 说明                                                                                                                 |
| -------------- | ---- | -------------------------------------------------------------------------------------------------------------------- |
| `module`       | 是   | markdown 一级标题内容；不是目录名或文件名。例如 `module: 示例 / 数组` 对应 `# 示例 / 数组`                           |
| `path`         | 是   | markdown 在所属 scope 下的相对路径，使用 `/` 分隔且不含 `.md` 后缀。例如 `path: base/example` 对应 `base/example.md` |
| `declarations` | 是   | 非空顶级声明列表；每项由 `kind` 判别并要求 `name`，数组顺序即 H2 顺序                                                |

### function

顶级 function 对象字段：

| 字段        | 必填   | 说明                                                   |
| ----------- | ------ | ------------------------------------------------------ |
| `kind`      | 是     | 固定为 `function`                                      |
| `name`      | 是     | function 简单名称；必须与 `signature` 中的名称一致     |
| `signature` | 是     | 只包含名称和参数名的调用签名                           |
| `desc`      | 是     | 函数描述，可包含多行                                   |
| `tags`      | 否     | 检索关键词列表；推荐填写，有助于更准确地识别和检索函数 |
| `params`    | 有参时 | 参数列表；无参函数省略                                 |
| `returns`   | 是     | 返回类型                                               |
| `examples`  | 否     | 示例列表；按顺序映射为独立的 TSL 代码块                |

参数字段：

| 字段       | 必填 | 说明                                                   |
| ---------- | ---- | ------------------------------------------------------ |
| `name`     | 是   | 参数名，与签名一致                                     |
| `type`     | 是   | 参数类型                                               |
| `desc`     | 是   | 参数说明                                               |
| `optional` | 否   | `true` 表示可选参数；markdown 参数说明以 `可选。` 开头 |
| `values`   | 否   | 枚举值列表，对应参数取值说明                           |

`values` 每项包含：

| 字段    | 必填 | 说明     |
| ------- | ---- | -------- |
| `value` | 是   | 枚举值   |
| `desc`  | 是   | 枚举含义 |

`examples` 每项包含：

| 字段     | 必填 | 说明                                           |
| -------- | ---- | ---------------------------------------------- |
| `desc`   | 是   | 示例场景说明；对应“范例NN：说明”               |
| `code`   | 是   | 不含代码围栏和标准输出注释的 TSL 代码          |
| `output` | 否   | 原始输出；按单行或多行规则映射为 `//` 输出注释 |

### class

class 对象字段：

| 字段      | 必填 | 说明                                      |
| --------- | ---- | ----------------------------------------- |
| `kind`    | 是   | 固定为 `class`                            |
| `name`    | 是   | class 简单名称                            |
| `desc`    | 是   | class 描述                                |
| `tags`    | 否   | 检索关键词列表                            |
| `bases`   | 否   | 按声明顺序保存的直接父类列表              |
| `members` | 是   | method/property/field/constant 的有序列表 |

所有 class member 都要求 `name`、`desc` 和 `visibility`。
所有 class member 都可以包含可选的 `tags`。visibility 只能是 `public` 或
`protected`。成员判别字段如下：

| kind       | 关键字段                                                                          |
| ---------- | --------------------------------------------------------------------------------- |
| `method`   | `signature`、`binding: instance\|class`；可选 `params/returns/modifiers/examples` |
| `property` | `access: read\|write\|readwrite`；可选 `type`，参数化时包含 `params`              |
| `field`    | `type`；可选 `static: true`                                                       |
| `constant` | `value`；可选 `type`、`static: true`                                              |

`kind: method` 对象不使用 `static` 字段；class function 由 `binding: class` 唯一
表达。`value` 的存在性与真假值分开判断，因此数字 `0` 和布尔值 `false` 都是合法
常量值。
这里的 `method` 是录入结构内部用于统一表达实例 function 和 class function 的 kind，
不对应 markdown 标题或 `声明：...` 行中的声明值。

### unit

顶级 unit 对象包含固定的 `kind: unit`，以及必填的 `name`、`desc`、`members`
和可选 `tags`。direct member 按 interface 源码顺序保存，kind 只允许：

| kind       | 关键字段                                                 |
| ---------- | -------------------------------------------------------- |
| `function` | 复用顶层 function 数据；`returns` 必填                   |
| `variable` | `name`、`desc`、`type`，可选 `tags`                      |
| `constant` | `name`、`desc`、`value`，可选 `tags/type`                |
| `class`    | 复用完整 class 数据，并以 `kind: class` 作为成员判别字段 |

录入数据不保存 unit 的 `uses`、implementation、initialization 或 finalization。

## 录入文件格式

### yaml

yaml 录入文件应符合以下规则：

- `examples[].code` 和多行 `examples[].output` 使用 `|` 块标量
- 参数名 `...` 必须加引号
- `nil|array` 可直接作为普通字符串值

完整例子：[examples/example.yaml](examples/example.yaml)

### json

json 录入文件应符合以下规则：

- json 不支持注释
- 多行 `examples[].code` 和 `examples[].output` 使用 `\n`
- 字符串内部的双引号使用 `\"`
- 结构标点必须使用半角字符

完整例子：[examples/example.json](examples/example.json)

## 统一 API 索引

`function_index.tsv` 固定为 13 列：

```text
name scope module signature page anchor tags summary kind binding visibility owner qualified_name
```

字段含义：

- `kind`：`function|class|method|property|field|constant|unit|variable`
- `binding`：不适用时为空，否则为 `instance|class|static|unit`
- `visibility`：class member 为 `public|protected`，unit direct member 为 `public`
- `owner`：不含该 API 名称的完整所属路径
- `qualified_name`：点分隔的稳定文档身份

索引的 `kind` 和 `binding` 由声明行和所属层级按下表确定：

| markdown 位置                | `声明：...`      | 录入对象表达                      | 索引 `kind` | 索引 `binding` |
| ---------------------------- | ---------------- | --------------------------------- | ----------- | -------------- |
| H2 顶级声明                  | `function`       | `kind: function`                  | `function`  | 空             |
| H2 顶级声明                  | `class`          | `kind: class`                     | `class`     | 空             |
| H2 顶级声明                  | `unit`           | `kind: unit`                      | `unit`      | 空             |
| 顶级/interface class 成员    | `function`       | `kind: method, binding: instance` | `method`    | `instance`     |
| 顶级/interface class 成员    | `class function` | `kind: method, binding: class`    | `method`    | `class`        |
| 顶级/interface class 成员    | `property`       | `kind: property`                  | `property`  | `instance`     |
| 顶级/interface class 成员    | `field`          | `kind: field`                     | `field`     | `instance`     |
| 顶级/interface class 成员    | `static field`   | `kind: field, static: true`       | `field`     | `static`       |
| 顶级/interface class 成员    | `const`          | `kind: constant`                  | `constant`  | `instance`     |
| 顶级/interface class 成员    | `static const`   | `kind: constant, static: true`    | `constant`  | `static`       |
| unit interface direct member | `function`       | `kind: function`                  | `function`  | `unit`         |
| unit interface direct member | `var`            | `kind: variable`                  | `variable`  | `unit`         |
| unit interface direct member | `const`          | `kind: constant`                  | `constant`  | `unit`         |
| unit interface direct member | `class`          | `kind: class`                     | `class`     | `unit`         |

表中的 interface class 成员指 unit interface class 的 H4 成员；其允许的声明值和
派生规则与顶级 class 的 H3 成员完全相同。

例如 class function `Widget.Create` 的 owner 是 `Widget`；unit interface class
function `DemoUnit.Document.Save` 的 owner 是 `DemoUnit.Document`。重载共享
`qualified_name`，由 `signature` 和唯一的 `page#anchor` 区分。
