Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions .github/config/tdesign_api.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# CI 专用:API 文档合规性审计清单
# 说明:此文件仅用于 tdesign-flutter-tools 仓库的 CI,不会写入 tdesign-component 源码。
# 注意:不要放在 .github/workflows/ —— 该目录下所有 .yaml 都会被 GitHub 当作 workflow 解析。
# 与 demo_tool/all_build.sh 中重点抽测的 5 个组件 --name 配置对齐。

version: 1

components:
button:
folder_name: button
source_folder: lib/src/components/button
classes:
- TButton
- TButtonStyle

picker:
folder_name: picker
source_folder: lib/src/components/picker
classes:
- TPicker
- TPickerOption
- TPickerValue
- TPickerLoadEvent
- TPickerColumns
- TPickerLinked
- TPickerItems
- TPickerKeys

popup:
folder_name: popup
source_folder: lib/src/components/popup
classes:
- TSlidePopupRoute
- TPopupBottomDisplayPanel
- TPopupBottomConfirmPanel
- TPopupCenterPanel

dialog:
folder_name: dialog
source_folder: lib/src/components/dialog
classes:
- TAlertDialog
- TConfirmDialog
- TDialogButtonOptions
- TDialogButtonStyle
- TDialogScaffold
- TDialogTitle
- TDialogContent
- TDialogInfoWidget
- HorizontalNormalButtons
- HorizontalTextButtons
- TDialogButton
- TDialogImagePosition
- TImageDialog
- TInputDialog

calendar:
folder_name: calendar
source_folder: lib/src/components/calendar
classes:
- TCalendar
- TCalendarPopup
- TCalendarStyle
- TCalendarDataSource
- TLunarInfo
- TCalendarDateType
66 changes: 66 additions & 0 deletions .github/workflows/api-compliance.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# 只读校验:tdesign_api.yaml 清单 + analyzer AST validate,不写回 tdesign-flutter 源码
name: API 文档合规性校验

on:
pull_request:
branches: [develop, main]
types: [opened, synchronize, reopened]
push:
branches: [develop, main]
workflow_dispatch:

concurrency:
group: api-compliance-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

env:
FLUTTER_VERSION: "3.32.0"
FLUTTER_REPO: tdesign-flutter
FLUTTER_BRANCH: develop

jobs:
validate-api-docs:
name: YAML 清单 + AST 合规性
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: 检出 tools 仓库
uses: actions/checkout@v4

- name: 安装 Flutter / Dart
uses: subosito/flutter-action@v2
with:
flutter-version: ${{ env.FLUTTER_VERSION }}
channel: stable
cache: true

- name: 解析 tools 依赖
run: flutter pub get

- name: 静态分析 tools
run: dart analyze --fatal-infos

- name: 克隆 tdesign-flutter(测试与 validate 共用)
run: |
git clone --depth 1 --branch "${FLUTTER_BRANCH}" \
https://github.com/Tencent/tdesign-flutter.git "${FLUTTER_REPO}"

- name: 单元测试(完备性相关)
env:
TDESIGN_COMPONENT_ROOT: ${{ github.workspace }}/${{ env.FLUTTER_REPO }}/tdesign-component
run: |
dart test test/aux_types_test.dart \
test/ctor_defaults_test.dart \
test/duplicate_source_test.dart \
test/factory_ctor_test.dart \
test/enum_members_test.dart \
test/positional_ctor_test.dart

- name: 运行 AST 完备性检测(非零 exit code 即失败)
run: |
dart run bin/main.dart validate \
--component-root "${{ github.workspace }}/${FLUTTER_REPO}/tdesign-component" \
--config .github/config/tdesign_api.yaml
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@
build/
.codebuddy/plans

# 本地 dart compile exe 产物(CI 构建 / README 编译命令)
/api_tool*
/demo_tool
/demo_tool_*
/demo_tool_*.exe
*.exe

# Android related
**/android/**/gradle-wrapper.jar
**/android/.gradle
Expand Down
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,53 @@
/// 属性简介(必须)
```

### 工具职责边界

工具只负责**通用 AST 解析规则**,不会对个别组件做特殊兼容,也不会修正源码里不合规的注释。

| 由工具负责(通用规则) | 由源码注释负责(需合规编写) |
| --- | --- |
| 从构造参数 AST 提取类型、默认值 | 字段/参数的 `///` 说明文案 |
| 构造参数与公开属性/静态成员分表展示 | 注释内容与字段语义一致(如 content 不应写「标题」) |
| 过滤 `this.xxx` 被误识别为默认值 | 错别字、遗漏注释、注释写在错误位置 |
| 解析 `abstract class` 实例方法、工厂构造及参数表 | `super.key` 等场景的类型展示 |
| 从父类字段解析 `super.xxx` 参数类型 | 无注释时说明列显示 `-`(符合预期) |
| 同文件内自动收录 public 的 enum / typedef | 也可在 `--name` 中显式指定枚举或别名名称 |
| folder 模式下检测跨文件重复 enum/typedef 并告警 | 文档保留重复条目以暴露源码问题,工具不做 silent dedupe |
| Markdown 表格转义、方法参数格式化 | 无注释时说明列显示 `-`(符合预期) |

