v2-refactor-temp/tools/data-classify/README.md
Cherry Studio 数据重构项目的自动化工具集,用于管理数据分类和生成 TypeScript 代码。
版本: 2.0.0 更新日期: 2025-11-28
⚠️ 阶段性使命已完成(重要)
本工具中仅 代码生成(generate) 流水线仍在使用。数据提取、一致性/生成校验、重复键检查等命令与脚本已完成阶段性使命,不再支持,请勿再次运行。
仍可用 已弃用(不再支持) npm run generate、generate:preferences、generate:boot-config、generate:migrationnpm run extract、validate、validate:gen、check:duplicates、all对应脚本文件已加
DO-NOT-USE-前缀(DO-NOT-USE-extract-inventory.js、DO-NOT-USE-validate-consistency.js、DO-NOT-USE-validate-generation.js、DO-NOT-USE-check-duplicates.js);运行已弃用的 npm 命令只会打印一行提示。下文中保留的相关章节仅作历史记录,如有疑问请询问作者。
本工具集提供以下功能:
v2-refactor-temp/tools/data-classify/
├── scripts/
│ ├── lib/
│ │ └── classificationUtils.js # 共享工具函数(仅被下方已弃用脚本使用)
│ ├── generate-all.js # 运行所有生成器
│ ├── generate-preferences.js # 生成 preferenceSchemas.ts
│ ├── generate-boot-config.js # 生成 bootConfigSchemas.ts
│ ├── generate-migration.js # 生成 PreferencesMappings.ts + BootConfigMappings.ts
│ ├── DO-NOT-USE-extract-inventory.js # [已弃用] 从源码提取数据清单
│ ├── DO-NOT-USE-validate-consistency.js # [已弃用] 验证数据一致性
│ ├── DO-NOT-USE-validate-generation.js # [已弃用] 验证生成代码质量
│ └── DO-NOT-USE-check-duplicates.js # [已弃用] 检查重复的目标键
├── data/
│ ├── classification.json # 分类映射(自动生成,人工维护)
│ ├── inventory.json # 数据清单(脚本生成)
│ └── target-key-definitions.json # 复杂映射的 target key 定义(人工维护)
├── package.json
└── README.md # 本文档
# 进入工具目录
cd v2-refactor-temp/tools/data-classify
# 安装依赖
npm install
# 生成所有代码(当前唯一仍受支持的流程)
npm run generate
# 或仅生成单一目标
npm run generate:preferences # 仅生成 preferenceSchemas.ts
npm run generate:boot-config # 仅生成 bootConfigSchemas.ts
npm run generate:migration # 仅生成 PreferencesMappings.ts + BootConfigMappings.ts
extract/validate/validate:gen/check:duplicates/all已弃用,不再支持,详见顶部说明。
| 脚本 | 说明 | 状态 |
|---|---|---|
npm run generate | 运行所有代码生成器 | ✅ 可用 |
npm run generate:preferences | 仅生成 preferenceSchemas.ts | ✅ 可用 |
npm run generate:boot-config | 仅生成 bootConfigSchemas.ts | ✅ 可用 |
npm run generate:migration | 仅生成 PreferencesMappings.ts + BootConfigMappings.ts | ✅ 可用 |
npm run extract | 从源文件提取数据清单 | ⛔ 已弃用 |
npm run validate | 验证数据一致性 | ⛔ 已弃用 |
npm run validate:gen | 验证生成代码质量 | ⛔ 已弃用 |
npm run check:duplicates | 检查重复的目标键 | ⛔ 已弃用 |
npm run all | 运行完整工作流 | ⛔ 已弃用 |
⛔ 标记的命令已完成阶段性使命,不再支持,运行只会打印提示。详见顶部说明。
注:下图与下表为原始完整工作流的历史记录;其中
extract-inventory/validate-consistency/validate-generation/check-duplicates相关脚本已弃用(文件名已加DO-NOT-USE-前缀),仅generate-*仍在使用。
┌─────────────────────────────────────────────────────────────┐
│ 共享模块 │
│ scripts/lib/classificationUtils.js │
│ - loadClassification() - traverseClassifications() │
│ - saveClassification() - calculateStats() │
│ - loadInventory() - normalizeType() │
│ - extractPreferencesData() - inferTypeFromValue() │
└─────────────────────────────────────────────────────────────┘
▲ ▲
│ │
┌───────────┘ └───────────┐
│ │
┌───────┴───────┐ ┌────────┴────────┐
│ extract- │ │ validate- │
│ inventory.js │ │ consistency.js │
│ │ │ │
│ 扫描源码 │ │ 检查数据 │
│ 构建清单 │ │ 一致性 │
└───────────────┘ └─────────────────┘
┌─────────────────────┐
│ generate-all.js │─────────────────────┬──────────────────────┐
│ │ │ │
│ 编排所有生成器 │ │ │
└─────────────────────┘ │ │
│ │ │
│ require() │ require() │ require()
▼ ▼ ▼
┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐
│ generate- │ │ generate- │ │ generate- │
│ preferences.js │ │ boot-config.js │ │ migration.js │
│ │ │ │ │ │
│ 生成 │ │ 生成 │ │ 生成 │
│ preferenceSchemas.ts│ │ bootConfigSchemas.ts│ │ PreferencesMappings │
└─────────────────────┘ └─────────────────────┘ │ BootConfigMappings │
└─────────────────────┘
┌─────────────────────┐ ┌─────────────────────┐
│ validate- │ │ check- │
│ generation.js │ │ duplicates.js │
│ │ │ │
│ 验证生成代码质量 │ │ 检查重复目标键 │
│ (独立运行) │ │ (独立运行) │
└─────────────────────┘ └─────────────────────┘
| 脚本 | 输入 | 输出 | 依赖 |
|---|---|---|---|
generate-preferences.js | classification.json | preferenceSchemas.ts | 无 |
generate-boot-config.js | classification.json | bootConfigSchemas.ts | 无 |
generate-migration.js | classification.json | PreferencesMappings.ts, BootConfigMappings.ts | 无 |
generate-all.js | - | 运行三个生成器 | generate-preferences.js, generate-boot-config.js, generate-migration.js |
DO-NOT-USE-extract-inventory.js (已弃用) | 源代码文件 | data/inventory.json | classificationUtils.js |
DO-NOT-USE-validate-consistency.js (已弃用) | inventory.json, classification.json | validation-report.md | classificationUtils.js |
DO-NOT-USE-validate-generation.js (已弃用) | 生成的 .ts 文件 | 控制台输出 | 无 |
DO-NOT-USE-check-duplicates.js (已弃用) | classification.json | 控制台输出 | 无 |
⚠️ 本节为历史记录:步骤 1(提取)与步骤 4(验证)所用命令已弃用、不再支持,当前仅步骤 3(生成)仍受支持。
npm run extract
扫描源文件并提取以下数据源的信息:
src/renderer/store/*.tssrc/main/services/ConfigManager.tssrc/renderer/databases/index.ts注意:
dexieSettings数据源中的字符串字面量 key 会被自动提取,但动态 key(如模板字符串拼接的)需要手动维护。详见下方 dexieSettings 数据源 章节。
编辑 data/classification.json 对每个数据项进行分类:
{
"originalKey": "theme",
"type": "string",
"status": "classified",
"category": "preferences",
"targetKey": "ui.theme_mode"
}
npm run generate
生成以下 TypeScript 文件:
src/shared/data/preference/preferenceSchemas.ts - 偏好配置类型定义与默认值src/shared/data/bootConfig/bootConfigSchemas.ts - 启动配置类型定义与默认值src/main/data/migration/v2/migrators/mappings/PreferencesMappings.ts - 偏好迁移映射src/main/data/migration/v2/migrators/mappings/BootConfigMappings.ts - 启动配置迁移映射npm run validate
npm run validate:gen
验证内容:
根据 Cherry Studio 数据重构架构,所有数据需要分类到以下 6 个类别之一:
判断标准:
典型例子:
showAssistants: 是否显示助手面板theme: 主题设置(light/dark/system)fontSize: 字体大小language: 界面语言命名规范:
ui.fontSize、system.languageui.*(界面)、system.*(系统)、app.*(应用行为)等判断标准:
app.whenReady、早于 lifecycle 的 BeforeReady 阶段)BeforeReady 阶段初始化,远晚于 boot config 的加载时机)~/.cherrystudio/boot-config.json,刻意放在 userData 之外,避免鸡生蛋问题)时序关系:
Boot Config 加载 → bootstrap(初始化 appData 目录)→ app.whenReady → lifecycle BeforeReady(DB 初始化)→ lifecycle WhenReady
Boot config 在整个启动链的最前端,为后续所有阶段提供基础配置。
典型例子:
disableHardwareAcceleration: 硬件加速开关(必须在任何 Electron API 调用前设置)与 preferences 的区别:
| bootConfig | preferences | |
|---|---|---|
| 加载时机 | 进程启动最早阶段(同步) | lifecycle BeforeReady 阶段(异步) |
| 存储方式 | JSON 文件(~/.cherrystudio/boot-config.json) | SQLite 数据库 |
| 访问方式(Main) | bootConfigService.get() 同步 | application.get('PreferenceService').get() |
| 访问方式(Renderer) | usePreference('BootConfig.*') 统一访问 | usePreference('key') |
判断标准:
典型例子:
topics: 对话历史messages: 消息内容files: 用户上传的文件knowledge_notes: 知识库笔记特殊处理:
判断标准:
典型例子:
failed_favicon_*: 失败的 favicon 缓存判断标准:
典型例子:
判断标准:
典型例子:
数据项
↓
是否必须在进程启动最早阶段同步加载(早于 lifecycle)?
↓ 是 ↓ 否
启动配置 是否用户创建/输入的内容?
(bootConfig) ↓ 是 ↓ 否
用户数据 是否需要持久化?
↓ 否 ↓ 是
运行时数据 是否可重新生成?
↓ 是 ↓ 否
缓存数据 是否用户可修改?
↓ 是 ↓ 否
偏好配置 应用资源
{
"classifications": {
"redux": {
"settings": [
{
"originalKey": "showAssistants",
"type": "boolean",
"defaultValue": true,
"status": "classified",
"category": "preferences",
"targetKey": "ui.show_assistants"
}
]
}
}
}
分析过程:
{
"originalKey": "codeEditor",
"type": "object",
"children": [
{
"originalKey": "enabled",
"type": "boolean",
"defaultValue": true,
"status": "classified",
"category": "preferences",
"targetKey": "code_editor.enabled"
},
{
"originalKey": "fontSize",
"type": "number",
"defaultValue": 14,
"status": "classified",
"category": "preferences",
"targetKey": "code_editor.font_size"
}
]
}
注意: 父级项不需要 status/category/targetKey,这些只在叶子节点设置。
{
"originalKey": "topics",
"type": "table",
"status": "classified",
"category": "user_data",
"targetTable": "topic",
"notes": "用户对话历史,核心业务数据"
}
偏好配置键必须遵循:namespace.sub.key_name
规则:
/^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/示例:
app.theme (有效)chat.input.send_shortcut (有效)Theme (无效 - 没有点分隔符)App.User (无效 - 大写字母)⚠️ 本节描述的提取(
npm run extract)流程已弃用、不再支持,仅作历史记录。
npm run extractclassification.json 到 classification.backup.jsonpending 数组status: 'classified-deleted'{
"metadata": {
"generatedAt": "ISO 日期",
"version": "版本号"
},
"redux": {
"moduleName": {
"fieldName": {
"type": "数据类型",
"defaultValue": "默认值"
}
}
},
"electronStore": { ... },
"localStorage": { ... },
"dexie": { ... }
}
{
"metadata": {
"version": "版本号",
"lastUpdated": "ISO 日期"
},
"classifications": {
"redux": {
"moduleName": [
{
"originalKey": "字段名",
"type": "数据类型",
"status": "classified|pending|classified-deleted",
"category": "preferences|bootConfig|user_data|cache|runtime|resources",
"targetKey": "target.key.name"
}
]
},
"electronStore": { ... },
"localStorage": { ... },
"dexieSettings": {
"settings": [
{
"originalKey": "字段名",
"type": "数据类型",
"status": "classified|pending",
"category": "preferences",
"targetKey": "target.key.name"
}
]
},
"dexie": { ... }
}
}
dexieSettings 是 classification.json 中与 redux、electronStore、localStorage、dexie 并列的第五个顶级数据源,专门用于分类 Dexie IndexedDB 中 settings 表的 KV 配置项。
与 dexie 数据源的区别:
| 数据源 | 用途 | 数据结构 | 典型分类 |
|---|---|---|---|
dexie | Dexie 的业务数据表(files, topics 等) | 表级别,使用 targetTable | user_data |
dexieSettings | Dexie 的 settings 表(KV 配置) | 字段级别,使用 targetKey | preferences(目前仅支持此分类) |
classification.json 中的结构:
{
"classifications": {
"dexieSettings": {
"settings": [
{
"originalKey": "settingKeyName",
"type": "string",
"defaultValue": "defaultValue",
"status": "classified",
"category": "preferences",
"targetKey": "namespace.key_name"
}
]
}
}
}
在代码生成中的作用:
generate-preferences.js: 作为四大偏好数据源之一(electronStore、redux、localStorage、dexieSettings),参与生成 preferenceSchemas.tsgenerate-migration.js: 生成独立的 DEXIE_SETTINGS_MAPPINGS 映射数组,用于迁移器从 Dexie settings 表读取数据去重优先级(当多个数据源映射到相同 targetKey 时):
redux (最高) > dexieSettings > localStorage > electronStore (最低)
已知字段清单(参考 PR #10162 comment):
Dexie settings 表是一个通用 KV 存储({ id: string, value: any }),所有 image:// 键由 ImageStorage 服务管理。
固定键:
| Key | Value Type | 迁移目标 |
|---|---|---|
translate:model | string (model id) | preference |
translate:target:language | string (langCode) | preference |
translate:source:language | string (langCode) | preference |
translate:bidirectional:enabled | boolean | preference |
translate:bidirectional:pair | [string, string] (langCode pair) | preference |
translate:scroll:sync | boolean | preference |
translate:markdown:enabled | boolean | preference |
translate:detect:method | string ('franc'/'llm'/'auto') | preference |
pinned:models | Model[] | preference |
image://avatar | string (base64 data URL | emoji) | preference / file manager |
动态键(基于 pattern):
| Key Pattern | Value Type | 迁移目标 |
|---|---|---|
image://provider-${providerId} | string (base64 data URL | emoji | '') | file manager |
mcp:provider:${provider.key}:servers | MCPServer[] | new table |
已知遗留键(代码中无引用,运行时 IndexedDB 中存在):
| Key | 说明 |
|---|---|
translate:model:prompt | 已被 Redux settings.translateModelPrompt 取代,已迁移到 preference feature.translate.model_prompt,跳过 |
注意事项:
extract-inventory.js 会自动提取 db.settings.get/put/add() 调用中的字符串字面量 key;动态 key(模板字符串拼接)无法自动提取,需要手动添加dexieSettings 的 category 目前仅支持 preferences,代码生成脚本只处理该分类validate-consistency.js 不会检查 dexieSettings 与 inventory 的一致性ctx.sources.dexieSettings.get(mapping.originalKey) 读取数据${} 模板的 pattern)需要特殊的迁移逻辑,不能用简单 1:1 映射处理| Status | 说明 | 操作建议 |
|---|---|---|
pending | 待分类 | 需要人工分析并设置 category 和 targetKey |
classified | 已分类 | 分类完成,可用于代码生成 |
classified-deleted | 已分类但源已删除 | 源代码中已不存在,保留历史记录 |
对于 status: "classified" 的项,targetKey 有两种情况:
| targetKey | 说明 | 生成行为 |
|---|---|---|
有效值(如 "ui.theme") | 需要迁移到新系统 | 会生成到 preferenceSchemas.ts |
null | 已分类,但不需要迁移 | 不会生成到 preferenceSchemas.ts |
使用场景:当一个数据项经过分析后,确定在新系统中不需要该配置(如已废弃、被其他配置替代、或不再需要持久化),应设置 status: "classified" 且 targetKey: null。这表示"已完成分类决策,决策结果是不加载该项"。
除了简单的一对一映射(originalKey → targetKey),系统还支持复杂的数据转换:
┌─────────────────────────────────────────────────────────────┐
│ classification.json (status: classified) │
│ ───────────────────────────────────────── │
│ 基础数据源,包含所有简单映射的 target keys │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ target-key-definitions.json │
│ ───────────────────────────────────────── │
│ 用途1: 复杂迁移 - 定义需要特殊转换逻辑的 target keys │
│ 用途2: 纯新增 - 添加 v2 新功能的 preferences(非迁移) │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ preferenceSchemas.ts (最终输出) │
└─────────────────────────────────────────────────────────────┘
用于定义无法通过 classification.json 简单映射处理的 preference keys。主要用于两个场景:
文件结构:
{
"metadata": {
"version": "1.0.0",
"description": "Target key definitions...",
"lastUpdated": "2025-01-18"
},
"definitions": [
{
"targetKey": "app.window.position.x",
"type": "number",
"defaultValue": 0,
"status": "classified",
"description": "Window X position (from complex mapping)"
}
]
}
字段说明:
| 字段 | 必填 | 说明 |
|---|---|---|
targetKey | ✓ | preference key(必须符合命名规范) |
type | ✓ | TypeScript 类型(string, number, boolean, 或自定义类型) |
defaultValue | ✓ | 默认值(支持 VALUE: ... 特殊格式) |
status | ✓ | classified 启用,pending 禁用 |
description | 可选描述 |
当需要添加一个全新的 preference(不是从旧代码迁移的 v2 新功能)时,直接在 definitions 数组中添加即可。
示例: 添加 v2 版本新增的功能配置
{
"definitions": [
{
"targetKey": "feature.new_assistant.enabled",
"type": "boolean",
"defaultValue": false,
"status": "classified",
"description": "启用新助手功能(v2 新增,非迁移)"
},
{
"targetKey": "feature.new_assistant.default_model",
"type": "string",
"defaultValue": "gpt-4",
"status": "classified",
"description": "新助手默认模型(v2 新增,非迁移)"
}
]
}
运行 npm run generate:preferences 后,这些 keys 会出现在生成的 preferenceSchemas.ts 中。
与复杂迁移的区别:
PreferenceTransformers.ts 和 ComplexPreferenceMappings.ts 中实现转换逻辑target-key-definitions.json 中定义,无需额外代码建议: 在 description 中注明是"复杂迁移"还是"v2 新增,非迁移",便于后续维护。
defaultValue 特殊格式:
与 classification.json 保持一致,支持 VALUE: ... 特殊格式:
// 引用枚举值
{ "defaultValue": "VALUE: PreferenceTypes.ThemeMode.system" }
// 生成: PreferenceTypes.ThemeMode.system(不加引号)
// 引用常量
{ "defaultValue": "VALUE: TRANSLATE_PROMPT" }
// 生成: TRANSLATE_PROMPT(不加引号)
// 特殊 null 值
{ "defaultValue": "VALUE: null" }
// 生成: null
// 普通字符串(不使用 VALUE: 前缀)
{ "defaultValue": "light" }
// 生成: 'light'(带引号)
复杂映射的转换逻辑定义在以下文件中:
src/main/data/migration/v2/migrators/
├── mappings/
│ ├── PreferencesMappings.ts # 偏好简单映射(自动生成)
│ ├── BootConfigMappings.ts # 启动配置映射(自动生成)
│ └── ComplexPreferenceMappings.ts # 复杂映射配置
├── transformers/
│ └── PreferenceTransformers.ts # 转换函数实现
├── PreferencesMigrator.ts # 偏好迁移执行器
└── BootConfigMigrator.ts # 启动配置迁移执行器
添加复杂映射的步骤:
target-key-definitions.json 中定义 target keys(设 status: "classified")PreferenceTransformers.ts 中实现转换函数ComplexPreferenceMappings.ts 中添加映射配置npm run generate:preferences 重新生成 preferenceSchemas.ts系统采用严格模式:如果简单映射和复杂映射的 target key 有冲突,迁移时会报错。
解决方法:从简单映射(classification.json)中移除冲突的 key,由复杂映射处理。
cd v2-refactor-temp/tools/data-classify
npm install
validation-report.md 了解详情classification.json 条目npm run validate:gen 识别问题npm run generate 重新生成检查提取脚本的模式是否正确匹配代码结构。
从以下位置恢复 classification.json:
classification.backup.json