+192
-56
@@ -1,21 +1,24 @@
|
||||
# TSL Codegen Toolkit
|
||||
|
||||
本工具把 YAML/JSON 录入文件转换为 TSL API skill 使用的 Markdown 函数文档,
|
||||
并根据 Markdown 重建 `function_index.tsv`
|
||||
本工具把一个或多个 tsf function、独立 class、完整 unit 转换为统一
|
||||
`declarations` json/yaml 录入文件,再生成 TSL API skill 使用的 markdown 文档,
|
||||
并根据 markdown 重建统一 API 索引 `function_index.tsv`。
|
||||
|
||||
## 目录结构
|
||||
|
||||
```text
|
||||
tools/tsl-codegen/
|
||||
├─ README.md 使用说明
|
||||
├─ STANDARD.md 函数文档与录入格式标准
|
||||
├─ STANDARD.md API 文档与录入格式标准
|
||||
├─ examples/
|
||||
│ ├─ example.yaml YAML 录入例子
|
||||
│ └─ example.json JSON 录入例子
|
||||
│ ├─ example.yaml yaml 录入例子
|
||||
│ └─ example.json json 录入例子
|
||||
├─ scripts/
|
||||
│ ├─ generate.py YAML/JSON → Markdown
|
||||
│ ├─ lint.py Markdown 格式校验
|
||||
│ └─ build_index.py 重建 function_index.tsv
|
||||
│ ├─ convert_tsf.py tsf → json/yaml
|
||||
│ ├─ generate.py yaml/json → markdown
|
||||
│ ├─ lint.py markdown 格式校验
|
||||
│ ├─ api_markdown.py lint/index 共用标题模型
|
||||
│ └─ build_index.py 重建 13 列 function_index.tsv
|
||||
└─ tests/ 工具测试
|
||||
```
|
||||
|
||||
@@ -29,38 +32,165 @@ tools/tsl-codegen/
|
||||
cd /path/to/playbook
|
||||
```
|
||||
|
||||
JSON 使用 Python 标准库,不需要额外安装解析包。YAML 需要安装 `pyyaml`:
|
||||
json 使用 Python 标准库,不需要额外安装解析包。yaml 需要安装 `pyyaml`:
|
||||
|
||||
```bash
|
||||
python -m pip install pyyaml
|
||||
```
|
||||
|
||||
markdown 生成器会强制使用仓库锁定版本的 Prettier。首次使用前安装 Node.js,并在
|
||||
仓库根目录安装依赖:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
### 2. 阅读标准
|
||||
|
||||
先阅读 [`STANDARD.md`](STANDARD.md)。其中定义:
|
||||
|
||||
- Markdown 函数条目的固定结构
|
||||
- YAML/JSON 录入字段
|
||||
- function、class、unit 同级 H2 顶级声明和混合页面的固定层级
|
||||
- tsf function、独立 class 和完整 unit 文档块格式
|
||||
- yaml/json 统一 `declarations` 判别联合与成员字段
|
||||
- 13 列统一 API 索引和完全限定名称
|
||||
- 参数表、返回类型和示例代码规则
|
||||
|
||||
录入文件和生成的 Markdown 都必须符合该标准
|
||||
录入文件和生成的 markdown 都必须符合该标准
|
||||
|
||||
### 3. 准备自己的 YAML 或 JSON
|
||||
### 3. 准备自己的 yaml 或 json
|
||||
|
||||
#### 从 tsf 转换
|
||||
|
||||
转换器接受任意混合输入:function、独立 class 和完整 unit TSF 可以在同一条命令中
|
||||
出现。每个文件贡献一个对外 declaration,生成的 `declarations` 严格保持命令行
|
||||
输入顺序。页面级 `module` 和 `path` 通过参数统一提供,`--format` 明确选择
|
||||
json 或 yaml:
|
||||
|
||||
```bash
|
||||
python tools/tsl-codegen/scripts/convert_tsf.py \
|
||||
src/OpenXmlAttribute.tsf \
|
||||
src/ParseOpenXml.tsf \
|
||||
src/OpenXmlRuntime.tsf \
|
||||
--format json \
|
||||
--module "OfficeXml / OpenXml" \
|
||||
--path officexml/openxml/elements \
|
||||
--output tmp/openxml-elements.json
|
||||
```
|
||||
|
||||
生成 yaml 时,把 `--format json` 改为 `--format yaml`,并把输出文件后缀改为
|
||||
`.yaml`。混合输入规则不变。
|
||||
|
||||
查看中文帮助:
|
||||
|
||||
```bash
|
||||
python tools/tsl-codegen/scripts/convert_tsf.py --help
|
||||
```
|
||||
|
||||
转换规则:
|
||||
|
||||
- function TSF 只转换第一个独立顶层 `function`
|
||||
- 独立 class 只公开第一个与文件名一致的 class;后续内部 class 和 private 成员忽略
|
||||
- class 开头默认 public;public/protected 进入草稿;类方法只接受 `class function`
|
||||
- 类方法没有 `///` 描述时,使用最终声明或修饰符分号后的同一行 `//` 注释作为描述;
|
||||
正式 `///` 描述优先,类外实现行和函数体内注释不读取
|
||||
- property 类型可选;源码未声明类型时草稿中的 `type` 为空字符串,访问方式仍然必填
|
||||
- 完整 unit 只收录 interface 的 function/var/const/class;implementation 全部忽略
|
||||
- function、class、unit 可以任意混合;重复 function signature、重复 class/unit
|
||||
名称会报错,不同 signature 的 function 重载和跨 kind 同名允许
|
||||
- 公开 API 中的 `procedure` 当前不支持
|
||||
- 输入支持 utf-8(含 BOM)和 gb18030;输出统一为 utf-8
|
||||
- 参数类型和返回类型都是可选的 TSL 注解;转换器从函数签名和 `///` 文档块中尽量
|
||||
解析,无法取得时保留空字段,生成待手工完善的录入稿
|
||||
- `@param: name {类型} 参数说明` 可以为无类型签名补充参数类型;花括号内的全部内容
|
||||
都属于类型;`@returns:` 可以补充返回类型;签名和 `///` 同时提供类型时必须一致
|
||||
- 描述、参数类型或说明等编辑性缺口不会阻止转换;类型冲突、文档结构或声明冲突会按
|
||||
“文件:行号”报错;全部输入成功后才写输出文件
|
||||
- json/yaml 输出补齐各 kind 的固定维护字段:function/method 固定包含
|
||||
`desc`、`params`、`returns`,property 固定包含 `desc`、`type`、`params`、`access`,
|
||||
field/variable 固定包含 `desc`、`type`,constant 固定包含 `desc`、`type`、`value`;
|
||||
参数固定包含 `name`、`type`、`desc`,class/unit 固定包含 `desc`、`members`;缺失值
|
||||
使用空字符串或空数组,条件字段只在源码确实存在时输出
|
||||
- 生成器把 method `returns`、property/constant `type` 的空字符串按可选字段未填写处理;
|
||||
顶级/unit function 返回类型和 field/variable 类型等必填内容仍须补全
|
||||
- 输出文件不得与任一输入 tsf 相同
|
||||
|
||||
#### 手工准备
|
||||
|
||||
从以下例子选择一种格式:
|
||||
|
||||
- [`examples/example.yaml`](examples/example.yaml)
|
||||
- [`examples/example.json`](examples/example.json)
|
||||
|
||||
例子中的函数是格式示例,不是真实 TSL API。复制例子到自己的工作目录,再修改
|
||||
`module`、`path` 和 `functions`。例如:
|
||||
两份完整例子深度等价,同时包含顶级 function、完整 class、class function、
|
||||
typed/untyped property、字段、常量、完整 unit 和 interface class 成员
|
||||
|
||||
```text
|
||||
tmp/my-functions.yaml
|
||||
tmp/my-functions.json
|
||||
例子中的 API 是格式示例,不是真实 TSL API。复制例子到自己的工作目录,再修改
|
||||
`module`、`path` 和非空有序 `declarations`。录入根只允许这三个字段;旧
|
||||
`functions`、`class`、`unit` 根不兼容,生成器会直接拒绝。混合页面的最小
|
||||
完整外形:
|
||||
|
||||
```json
|
||||
{
|
||||
"module": "OfficeXml / OpenXml",
|
||||
"path": "officexml/openxml/elements",
|
||||
"declarations": [
|
||||
{
|
||||
"kind": "class",
|
||||
"name": "OpenXmlAttribute",
|
||||
"desc": "表示 OpenXml 属性",
|
||||
"members": []
|
||||
},
|
||||
{
|
||||
"kind": "function",
|
||||
"name": "ParseOpenXml",
|
||||
"signature": "ParseOpenXml(xml)",
|
||||
"desc": "解析 OpenXml 文本",
|
||||
"params": [
|
||||
{"name": "xml", "type": "string", "desc": "OpenXml 文本"}
|
||||
],
|
||||
"returns": "OpenXmlElement"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
一个录入文件对应一个 Markdown 叶子页。录入文件不放入 skill;是否长期保留由
|
||||
生成的 markdown 使用纯 API 标题和独立声明行。class function 的参数类型进入参数表,
|
||||
返回类型写在返回行:
|
||||
|
||||
```markdown
|
||||
# OfficeXml / OpenXml
|
||||
|
||||
## `OpenXmlAttribute`
|
||||
|
||||
声明:class
|
||||
|
||||
表示 OpenXml 属性
|
||||
|
||||
### `CreateVirtual(position, row_index, _story)`
|
||||
|
||||
声明:class function
|
||||
|
||||
创建虚段落
|
||||
|
||||
可见性:`public`
|
||||
|
||||
| 参数 | 类型 | 说明 |
|
||||
| ----------- | --------- | -------- |
|
||||
| `position` | integer | 段落位置 |
|
||||
| `row_index` | integer | 行索引 |
|
||||
| `_story` | StoryNode | 故事节点 |
|
||||
|
||||
返回:ParagraphSegment
|
||||
```
|
||||
|
||||
录入文件可放在自己的临时目录,例如:
|
||||
|
||||
```text
|
||||
tmp/my-api.yaml
|
||||
tmp/my-api.json
|
||||
```
|
||||
|
||||
一个录入文件对应一个 markdown 叶子页。录入文件不放入 skill;是否长期保留由
|
||||
维护者自行决定
|
||||
|
||||
### 4. 选择 Skill 中的目标位置
|
||||
@@ -82,18 +212,18 @@ skills/tsl-api-reference/
|
||||
└─ lookup.py
|
||||
```
|
||||
|
||||
Markdown 目标路径固定为:
|
||||
markdown 目标路径固定为:
|
||||
|
||||
```text
|
||||
skills/tsl-api-reference/references/codegen/<scope>/<module-dir>/<page>.md
|
||||
```
|
||||
|
||||
- `<scope>`:用户文档默认使用 `project`,也可以自定义单级目录名。`builtin` 和
|
||||
`dotnet` 由 playbook 项目维护,不应用于存放用户自己的函数文档
|
||||
`dotnet` 由 playbook 项目维护,不应用于存放用户自己的 API 文档
|
||||
- `<module-dir>`:功能分类目录,例如 `base`、`runtime`、`document`
|
||||
- `<page>.md`:同类函数的叶子文档,例如 `array.md`、`string.md`
|
||||
- `<page>.md`:相关 API 的叶子文档,例如 `array.md`、`elements.md`
|
||||
|
||||
录入文件的 `module` 是 Markdown 一级标题,不是目录名。例如:
|
||||
录入文件的 `module` 是 markdown 一级标题,不是目录名。例如:
|
||||
|
||||
```text
|
||||
module: 我的项目 / 数组
|
||||
@@ -107,63 +237,60 @@ path: base/array
|
||||
rg --files skills/tsl-api-reference/references/codegen/project
|
||||
```
|
||||
|
||||
生成后可以直接打开目标 Markdown 手动阅读。例如:
|
||||
生成后可以直接打开目标 markdown 手动阅读。例如:
|
||||
|
||||
```text
|
||||
skills/tsl-api-reference/references/codegen/project/base/array.md
|
||||
```
|
||||
|
||||
### 5. 生成 Markdown
|
||||
### 5. 生成 markdown
|
||||
|
||||
#### 新建叶子页
|
||||
|
||||
目标文件不存在时,可以直接生成到 skill。例如:
|
||||
|
||||
```bash
|
||||
python tools/tsl-codegen/scripts/generate.py tmp/my-functions.yaml
|
||||
python tools/tsl-codegen/scripts/generate.py tmp/my-api.yaml
|
||||
```
|
||||
|
||||
JSON 使用相同命令:
|
||||
json 使用相同命令:
|
||||
|
||||
```bash
|
||||
python tools/tsl-codegen/scripts/generate.py tmp/my-functions.json
|
||||
python tools/tsl-codegen/scripts/generate.py tmp/my-api.json
|
||||
```
|
||||
|
||||
生成器读取录入文件中的 `path`,默认写入
|
||||
`skills/tsl-api-reference/references/codegen/project/<path>.md`。不指定
|
||||
`--scope` 时,scope 就是 `project`
|
||||
|
||||
写入前会自动使用仓库的 `.prettierrc.json` 格式化 markdown,使新页面与现有
|
||||
builtin 页面保持一致。未安装 Prettier 或格式化失败时,生成器会停止且不写目标文件
|
||||
|
||||
需要使用自定义 scope 时,通过 `--scope` 指定单级目录名:
|
||||
|
||||
```bash
|
||||
python tools/tsl-codegen/scripts/generate.py tmp/my-functions.json --scope my-project
|
||||
python tools/tsl-codegen/scripts/generate.py tmp/my-api.json --scope my-project
|
||||
```
|
||||
|
||||
#### 修改现有叶子页
|
||||
|
||||
生成器会整体覆盖 `path` 对应的页面。只有录入文件包含该页面的全部函数时才运行
|
||||
生成器。只修改现有页面中的少量函数时,应按照 `STANDARD.md` 直接编辑 Markdown
|
||||
生成器会整体覆盖 `path` 对应的页面。只有录入文件包含该页面的全部 API 时才运行
|
||||
生成器。只修改现有页面中的少量条目时,应按照 `STANDARD.md` 直接编辑 markdown
|
||||
|
||||
### 6. 手动检查并校验 Markdown
|
||||
### 6. 手动检查并校验 markdown
|
||||
|
||||
以下命令以新建页面
|
||||
`skills/tsl-api-reference/references/codegen/project/base/my_functions.md` 为例
|
||||
`skills/tsl-api-reference/references/codegen/project/base/my_api.md` 为例
|
||||
|
||||
先打开文件,检查页面标题、函数签名、参数、返回类型和示例
|
||||
先打开文件,检查页面标题、API 名称、成员层级、参数、返回类型和示例
|
||||
|
||||
#### 6.1 格式化表格(可选)
|
||||
#### 6.1 格式说明
|
||||
|
||||
此步骤不是必需的,仅用于对齐 Markdown 表格列宽。使用前需要安装 Node.js,并在
|
||||
仓库根目录安装 `prettier`:
|
||||
通过 `generate.py` 生成的页面已经完成 Prettier 格式化,不需要再次处理。直接手工
|
||||
编辑 markdown 后,可以单独格式化目标文件:
|
||||
|
||||
```bash
|
||||
npm install --save-dev prettier
|
||||
```
|
||||
|
||||
然后格式化目标文件:
|
||||
|
||||
```bash
|
||||
npx prettier --write skills/tsl-api-reference/references/codegen/project/base/my_functions.md
|
||||
npx --no-install prettier --write skills/tsl-api-reference/references/codegen/project/base/my_api.md
|
||||
```
|
||||
|
||||
#### 6.2 校验
|
||||
@@ -171,7 +298,7 @@ npx prettier --write skills/tsl-api-reference/references/codegen/project/base/my
|
||||
校验目标文件:
|
||||
|
||||
```bash
|
||||
python tools/tsl-codegen/scripts/lint.py --file skills/tsl-api-reference/references/codegen/project/base/my_functions.md
|
||||
python tools/tsl-codegen/scripts/lint.py --file skills/tsl-api-reference/references/codegen/project/base/my_api.md
|
||||
```
|
||||
|
||||
校验整个项目目录:
|
||||
@@ -185,46 +312,55 @@ python tools/tsl-codegen/scripts/lint.py --dir skills/tsl-api-reference/referenc
|
||||
校验器将以下问题视为错误:
|
||||
|
||||
- 缺少描述
|
||||
- 缺少返回类型
|
||||
- 顶层/unit function 缺少返回类型
|
||||
- 有参数但没有参数表
|
||||
- 无参数但存在参数表
|
||||
- 参数表不是固定三列
|
||||
- 参数表不是固定三列,或参数名称/顺序与签名不一致
|
||||
- 参数表数据行缺少参数名、类型或说明
|
||||
- class member 缺少 visibility
|
||||
- property 缺少访问方式,field/variable 缺少类型,constant 缺少值
|
||||
- class/unit 成员标题层级、声明形式或子标题错误,或出现 private API
|
||||
|
||||
以下问题默认作为警告:
|
||||
|
||||
- 可选参数说明未以 `可选。` 开头
|
||||
- tags 行为空
|
||||
|
||||
### 7. 更新并验证函数索引
|
||||
### 7. 更新并验证统一 API 索引
|
||||
|
||||
Markdown 确认无误后,重建 TSV:
|
||||
markdown 确认无误后,重建 TSV:
|
||||
|
||||
索引会分别保存函数的 tags 和描述。关键词检索会同时匹配函数名、签名、模块、
|
||||
tags 和描述
|
||||
索引固定为 13 列:保留原 8 列并追加 kind、binding、visibility、owner、
|
||||
qualified_name。关键词检索会同时匹配原有字段和这些扩展字段。
|
||||
|
||||
```bash
|
||||
python tools/tsl-codegen/scripts/build_index.py --skill-dir skills/tsl-api-reference
|
||||
```
|
||||
|
||||
检查 TSV 是否与 Markdown 一致:
|
||||
检查 TSV 是否与 markdown 一致:
|
||||
|
||||
```bash
|
||||
python tools/tsl-codegen/scripts/build_index.py --skill-dir skills/tsl-api-reference --check
|
||||
```
|
||||
|
||||
默认从 `<skill-dir>/references/codegen` 读取 Markdown,并写入
|
||||
默认从 `<skill-dir>/references/codegen` 读取 markdown,并写入
|
||||
`<skill-dir>/data/function_index.tsv`
|
||||
|
||||
最后使用函数名验证 skill 可以检索到新条目。把 `myFunction` 替换为真实函数名:
|
||||
最后使用简单名称或完全限定名称验证 skill 可以检索到新条目:
|
||||
|
||||
```bash
|
||||
python skills/tsl-api-reference/scripts/lookup.py --name myFunction
|
||||
python skills/tsl-api-reference/scripts/lookup.py --name DemoUnit.Document.Save
|
||||
```
|
||||
|
||||
查询简单成员名会返回所有 owner 下的同名 API;`Unit.Class.Member` 等完全限定名称
|
||||
用于缩小范围。重载共享完全限定名称,查询会返回全部重载。关键词候选显示
|
||||
`class function`、`static field` 等实际声明术语。
|
||||
|
||||
最终提交:
|
||||
|
||||
- 新增或修改的 Markdown 叶子页
|
||||
- 新增或修改的 markdown 叶子页
|
||||
- `skills/tsl-api-reference/data/function_index.tsv`
|
||||
|
||||
TSL API skill 只需要 Markdown 和 TSV。录入用的 YAML/JSON 可以由维护者在自己的
|
||||
TSL API skill 只需要 markdown 和 TSV。录入用的 yaml/json 可以由维护者在自己的
|
||||
版本库中管理
|
||||
|
||||
Reference in New Issue
Block a user