**原则:** 注释不合规导致的文档问题,应在组件源码中补全/修正 `///` 注释,而不是在工具里打补丁。

### 组件demo注释示例

```dart
/// demo名称(可以为空,为空的时候默认显示组件名称)
/// demo示例介绍(可以为空)
```

## 本地开发与测试

当 `tdesign-component/pubspec.yaml` 使用 path 依赖指向本仓库时,可在本地直接验证文档生成,无需发布到 git:

```bash
# 1. 确保 component 的 pubspec 已配置:
# tdesign_flutter_tools:
# path: ../tdesign-flutter-tools

# 2. 在 component 目录解析依赖(需要网络)
cd ../tdesign-component && dart pub get

# 3. 运行本地测试脚本(picker / calendar / dialog)
./scripts/local_test.sh picker
```

若 `dart pub get` 因网络不可用失败,可临时将 `tdesign-component/.dart_tool/package_config.json` 中
`tdesign_flutter_tools` 的 `rootUri` 指向本地路径,脚本会通过 `--packages` 跳过联网校验:

```bash
./scripts/local_test.sh calendar
```

## 组件库工具使用方法

### 初始化工具调用命令
Expand Down
75 changes: 75 additions & 0 deletions bin/main.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import 'dart:io';

import 'package:args/command_runner.dart';
import 'package:path/path.dart' as p;
import 'package:tdesign_flutter_tools/api_completeness.dart';
import 'package:tdesign_flutter_tools/model.dart';
import 'package:tdesign_flutter_tools/smart_create.dart';
import 'package:tdesign_flutter_tools/smart_update.dart';
Expand Down Expand Up @@ -78,6 +80,78 @@ class CreateCommand extends Command {
}
}

class ValidateCommand extends Command {
@override
String name = 'validate';

@override
String description =
'校验 API 文档完备性(使用 analyzer AST,与 generate 同一套解析规则)。';

ValidateCommand() {
argParser.addOption(
'component-root',
help: 'tdesign-component 根目录路径',
defaultsTo: '../tdesign-flutter/tdesign-component',
);
argParser.addOption(
'config',
help: '审计清单 YAML/JSON 路径',
defaultsTo: '.github/config/tdesign_api.yaml',
);
argParser.addMultiOption(
'components',
help: '仅检测指定组件,如 button,picker(默认 5 组件全量)',
);
argParser.addFlag('verbose', abbr: 'v', help: '打印 analyzer 解析过程');
}

@override
Future<void> run() async {
final String raw = argResults!['component-root'] as String;
final String componentRoot = p.isAbsolute(raw)
? p.normalize(raw)
: p.normalize(p.join(Directory.current.path, raw));
if (!Directory(componentRoot).existsSync()) {
stderr.writeln('ERROR: component 目录不存在: $componentRoot');
exitCode = 1;
return;
}

final String configRaw = argResults!['config'] as String;
final String configPath = p.isAbsolute(configRaw)
? p.normalize(configRaw)
: p.normalize(p.join(Directory.current.path, configRaw));

List<ComponentAuditConfig> configs;
try {
configs = await loadAuditConfigsFromFile(configPath);
} catch (e) {
stderr.writeln('ERROR: 无法加载配置 $configPath: $e');
exitCode = 2;
return;
}

final List<String> only =
argResults!['components'] as List<String>? ?? <String>[];
if (only.isNotEmpty) {
final Set<String> wanted = only.toSet();
configs = configs
.where((ComponentAuditConfig c) => wanted.contains(c.componentKey))
.toList();
}

final int errors = await runCompletenessAudit(
componentRoot: componentRoot,
configs: configs,
quiet: !(argResults!['verbose'] as bool? ?? false),
);
if (errors > 0) {
exitCode = 1;
}
}
}

class UpdateCommand extends Command {
@override
String name = 'update';
Expand Down Expand Up @@ -120,6 +194,7 @@ void main(List<String> arguments) {

CommandRunner('tdesign_flutter_tools', 'TDesign Flutter component documentation tools.')
..addCommand(CreateCommand())
..addCommand(ValidateCommand())
..addCommand(UpdateCommand())
..run(arguments);
}
Loading
Loading