Add TSF conversion and shared Markdown recognition for mixed function, class, and unit declarations. Extend generation, linting, indexing, examples, and tests around the unified declaration model.
1137 lines
38 KiB
Markdown
1137 lines
38 KiB
Markdown
# 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-索引)
|
||
|
||
## 基本原则
|
||
|
||
- markdown 是唯一存储源
|
||
- yaml/json 用于生成 markdown
|
||
- tsf 源码文档可以转换为 json 或 yaml 录入稿,再由同一生成流程产出 markdown
|
||
- 一个录入文件对应一个 markdown 叶子页;录入根固定为
|
||
`module`、`path`、`declarations`
|
||
- `declarations` 是非空有序列表,function、class、unit 可以按输入顺序混合
|
||
- 生成器写入 markdown 前必须使用仓库锁定版本的 Prettier 统一格式
|
||
- 转换器允许生成描述或类型不完整的草稿;生成器严格校验,不发布不完整录入稿
|
||
- function 调用签名由维护者或转换器提供;工具不推断 API 语义
|
||
- 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 TSF 的对外声明可以进入同一叶子页,
|
||
也可以在内容过长或主题不同时拆到同一目录下的多个叶子页。例如
|
||
`OpenXmlAttribute` 和 `OpenXmlElement` 可以作为两个 H2 同处
|
||
`officexml/openxml/elements.md`。每个 TSF 文件对应一个对外顶级声明,一个 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 必须包含非空返回类型:
|
||
|
||
```markdown
|
||
返回:array
|
||
```
|
||
|
||
#### 示例代码
|
||
|
||
- 每个示例以“范例NN:说明”开头,编号按出现顺序自动生成并至少保留两位
|
||
- 代码围栏使用 `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,因此正文不重复写 public;统一索引把其
|
||
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` 可以在源码中记录录入数据所需的函数级内容。签名、参数类型、
|
||
默认参数和返回类型直接读取源码声明。
|
||
|
||
- 一个 tsf 文件只记录第一个主函数;文件中的后续辅助函数不进入录入数据
|
||
- 顶层 `procedure` 不按 `function` 格式处理
|
||
- 多个 tsf 可以与 class/unit TSF 混合生成同一个 json/yaml 录入文件;页面级
|
||
`module` 和 `path` 在转换时统一提供,不写进单个函数的注释
|
||
|
||
#### 文档块位置
|
||
|
||
文档块必须是主函数 `begin` 之后的第一段非空内容,并且位于任何可执行语句、
|
||
编译指令或其他注释之前
|
||
|
||
文档块由连续的 `///` 行组成。允许按照函数体缩进;解析时忽略 `///` 之前的空白,
|
||
并移除 `///` 及其后的一个可选空格。遇到第一行非 `///` 内容时,文档块结束;函数体
|
||
后续位置的注释是普通注释
|
||
|
||
TSL 解释器将 `///` 作为普通的 `//` 行注释;第三个 `/` 是 codegen 用来识别文档行的
|
||
标记
|
||
|
||
#### 文档块结构
|
||
|
||
文档块按以下顺序书写:
|
||
|
||
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:` 中的参数名与函数声明大小写无关地匹配,json 使用函数声明中的
|
||
参数拼写。
|
||
|
||
#### 字段来源与映射
|
||
|
||
以下字段由主函数声明以及必要的文档指令确定:
|
||
|
||
| tsf 声明内容 | json 字段 | 转换规则 |
|
||
| -------------- | ---------------------------------- | --------------------------------------------------- |
|
||
| 函数名 | `declarations[].name` | 保留声明名称 |
|
||
| 函数名和参数名 | `declarations[].signature` | 规范化为只含名称的调用形式,不复制类型或默认值 |
|
||
| 参数类型 | `declarations[].params[].type` | 保留声明中的类型 |
|
||
| 参数默认值 | `declarations[].params[].optional` | 存在默认值时写入 `true`,默认表达式不另建 json 字段 |
|
||
| 返回类型 | `declarations[].returns` | 读取声明和 `@returns:`,按下述规则合并 |
|
||
|
||
要直接得到可生成 markdown 的完整录入数据,函数必须显式声明每个参数的类型,为每个
|
||
参数提供非空的 `@param:`,并通过函数声明或 `@returns:` 提供返回类型。缺少这些内容
|
||
时只能得到待手工完善的录入稿。
|
||
可选参数的说明仍应写清默认值含义;`optional: true` 只表达该参数可以省略。
|
||
|
||
返回类型按以下规则合并:
|
||
|
||
- 只有函数声明时,使用声明中的拼写
|
||
- 只有 `@returns:` 时,去除首尾空白后使用指令中的拼写
|
||
- 两处同时存在时,转换器使用与函数声明相同的词法规则拆分类型,忽略 token 之间的
|
||
空白,并按 TSL 标识符大小写无关的规则比较标识符 token;其他 token 必须一致。
|
||
校验通过后使用声明中的拼写,校验失败则定位 `@returns:` 行、报错并停止转换
|
||
- 两处都不存在时,录入稿中的 `returns` 为空,不能直接生成 markdown
|
||
|
||
转换器只校验类型的词法结构,不判断类型别名等语义等价。
|
||
|
||
#### 枚举值表
|
||
|
||
枚举值表使用分组格式,每一项在 `///` 标记后额外缩进两个空格:
|
||
|
||
```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 后停止收集 API;其中的函数、类、变量、常量和 `///` 文档块
|
||
全部忽略。interface 中的 procedure 和非 class type 不支持,必须在声明行报错,
|
||
不能静默遗漏。interface function 复用 function 文档指令并要求最终返回类型;
|
||
var/const 只允许描述和可选 `@tags:`,且一项一条声明。
|
||
|
||
## 录入数据结构
|
||
|
||
一个录入文件对应一个 markdown 叶子页。录入根只允许 `module`、`path`、
|
||
`declarations`。`declarations` 必须是非空有序列表,function、class、unit 可以
|
||
任意混合,生成器严格保持数组顺序。
|
||
|
||
顶层字段:
|
||
|
||
| 字段 | 必填 | 说明 |
|
||
| -------------- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||
| `module` | 是 | markdown 一级标题内容;不是目录名或文件名。例如 `module: 示例 / 数组` 生成 `# 示例 / 数组` |
|
||
| `path` | 是 | 目标 markdown 在 scope 目录下的相对路径,包含子目录和文件名,使用 `/` 分隔且不含 `.md` 后缀。例如 `path: base/example` 在默认 `project` scope 下生成 `references/codegen/project/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` 时自动添加 `可选。` 前缀 |
|
||
| `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 适合包含多行示例的页面。解析 yaml 需要安装 `pyyaml`
|
||
|
||
注意:
|
||
|
||
- `examples[].code` 和多行 `examples[].output` 使用 `|` 块标量
|
||
- 参数名 `...` 必须加引号
|
||
- `nil|array` 可直接作为普通字符串值
|
||
|
||
完整例子:[examples/example.yaml](examples/example.yaml)
|
||
|
||
### json
|
||
|
||
json 使用 Python 标准库解析,无额外依赖
|
||
|
||
注意:
|
||
|
||
- 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` 区分。
|
||
|
||
lookup 的 `--name` 同时精确匹配简单名称与 `qualified_name`,比较大小写不敏感。
|
||
简单成员名会返回所有 owner 下的同名 API;完全限定名称用于缩小到指定 class/unit。
|
||
`--kw` 还会搜索 kind、binding、visibility、owner 和 qualified_name。
|