”深蓝词库转换“ 一款开源免费的输入法词库转换程序
## 快速定位
> 这是你进入项目时最先需要知道的信息。根据任务类型,跳转到对应章节。
| 你想做什么 | 入口文件/目录 |
|-----------|-------------|
| 添加新的输入法格式支持 | `src/ImeWlConverter.Formats/{Format}/` → 创建 Importer + Exporter |
| 修改码表/字典数据(拼音、五笔、注音等) | `src/ImeWlConverter.CodeData/`(接口 + `Resources/` 嵌入码表) |
| 修改转换管道逻辑 | `src/ImeWlConverter.Core/Pipeline/ConversionPipeline.cs` |
| 修改 CLI 参数/行为 | `src/ImeWlConverter.Application/Cli/`(命令定义+执行链)与 `Mapping/`(参数解析) |
| 查询 CLI 机器可读契约(退出码/JSON) | `src/ImeWlConverter.Application/Cli/ExitCodes.cs`、`docs/MIGRATION.md` |
| 修改编码生成(拼音/五笔等) | `src/ImeWlConverter.Core/CodeGeneration/Generators/` |
| 修改过滤器 | `src/ImeWlConverter.Core/Filters/` |
| 修改过滤配置 DTO | `src/ImeWlConverter.Abstractions/Options/FilterConfig.cs` |
| 修改 macOS GUI | `src/ImeWlConverterMac/ViewModels/MainWindowViewModel.cs` |
| 修改 Windows GUI | `src/IME WL Converter Win/Forms/MainForm.cs` |
| 添加/修改单元测试 | `src/ImeWlConverterCoreTest/` |
| 修改 CI 流程 | `.github/workflows/ci.yml` |
| 发布新版本 | `docs/RELEASING.md` |
## 项目一句话描述
深蓝词库转换(IME WL Converter)是一个跨平台的输入法词库格式转换工具,支持 50+ 种输入法格式之间的相互转换。
- **语言**: C# / .NET 10.0
- **测试框架**: xUnit 2.9.3
- **构建系统**: Makefile + dotnet CLI
- **版本管理**: MinVer(从 Git tag 自动生成)
- **平台**: Windows / Linux / macOS
## 日常命令
```bash
make build # 构建所有项目
make test # 运行单元测试 (318 个,实际以 dotnet test 输出为准)
make integration-test # 运行集成测试 (29 个用例,需先 make build-cmd)
make lint # 检查代码格式
make format # 自动格式化代码
make run-cmd # 运行 CLI 工具
make run-mac # 运行 macOS GUI
```
## 架构概览
```
src/
├── ImeWlConverter.Abstractions/ # 接口层(零依赖)
├── ImeWlConverter.CodeData/ # 码表数据叶子(零依赖,只读线程安全表服务)
├── ImeWlConverter.Core/ # 业务服务层(转换管道、编码生成、过滤、简繁转换)
├── ImeWlConverter.Formats/ # 格式实现层(107个文件,50+种格式)
├── ImeWlConverter.Application/ # 三端共享应用层(参数映射、请求工厂、CLI 前端、引导)
├── ImeWlConverter.SourceGenerators/ # Source Generator(编译时格式注册)
├── ImeWlConverterCmd/ # CLI 薄入口(逻辑在 Application/Cli)
├── ImeWlConverterMac/ # macOS GUI (Avalonia 11.2.3)
├── IME WL Converter Win/ # Windows GUI (WinForms)
└── ImeWlConverterCoreTest/ # xUnit 单元测试
```
### 三端统一数据流
```
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ CLI │ │ WinForms │ │ macOS GUI │
│ CommandBuild│ │ MainForm │ │ ViewModel │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
└────共享 Application 层────┬─────────┘
▼
┌───────────────────────┐
│ IConversionPipeline │ (Abstractions 层接口)
└───────────┬───────────┘
▼
┌───────────────────────┐
│ ConversionPipeline │ (Core 层统一实现)
│ │
│ Import → Filter → │
│ ChineseConvert → │
│ WordRank → CodeGen → │
│ RemoveEmpty → Export │
└───────────────────────┘
```
**设计原则**:三端(CLI、WinForms、macOS GUI)共用同一个 `ConversionPipeline` 底层转换引擎,只在用户交互层不同。
- CLI 通过 `Application/Cli` 与 `Application/Requests` 解析参数构建 `ConversionRequest`
- WinForms 通过 `MainForm` 用户操作构建 `ConversionRequest`
- macOS GUI 通过 `MainWindowViewModel` 构建 `ConversionRequest`
- 三端共享 `FilterConfig`(`Abstractions/Options/`)、`ConversionOptions`、`IProgress<ProgressInfo>`
---
## 深入:项目层次
以下按从外到内的顺序描述各层,你只需要读到与任务相关的层即可。
### Layer 1: 前端入口
#### CLI (`src/ImeWlConverterCmd/` → `src/ImeWlConverter.Application/Cli/`)
| 文件 | 职责 |
|------|------|
| `ImeWlConverterCmd/Program.cs` | 薄入口:注册编码 Provider,调用 `CliApp.Run` |
| `Application/Cli/CliApp.cs` | CLI 统一入口(旧参数检测 → 命令调用);Win 内嵌 CLI 共用 |
| `Application/Cli/CliOptions.cs` | System.CommandLine 选项定义 |
| `Application/Cli/CliCommandFactory.cs` | 根命令装配与转换执行链(校验→组装→执行→输出) |
| `Application/Cli/CliValidator.cs` | 必填项/文件存在性/格式 ID 校验(结构化 CliError) |
| `Application/Cli/Output/*.cs` | 人类输出 / --json 输出 / 格式清单输出 |
| `Application/Cli/ExitCodes.cs` | 退出码契约(0 成功 / 1 用法 / 2 输入 / 3 部分失败 / 4 内部) |
| `Application/Mapping/*.cs` | filter/编码类型/自定义格式 spec 解析(Try 模式,可单测) |
| `Application/Requests/ConversionRequestFactory.cs` | ConversionRequest 组装单一事实来源 |
| `Application/Bootstrap/ImeWlConverterBootstrapper.cs` | 三端共用 DI 组装 |
#### macOS GUI (`src/ImeWlConverterMac/`)
| 文件 | 职责 |
|------|------|
| `App.axaml.cs` | 应用入口,创建 DI 容器,注入 ViewModel |
| `ViewModels/MainWindowViewModel.cs` | MVVM ViewModel,构建 `ConversionRequest`,调用 `IConversionPipeline` |
| `Views/FilterConfigWindow.axaml.cs` | 过滤配置 UI,使用共享 `FilterConfig` DTO |
#### Windows GUI (`src/IME WL Converter Win/`)
| 文件 | 职责 |
|------|------|
| `Program.cs` | 应用入口,创建 DI 容器 |
| `Forms/MainForm.cs` | 主窗口,构建 `ConversionRequest`,调用 `IConversionPipeline` |
| `Forms/FilterConfigForm.cs` | 过滤配置 UI,使用共享 `FilterConfig` DTO |
### Layer 2: 转换管道 (`src/ImeWlConverter.Core/Pipeline/`)
| 文件 | 职责 |
|------|------|
| `ConversionPipeline.cs` | 薄编排层:导入 → 委托 EntryTransformationService → 导出;合并/逐文件两种模式 |
| `EntryTransformationService.cs` | 词条五阶段处理(Filter→ChineseConvert→WordRank→CodeGen→RemoveEmpty),两条导出路径共用 |
| `FilterPipelineFactory.cs` + `FilterModules/` | 过滤器装配(模块注册制,开闭原则) |
| `FilterPipeline.cs` | 过滤执行器(单条过滤 → 变换 → 批量过滤) |
| `CodePredicates.cs` | 空编码判定谓词(两条路径共用) |
| `SelfDefiningCodeSource.cs` | 自定义码表加载(ISelfDefiningCodeSource 实现) |
`ConversionPipeline` 支持的能力:
- **合并导出** / **逐文件导出**(`MergeToOneFile` 选项)
- **文件输出** / **Stream 输出**(GUI 先预览再保存)
- **从 FilterConfig 经 FilterPipelineFactory 模块化构建 FilterPipeline**
- **IProgress 细粒度进度报告**
- **CancellationToken 取消支持**
- **逐文件错误捕获与结构化累积**(`ConversionResult.Errors`)
### Layer 3: 格式实现 (`src/ImeWlConverter.Formats/`)
每个格式拆分为独立的 Importer 和 Exporter,通过 `[FormatPlugin]` 属性标记,Source Generator 自动注册到 DI。
| 基类 | 用途 |
|------|------|
| `TextFormatImporter` | 文本格式导入(逐行解析) |
| `TextFormatExporter` | 文本格式导出(逐行生成) |
| `BinaryFormatImporter` | 二进制格式导入 |
### Layer 4: 核心基础设施 (`src/ImeWlConverter.Core/`)
| 目录 | 内容 |
|------|------|
| `CodeGeneration/Generators/` | 编码生成器(拼音、五笔86/98/新世纪、郑码、仓颉、注音、超音、二笔x4) |
| `Filters/` | IWordFilter / IWordTransform / IBatchFilter 实现(12 种) |
| `Helpers/` | 文件操作、编码检测、拼音字典、HTTP |
| `Language/` | 纯 .NET 简繁转换(基于 OpenCC 映射表) |
| `WordRank/` | 默认词频生成器 |
| `Resources/` | 嵌入式码表 + 简繁映射文件 |
### Layer 5: 抽象层 (`src/ImeWlConverter.Abstractions/`)
纯接口和 DTO,零依赖。供所有层引用。
| 子目录 | 关键类型 |
|--------|---------|
| `Contracts/` | IFormatImporter, IFormatExporter, IConversionPipeline, ICodeGenerator, IWordFilter, IWordTransform, IBatchFilter |
| `Models/` | WordEntry (sealed record), WordCode, FormatMetadata, ProgressInfo |
| `Options/` | ConversionOptions, FilterConfig, CodeGenerationOptions, ImportOptions, ExportOptions |
| `Results/` | Result\<T\>, ImportResult, ExportResult, ConversionRequest, ConversionResult |
| `Enums/` | CodeType, SortType, PinyinType, ChineseConversionMode |
---
## 常见任务操作指南
### 添加新的输入法格式
```bash
# 1. 在 Formats 项目中创建目录和文件
mkdir src/ImeWlConverter.Formats/MyFormat/
```
```csharp
// 2. 创建 Importer(注意:必须是 partial 类,且不要手写 Metadata 属性——由 Source Generator 生成)
[FormatPlugin("myf", "我的格式", 500)]
public sealed partial class MyFormatImporter : TextFormatImporter
{
protected override Encoding FileEncoding => new UTF8Encoding(false);
protected override bool IsContentLine(string line) =>
!string.IsNullOrWhiteSpace(line) && !line.StartsWith("#"); // 可选:跳过注释/空行
protected override IEnumerable<WordEntry> ParseLine(string line) { /* 解析逻辑 */ }
}
```
```csharp
// 3. 创建 Exporter(同样不手写 Metadata)
[FormatPlugin("myf", "我的格式", 500)]
public sealed partial class MyFormatExporter : TextFormatExporter
{
protected override Encoding FileEncoding => new UTF8Encoding(false);
protected override string? FormatEntry(WordEntry entry) { /* 导出逻辑,返回 null 跳过该词条 */ }
}
```
Source Generator 会自动完成两件事:
- 将带 `[FormatPlugin]` 的类注册到 DI 容器(无需手动注册)
- 为每个类生成 `Metadata` 属性(从 `[FormatPlugin]` 参数与基类链自动推断 `IsBinary` 等,**手写 Metadata 会与生成代码冲突**)
完整真实示例见 `src/ImeWlConverter.Formats/Rime/RimeImporter.cs`。
### 修改过滤逻辑
过滤器位于 `src/ImeWlConverter.Core/Filters/`,实现接口:
```csharp
public interface IWordFilter { bool ShouldKeep(WordEntry entry); }
public interface IWordTransform { WordEntry? Transform(WordEntry entry); }
public interface IBatchFilter { IReadOnlyList<WordEntry> Filter(IReadOnlyList<WordEntry> entries); }
```
`FilterConfig`(`Abstractions/Options/FilterConfig.cs`)定义了所有过滤选项,`ConversionPipeline` 内部的 `BuildFilterPipeline()` 方法将其转换为 `FilterPipeline` 实例。
CLI 通过 `--filter` 参数启用过滤:`-f "len:2-10|rm:eng|rm:num"`
### 修改编码生成
编码生成器位于 `src/ImeWlConverter.Core/CodeGeneration/Generators/`,实现 `ICodeGenerator` 接口。通过 DI 注册,由 `CodeGenerationService` 根据 `CodeType` 选择对应生成器。
### 修改转换管道行为
- **编排与导出**:`src/ImeWlConverter.Core/Pipeline/ConversionPipeline.cs`(薄层)
- **词条阶段处理**:`EntryTransformationService.cs`,7 步流程:
1. **Import** — 逐文件导入,累积所有 WordEntry(ConversionPipeline)
2. **Filter → ChineseConvert → WordRank → CodeGen → RemoveEmpty** — EntryTransformationService.ApplyAsync(合并模式调一次,逐文件模式每文件一次)
3. **Export** — 导出到文件或 Stream(ConversionPipeline)
### 修改过滤逻辑(注册制)
- 过滤器实现位于 `src/ImeWlConverter.Core/Filters/`,装配位于 `Pipeline/FilterPipelineFactory.cs` + `Pipeline/FilterModules/`
- **新增过滤器**:实现 `IFilterModule`(或往现有模块加一行)→ 加入 `DefaultFilterModules.Create()` 清单即可,无需修改管道
---
## 项目约定
### 禁止操作
- **禁止手动修改版本号**(由 MinVer 从 Git tag 生成,配置在 `src/Directory.Build.props`)
- **禁止使用运行时反射注册格式**(Source Generator 自动注册)
- **禁止硬编码路径分隔符**(用 `Path.Combine()`)
- **禁止在 GUI 项目中重复实现转换逻辑**(统一使用 `IConversionPipeline`)
- **禁止 GUI 内联格式识别/请求组装/预览截断**(统一用 `ImeWlConverter.Application` 的 FormatDetectionService/ConversionRequestFactory/PreviewService——历史上三端各写一份已导致 macOS 识别 Bug)
- **禁止 CLI 输出契约随意变更**(退出码 0-4 与 --json schema 见 `Application/Cli/ExitCodes.cs` 与 `docs/MIGRATION.md`;变更必须同步基线测试 `tests/integration/cli-baseline.sh`)
### DI 注册模式
三端使用相同的 DI 注册方式:
```csharp
var services = new ServiceCollection();
services.AddAllFormats(); // Source Generator 生成的格式注册
services.AddImeWlConverterCore(); // 管道、编码生成器、简繁转换、词频生成器
var sp = services.BuildServiceProvider();
// 获取管道
var pipeline = sp.GetRequiredService<IConversionPipeline>();
```
### 编码处理
项目处理多种字符编码(UTF-8、GBK、GB2312、Big5、Unicode)。.NET 10 已内置 CodePages 支持,但部分旧代码仍调用:
```csharp
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
```
### 跨平台注意事项
- CLI 工具为 framework-dependent(需 .NET 运行时)
- macOS app bundle 为 self-contained(包含运行时)
- Windows GUI 为 WinForms(仅 Windows)
- 集成测试支持 Linux、macOS、Windows (Git Bash)
### 测试
- **单元测试**: xUnit 2.9.3,位于 `src/ImeWlConverterCoreTest/`
- **集成测试**: shell 脚本框架,位于 `tests/integration/`
- 测试并行执行(`xunit.runner.json` 中 `parallelizeTestCollections: true`;Phase 2 已消灭静态可变状态,码表全部走 `ImeWlConverter.CodeData` 的线程安全只读表)
- **禁新增 static 可变字典/集合**——需要码表数据时注入 `ICodeTableLibrary`/`IPinyinTable` 等接口(见 `src/ImeWlConverter.CodeData/`)
- `[Fact(Skip = "...")]` 标记按需运行的慢速测试
### CI/CD
GitHub Actions (`.github/workflows/ci.yml`):
1. Lint(格式检查,快速失败)
2. Build + 单元测试 (Ubuntu)
3. 多平台构建 (Win x64/x86, Linux x64/arm64, macOS x64/arm64)
4. 集成测试 (Linux + macOS)
---
## 关键决策记录
| 决策 | 原因 |
|------|------|
| 三端统一使用 ConversionPipeline | 消除重复转换逻辑,保证行为一致 |
| FilterConfig 放在 Abstractions 层 | 三端共享过滤配置 DTO,避免各端重复定义 |
| ConversionPipeline 支持 Stream 输出 | GUI 需要先预览内容再决定是否保存 |
| CLI 用 FormatRegistrar 显式注册 | 消除反射,支持 AOT/Trimming |
| Source Generator 注册新格式 | 添加格式只需加 `[FormatPlugin]` 属性 |
| 测试并行执行 | Phase 2 建立码表数据层(CodeData),静态可变字典全部改为 DI 只读表,竞态根因消除 |
| sealed record 实体 | 不可变性保证,不会意外修改中间状态 |