mirror of
https://github.com/hanzoai/icons.git
synced 2026-09-24 16:59:52 +00:00
💄 style(rn): Update rn
This commit is contained in:
@@ -42,9 +42,11 @@ import Inflection from '../icons/Inflection';
|
||||
import InternLM from '../icons/InternLM';
|
||||
import Jina from '../icons/Jina';
|
||||
import Kolors from '../icons/Kolors';
|
||||
import Kwaipilot from '../icons/Kwaipilot';
|
||||
import LG from '../icons/LG';
|
||||
import LLaVA from '../icons/LLaVA';
|
||||
import Liquid from '../icons/Liquid';
|
||||
import LongCat from '../icons/LongCat';
|
||||
import Menlo from '../icons/Menlo';
|
||||
import Meta from '../icons/Meta';
|
||||
import Microsoft from '../icons/Microsoft';
|
||||
@@ -53,7 +55,6 @@ import Mistral from '../icons/Mistral';
|
||||
import Moonshot from '../icons/Moonshot';
|
||||
import NousResearch from '../icons/NousResearch';
|
||||
import Nvidia from '../icons/Nvidia';
|
||||
// Import React Native icon components
|
||||
import OpenAI from '../icons/OpenAI';
|
||||
import OpenChat from '../icons/OpenChat';
|
||||
import OpenRouter from '../icons/OpenRouter';
|
||||
@@ -65,6 +66,7 @@ import Qwen from '../icons/Qwen';
|
||||
import Rwkv from '../icons/Rwkv';
|
||||
import SenseNova from '../icons/SenseNova';
|
||||
import Skywork from '../icons/Skywork';
|
||||
import Sora from '../icons/Sora';
|
||||
import Spark from '../icons/Spark';
|
||||
import Stability from '../icons/Stability';
|
||||
import Stepfun from '../icons/Stepfun';
|
||||
@@ -101,6 +103,7 @@ export const rnModelMappings: RNModelMapping[] = [
|
||||
{ Icon: OpenAI, keywords: ['gpt-3'], props: { type: 'gpt3' } },
|
||||
{ Icon: OpenAI, keywords: ['gpt-4'], props: { type: 'gpt4' } },
|
||||
{ Icon: OpenAI, keywords: ['gpt-5'], props: { type: 'gpt5' } },
|
||||
{ Icon: Sora, keywords: ['sora'] },
|
||||
{ Icon: OpenAI, keywords: ['gpt-oss'], props: { type: 'oss' } },
|
||||
{
|
||||
Icon: OpenAI,
|
||||
@@ -147,7 +150,7 @@ export const rnModelMappings: RNModelMapping[] = [
|
||||
{ Icon: Gemma, keywords: ['gemma'] },
|
||||
{ Icon: Moonshot, keywords: ['kimi', 'moonshot'] },
|
||||
{ Icon: Qiniu, keywords: ['qiniu'] },
|
||||
{ Icon: Qwen, keywords: ['qwen', 'qwq', 'qvq', 'wanx', 'wan\\d/', 'wan\\d\\.\\d-'] },
|
||||
{ Icon: Qwen, keywords: ['qwen', 'qwq', 'qvq', 'wanx', 'wan\\d/', 'wan\\d\\.\\d-', 'tongyi'] },
|
||||
{ Icon: Minimax, keywords: ['minimax', 'abab', '^image-'] },
|
||||
{
|
||||
Icon: Mistral,
|
||||
@@ -181,7 +184,7 @@ export const rnModelMappings: RNModelMapping[] = [
|
||||
{ Icon: Doubao, keywords: ['^ep-', 'doubao-', 'seedream', 'seededit'] },
|
||||
{ Icon: Hunyuan, keywords: ['hunyuan'] },
|
||||
{ Icon: FishAudio, keywords: ['^d_', '^g_', '^wd_'] },
|
||||
{ Icon: ByteDance, keywords: ['skylark'] },
|
||||
{ Icon: ByteDance, keywords: ['skylark', 'seed-', 'bytedance'] },
|
||||
{ Icon: BurnCloud, keywords: ['burncloud'] },
|
||||
{
|
||||
Icon: Stability,
|
||||
@@ -199,7 +202,7 @@ export const rnModelMappings: RNModelMapping[] = [
|
||||
},
|
||||
{ Icon: Flux, keywords: ['flux'] },
|
||||
{ Icon: Suno, keywords: ['suno'] },
|
||||
{ Icon: Microsoft, keywords: ['wizardlm', '/phi-', '^phi-', '-phi-'] },
|
||||
{ Icon: Microsoft, keywords: ['wizardlm', '/phi-', '^phi-', '-phi-', 'mai-', 'microsoft'] },
|
||||
{ Icon: Adobe, keywords: ['firefly'] },
|
||||
{ Icon: Ai21, keywords: ['jamba', '^j2-', 'ai21'] },
|
||||
{ Icon: Upstage, keywords: ['^solar-', '/solar'] },
|
||||
@@ -244,4 +247,6 @@ export const rnModelMappings: RNModelMapping[] = [
|
||||
{ Icon: LG, keywords: ['kmmlu', 'exaone', 'lgai'] },
|
||||
{ Icon: TII, keywords: ['falcon'] },
|
||||
{ Icon: Menlo, keywords: ['menlo', 'lucy', 'jan-nano'] },
|
||||
{ Icon: LongCat, keywords: ['longcat'] },
|
||||
{ Icon: Kwaipilot, keywords: ['kat-'] },
|
||||
];
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { FC, memo } from 'react';
|
||||
|
||||
// Import React Native icon components
|
||||
import Ai21 from '../icons/Ai21';
|
||||
import Ai302 from '../icons/Ai302';
|
||||
import Ai360 from '../icons/Ai360';
|
||||
@@ -17,6 +16,7 @@ import BaiduCloud from '../icons/BaiduCloud';
|
||||
import Bedrock from '../icons/Bedrock';
|
||||
import Bfl from '../icons/Bfl';
|
||||
import BurnCloud from '../icons/BurnCloud';
|
||||
import Cerebras from '../icons/Cerebras';
|
||||
import Claude from '../icons/Claude';
|
||||
import Cloudflare from '../icons/Cloudflare';
|
||||
import Cohere from '../icons/Cohere';
|
||||
@@ -39,6 +39,7 @@ import InternLM from '../icons/InternLM';
|
||||
import Jina from '../icons/Jina';
|
||||
import LmStudio from '../icons/LmStudio';
|
||||
import LobeHub from '../icons/LobeHub';
|
||||
import LongCat from '../icons/LongCat';
|
||||
import Minimax from '../icons/Minimax';
|
||||
import Mistral from '../icons/Mistral';
|
||||
import ModelScope from '../icons/ModelScope';
|
||||
@@ -62,6 +63,7 @@ import SiliconCloud from '../icons/SiliconCloud';
|
||||
import SophNet from '../icons/SophNet';
|
||||
import Spark from '../icons/Spark';
|
||||
import Stepfun from '../icons/Stepfun';
|
||||
import Straico from '../icons/Straico';
|
||||
import TencentCloud from '../icons/TencentCloud';
|
||||
import Together from '../icons/Together';
|
||||
import Upstage from '../icons/Upstage';
|
||||
@@ -98,7 +100,7 @@ export interface RNProviderMapping {
|
||||
}
|
||||
|
||||
export const rnProviderMappings: RNProviderMapping[] = [
|
||||
{ Icon: LobeHub, keywords: [RNModelProvider.LobeHub] },
|
||||
{ Icon: LobeHub, combineMultiple: 1.1, keywords: [RNModelProvider.LobeHub] },
|
||||
{ Icon: Zhipu, combineMultiple: 1.25, keywords: [RNModelProvider.ZhiPu] },
|
||||
{
|
||||
Combine: memo(({ size = 24, type = 'color', ...props }) => (
|
||||
@@ -261,9 +263,31 @@ export const rnProviderMappings: RNProviderMapping[] = [
|
||||
Icon: Vercel,
|
||||
keywords: [RNModelProvider.V0],
|
||||
},
|
||||
{ Icon: Vercel, combineMultiple: 0.9, keywords: [RNModelProvider.Vercel] },
|
||||
{ Icon: Bfl, keywords: [RNModelProvider.Bfl] },
|
||||
{ Icon: Nebius, combineMultiple: 0.75, keywords: [RNModelProvider.Nebius] },
|
||||
{ Icon: NewAPI, combineMultiple: 0.85, keywords: [RNModelProvider.NewAPI] },
|
||||
{ Icon: AkashChat, combineMultiple: 0.8, keywords: [RNModelProvider.AkashChat] },
|
||||
{ Icon: SophNet, combineMultiple: 0.85, keywords: [RNModelProvider.SophNet] },
|
||||
{
|
||||
Combine: memo(({ size = 24, ...props }) => (
|
||||
<Combine
|
||||
left={
|
||||
<Ollama.Combine
|
||||
extra={'Cloud'}
|
||||
extraStyle={{ fontSize: 21, fontWeight: 500, marginLeft: 3 }}
|
||||
size={size * 1.16}
|
||||
/>
|
||||
}
|
||||
right={<Ollama.Combine size={0} />}
|
||||
size={size}
|
||||
{...props}
|
||||
/>
|
||||
)),
|
||||
Icon: Ollama,
|
||||
keywords: [RNModelProvider.OllamaCloud],
|
||||
},
|
||||
{ Icon: LongCat, combineMultiple: 1, keywords: [RNModelProvider.LongCat] },
|
||||
{ Icon: Cerebras, combineMultiple: 1, keywords: [RNModelProvider.Cerebras] },
|
||||
{ Icon: Straico, combineMultiple: 1, keywords: [RNModelProvider.Straico] },
|
||||
];
|
||||
|
||||
@@ -11,6 +11,7 @@ export enum RNModelProvider {
|
||||
Bedrock = 'bedrock',
|
||||
Bfl = 'bfl',
|
||||
BurnCloud = 'burncloud',
|
||||
Cerebras = 'cerebras',
|
||||
Cloudflare = 'cloudflare',
|
||||
Cohere = 'cohere',
|
||||
CometAPI = 'cometapi',
|
||||
@@ -31,6 +32,7 @@ export enum RNModelProvider {
|
||||
Jina = 'jina',
|
||||
LmStudio = 'lmstudio',
|
||||
LobeHub = 'lobehub',
|
||||
LongCat = 'longcat',
|
||||
Minimax = 'minimax',
|
||||
Mistral = 'mistral',
|
||||
ModelScope = 'modelscope',
|
||||
@@ -40,6 +42,7 @@ export enum RNModelProvider {
|
||||
Novita = 'novita',
|
||||
Nvidia = 'nvidia',
|
||||
Ollama = 'ollama',
|
||||
OllamaCloud = 'ollamacloud',
|
||||
OpenAI = 'openai',
|
||||
OpenRouter = 'openrouter',
|
||||
PPIO = 'ppio',
|
||||
@@ -54,12 +57,14 @@ export enum RNModelProvider {
|
||||
SophNet = 'sophnet',
|
||||
Spark = 'spark',
|
||||
Stepfun = 'stepfun',
|
||||
Straico = 'straico',
|
||||
Taichu = 'taichu',
|
||||
TencentCloud = 'tencentcloud',
|
||||
TogetherAI = 'togetherai',
|
||||
Upstage = 'upstage',
|
||||
V0 = 'v0',
|
||||
VLLM = 'vllm',
|
||||
Vercel = 'vercelaigateway',
|
||||
VertexAI = 'vertexai',
|
||||
Volcengine = 'volcengine',
|
||||
Wenxin = 'wenxin',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { ComponentType } from 'react';
|
||||
import type { ViewStyle } from 'react-native';
|
||||
import type { TextStyle, ViewStyle } from 'react-native';
|
||||
|
||||
export interface RNIconProps {
|
||||
color?: string;
|
||||
@@ -28,7 +28,7 @@ export interface RNIconCombineProps extends RNIconProps {
|
||||
Text?: ComponentType<RNIconProps>;
|
||||
color?: string;
|
||||
extra?: string;
|
||||
extraStyle?: ViewStyle;
|
||||
extraStyle?: ViewStyle & TextStyle;
|
||||
iconProps?: Partial<RNIconAvatarProps>;
|
||||
inverse?: boolean;
|
||||
showLogo?: boolean;
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
1. 🔍 **智能检测** - 自动对比 `/src` 和 `/packages/react-native/src/icons` 目录,识别未转换的 Web 图标
|
||||
2. 🚀 **批量转换** - 调用 `batch-converter.ts` 完成图标转换
|
||||
3. 📦 **更新导出** - 调用 `export-updater.ts` 更新主导出文件
|
||||
4. 🔧 **代码检查** - 可选的运行 lint 检查验证代码质量
|
||||
5. 🧪 **构建测试** - 可选的运行构建测试验证转换结果
|
||||
4. 🔄 **同步配置** - 调用 `feature-config-syncer.ts` 同步特性配置文件(modelConfig、providerEnum、providerConfig)
|
||||
5. 🔧 **代码检查** - 可选的运行 lint 检查验证代码质量
|
||||
6. 🧪 **构建测试** - 可选的运行构建测试验证转换结果
|
||||
|
||||
这个脚本整合了现有的转换工具,提供一站式的转换解决方案。
|
||||
|
||||
@@ -84,20 +85,23 @@ graph TD
|
||||
F --> G{转换成功?}
|
||||
G -->|否| H[显示失败统计]
|
||||
G -->|是| I[更新导出文件]
|
||||
I --> J{启用代码检查?}
|
||||
J -->|否| K{启用构建测试?}
|
||||
J -->|是| L[运行代码检查]
|
||||
L --> M{代码检查通过?}
|
||||
M -->|否| H
|
||||
M -->|是| K
|
||||
K -->|否| N[显示成功统计]
|
||||
K -->|是| O[运行构建测试]
|
||||
O --> P{构建测试通过?}
|
||||
P -->|否| H
|
||||
P -->|是| N
|
||||
H --> Q[结束]
|
||||
N --> Q
|
||||
D --> Q
|
||||
I --> J[同步特性配置文件]
|
||||
J --> K{同步成功?}
|
||||
K -->|否| H
|
||||
K -->|是| L{启用代码检查?}
|
||||
L -->|否| M{启用构建测试?}
|
||||
L -->|是| N[运行代码检查]
|
||||
N --> O{代码检查通过?}
|
||||
O -->|否| H
|
||||
O -->|是| M
|
||||
M -->|否| P[显示成功统计]
|
||||
M -->|是| Q[运行构建测试]
|
||||
Q --> R{构建测试通过?}
|
||||
R -->|否| H
|
||||
R -->|是| P
|
||||
H --> S[结束]
|
||||
P --> S
|
||||
D --> S
|
||||
```
|
||||
|
||||
## 输出说明
|
||||
@@ -108,6 +112,7 @@ graph TD
|
||||
- 📝 **待转换列表** - 显示所有需要转换的图标名称
|
||||
- 🚀 **转换进度** - 实时显示转换过程
|
||||
- 📦 **导出更新** - 更新主导出文件状态
|
||||
- 🔄 **配置同步** - 同步特性配置文件(modelConfig、providerEnum、providerConfig)
|
||||
- 🔧 **代码检查** - 代码质量检查结果(如果启用)
|
||||
- 🧪 **构建测试** - 构建测试结果(如果启用)
|
||||
- 📊 **最终统计** - 成功 / 失败 / 跳过的详细数量
|
||||
@@ -118,14 +123,16 @@ graph TD
|
||||
auto-converter.ts (主脚本)
|
||||
├── batch-converter.ts (批量转换)
|
||||
├── export-updater.ts (导出更新)
|
||||
├── feature-config-syncer.ts (配置同步)
|
||||
├── test-runner.ts (测试运行器)
|
||||
└── utils/file-converter.ts (文件转换器)
|
||||
```
|
||||
|
||||
- **auto-converter.ts** - 主要的一站式脚本
|
||||
- **batch-converter.ts** - 专门的批量转换工具
|
||||
- **test-runner.ts** - 专门的测试运行器
|
||||
- **export-updater.ts** - 专门的导出更新工具
|
||||
- **feature-config-syncer.ts** - 专门的特性配置文件同步工具
|
||||
- **test-runner.ts** - 专门的测试运行器
|
||||
|
||||
## 错误处理
|
||||
|
||||
@@ -143,9 +150,62 @@ auto-converter.ts (主脚本)
|
||||
- 🚀 预演模式快速预览转换计划
|
||||
- 🚀 详细的进度显示和时间统计
|
||||
|
||||
## 配置文件同步
|
||||
|
||||
### 同步的配置文件
|
||||
|
||||
脚本会自动同步以下三个特性配置文件:
|
||||
|
||||
1. **modelConfig.ts** - 模型图标映射配置
|
||||
2. **providerEnum.ts** - 提供商枚举定义
|
||||
3. **providerConfig.tsx** - 提供商图标映射配置
|
||||
|
||||
### 转换规则
|
||||
|
||||
配置文件从 Web 版本转换到 React Native 版本时,会自动应用以下转换:
|
||||
|
||||
#### 1. 导入路径转换
|
||||
|
||||
- `@/IconName` → `../icons/IconName`
|
||||
- `@/features/IconAvatar` → `./IconAvatar`
|
||||
- `@/types` → `./types`
|
||||
|
||||
#### 2. 类型名称转换
|
||||
|
||||
- `ModelProvider` → `RNModelProvider`
|
||||
- `ModelMapping` → `RNModelMapping`
|
||||
- `ProviderMapping` → `RNProviderMapping`
|
||||
- `ModelProviderKey` → `RNModelProviderKey`
|
||||
|
||||
#### 3. 类型导入转换
|
||||
|
||||
- `IconType` → `RNIconProps`
|
||||
- `IconAvatarProps` → `RNIconAvatarProps`
|
||||
- `IconCombineProps` → `RNIconCombineProps`
|
||||
|
||||
#### 4. 导出变量名转换
|
||||
|
||||
- `modelMappings` → `rnModelMappings`
|
||||
- `providerMappings` → `rnProviderMappings`
|
||||
|
||||
#### 5. 特殊处理
|
||||
|
||||
- 移除 `@lobehub/ui` 的 `DivProps` 导入
|
||||
- 移除 `DivProps` 类型引用
|
||||
|
||||
### 独立使用
|
||||
|
||||
配置同步器也可以独立运行:
|
||||
|
||||
```bash
|
||||
# 独立运行配置同步
|
||||
npx tsx feature-config-syncer.ts
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **权限** - 确保对项目目录有读写权限
|
||||
2. **依赖** - 需要安装所有相关的 npm 依赖
|
||||
3. **备份** - 建议在大规模转换前备份项目
|
||||
4. **测试** - 使用 `--dry-run` 和 `--max` 选项进行小规模测试
|
||||
5. **配置同步** - 配置文件会在每次运行时自动同步,确保 Web 和 RN 版本保持一致
|
||||
|
||||
@@ -4,6 +4,8 @@ import { existsSync, readdirSync } from 'node:fs';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
import FeatureConfigSyncer from './feature-config-syncer';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
@@ -196,6 +198,23 @@ class AutoConverter {
|
||||
}
|
||||
}
|
||||
|
||||
// 同步特性配置文件
|
||||
private async syncFeatureConfigs(options: ConversionOptions): Promise<boolean> {
|
||||
if (options.dryRun) {
|
||||
console.log('\n🔄 预演模式:不会实际同步配置文件');
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
const syncer = new FeatureConfigSyncer();
|
||||
const success = await syncer.syncAll();
|
||||
return success;
|
||||
} catch (error) {
|
||||
console.error('❌ 配置文件同步失败:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 运行构建测试
|
||||
private async runBuildTest(options: ConversionOptions): Promise<boolean> {
|
||||
if (!options.buildTest) {
|
||||
@@ -305,6 +324,10 @@ class AutoConverter {
|
||||
success = await this.updateExports(options);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
success = await this.syncFeatureConfigs(options);
|
||||
}
|
||||
|
||||
if (success && options.lintCheck) {
|
||||
success = await this.runLintCheck(options);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,303 @@
|
||||
#!/usr/bin/env npx tsx
|
||||
import { execSync } from 'node:child_process';
|
||||
import { promises as fs } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
/**
|
||||
* 特性配置文件同步器
|
||||
* 将 web 版本的配置文件转换为 React Native 版本
|
||||
*/
|
||||
|
||||
interface ConfigFile {
|
||||
name: string;
|
||||
sourceFile: string;
|
||||
targetFile: string;
|
||||
}
|
||||
|
||||
class FeatureConfigSyncer {
|
||||
private projectRoot: string;
|
||||
private configFiles: ConfigFile[];
|
||||
|
||||
constructor() {
|
||||
this.projectRoot = path.resolve(__dirname, '../../');
|
||||
this.configFiles = [
|
||||
{
|
||||
name: 'modelConfig.ts',
|
||||
sourceFile: path.join(this.projectRoot, 'src/features/modelConfig.ts'),
|
||||
targetFile: path.join(
|
||||
this.projectRoot,
|
||||
'packages/react-native/src/features/modelConfig.ts',
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'providerEnum.ts',
|
||||
sourceFile: path.join(this.projectRoot, 'src/features/providerEnum.ts'),
|
||||
targetFile: path.join(
|
||||
this.projectRoot,
|
||||
'packages/react-native/src/features/providerEnum.ts',
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'providerConfig.tsx',
|
||||
sourceFile: path.join(this.projectRoot, 'src/features/providerConfig.tsx'),
|
||||
targetFile: path.join(
|
||||
this.projectRoot,
|
||||
'packages/react-native/src/features/providerConfig.tsx',
|
||||
),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换配置文件内容
|
||||
*/
|
||||
private transformContent(content: string, fileName: string): string {
|
||||
let transformed = content;
|
||||
|
||||
// 1. 转换导入路径:@/IconName → ../icons/IconName
|
||||
transformed = transformed.replaceAll(/from '@\/([A-Z][\dA-Za-z]*)'/g, "from '../icons/$1'");
|
||||
|
||||
// 2. 转换类型名称
|
||||
// ModelProvider → RNModelProvider (枚举定义)
|
||||
transformed = transformed.replaceAll(
|
||||
/export enum ModelProvider\s*{/g,
|
||||
'export enum RNModelProvider {',
|
||||
);
|
||||
|
||||
// ModelProviderKey → RNModelProviderKey (类型定义)
|
||||
transformed = transformed.replaceAll(
|
||||
/export type ModelProviderKey\s*=/g,
|
||||
'export type RNModelProviderKey =',
|
||||
);
|
||||
|
||||
// ModelMapping → RNModelMapping (接口和类型)
|
||||
transformed = transformed.replaceAll(/\bModelMapping\b/g, 'RNModelMapping');
|
||||
|
||||
// ProviderMapping → RNProviderMapping (接口和类型)
|
||||
transformed = transformed.replaceAll(/\bProviderMapping\b/g, 'RNProviderMapping');
|
||||
|
||||
// ModelProvider 引用 → RNModelProvider (在使用的地方)
|
||||
// 处理 typeof ModelProvider 的情况
|
||||
transformed = transformed.replaceAll('typeof ModelProvider', 'typeof RNModelProvider');
|
||||
// 处理 ModelProvider. 的情况
|
||||
transformed = transformed.replaceAll(/\bModelProvider\./g, 'RNModelProvider.');
|
||||
// 处理导入的情况
|
||||
transformed = transformed.replaceAll('{ ModelProvider }', '{ RNModelProvider }');
|
||||
transformed = transformed.replaceAll("from './providerEnum'", "from './providerEnum'");
|
||||
|
||||
// 3. 转换类型导入和使用
|
||||
// IconType → RNIconProps
|
||||
transformed = transformed.replaceAll(/\bIconType\b/g, 'RNIconProps');
|
||||
|
||||
// IconAvatarProps → RNIconAvatarProps
|
||||
transformed = transformed.replaceAll(/\bIconAvatarProps\b/g, 'RNIconAvatarProps');
|
||||
|
||||
// IconCombineProps → RNIconCombineProps
|
||||
transformed = transformed.replaceAll(/\bIconCombineProps\b/g, 'RNIconCombineProps');
|
||||
|
||||
// 确保类型名称带有 RN 前缀
|
||||
if (fileName === 'modelConfig.ts') {
|
||||
// ModelIconType → RNModelIconType
|
||||
transformed = transformed.replaceAll('type ModelIconType = ', 'type RNModelIconType = ');
|
||||
transformed = transformed.replaceAll('Icon: ModelIconType;', 'Icon: RNModelIconType;');
|
||||
}
|
||||
|
||||
if (fileName === 'providerConfig.tsx') {
|
||||
// ProviderIconType → RNProviderIconType
|
||||
transformed = transformed.replaceAll(
|
||||
'type ProviderIconType = ',
|
||||
'type RNProviderIconType = ',
|
||||
);
|
||||
transformed = transformed.replaceAll('Icon: ProviderIconType;', 'Icon: RNProviderIconType;');
|
||||
}
|
||||
|
||||
// 4. 转换导出变量名
|
||||
transformed = transformed.replaceAll(
|
||||
'export const modelMappings:',
|
||||
'export const rnModelMappings:',
|
||||
);
|
||||
transformed = transformed.replaceAll(
|
||||
'export const providerMappings:',
|
||||
'export const rnProviderMappings:',
|
||||
);
|
||||
|
||||
// 5. 特殊导入处理
|
||||
// 移除 @lobehub/ui 的 DivProps 导入
|
||||
transformed = transformed.replaceAll(
|
||||
/import\s*{\s*DivProps\s*}\s*from\s*'@lobehub\/ui';\s*\n/g,
|
||||
'',
|
||||
);
|
||||
|
||||
// 移除 DivProps 类型引用
|
||||
transformed = transformed.replaceAll(/\bDivProps\s*&\s*/g, '');
|
||||
|
||||
// 调整类型导入路径
|
||||
transformed = transformed.replaceAll("from '@/features/IconAvatar'", "from './IconAvatar'");
|
||||
transformed = transformed.replaceAll("from '@/features/IconCombine'", "from './IconCombine'");
|
||||
transformed = transformed.replaceAll("from '@/types'", "from './types'");
|
||||
|
||||
// 处理特殊的导入语句
|
||||
if (fileName === 'modelConfig.ts') {
|
||||
// 添加 React Native 特有的注释
|
||||
transformed = transformed.replaceAll(
|
||||
"import { FC } from 'react';",
|
||||
"import { FC } from 'react';\n",
|
||||
);
|
||||
} else if (fileName === 'providerConfig.tsx') {
|
||||
// 移除 memo 导入中的多余部分
|
||||
transformed = transformed.replaceAll(
|
||||
/import\s*{\s*FC,\s*memo\s*}\s*from\s*'react';/g,
|
||||
"import { FC, memo } from 'react';",
|
||||
);
|
||||
}
|
||||
|
||||
// 6. 修复特定的导入语句格式
|
||||
// 处理 Kwaipilot 的特殊导入 - 从 @/icons 改为直接导入
|
||||
transformed = transformed.replaceAll(
|
||||
"import { Kwaipilot } from '@/icons';",
|
||||
"import Kwaipilot from '../icons/Kwaipilot';",
|
||||
);
|
||||
|
||||
// 移除转换后多余的类型导入行
|
||||
// 这些在步骤5的路径转换后会变成 './IconAvatar' 和 './IconCombine'
|
||||
transformed = transformed.replaceAll(
|
||||
"import type { RNIconAvatarProps } from './IconAvatar';\n",
|
||||
'',
|
||||
);
|
||||
transformed = transformed.replaceAll(
|
||||
"import type { RNIconCombineProps } from './IconCombine';\n",
|
||||
'',
|
||||
);
|
||||
transformed = transformed.replaceAll("import type { RNIconProps } from './types';\n", '');
|
||||
|
||||
// 7. 统一添加类型导入
|
||||
if (fileName === 'modelConfig.ts') {
|
||||
// 在 Kwaipilot 导入后添加统一的类型导入
|
||||
transformed = transformed.replaceAll(
|
||||
"import Kwaipilot from '../icons/Kwaipilot';",
|
||||
"import Kwaipilot from '../icons/Kwaipilot';\nimport type { RNIconAvatarProps, RNIconCombineProps, RNIconProps } from './types';",
|
||||
);
|
||||
} else if (fileName === 'providerConfig.tsx') {
|
||||
// 在 Combine 导入之前添加统一的类型导入
|
||||
transformed = transformed.replaceAll(
|
||||
"import Combine from './ProviderCombine/Combine';",
|
||||
"import type { RNIconAvatarProps, RNIconCombineProps, RNIconProps } from './types';\nimport Combine from './ProviderCombine/Combine';",
|
||||
);
|
||||
}
|
||||
|
||||
return transformed;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步单个配置文件
|
||||
*/
|
||||
private async syncFile(config: ConfigFile): Promise<boolean> {
|
||||
try {
|
||||
console.log(`📝 同步 ${config.name}...`);
|
||||
|
||||
// 读取源文件
|
||||
const content = await fs.readFile(config.sourceFile, 'utf8');
|
||||
|
||||
// 转换内容
|
||||
const transformed = this.transformContent(content, config.name);
|
||||
|
||||
// 写入目标文件
|
||||
await fs.writeFile(config.targetFile, transformed, 'utf8');
|
||||
|
||||
console.log(`✅ ${config.name} 同步完成`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error(`❌ ${config.name} 同步失败:`, error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化生成的文件
|
||||
*/
|
||||
private async formatFiles(): Promise<boolean> {
|
||||
try {
|
||||
console.log('\n🎨 格式化生成的文件...');
|
||||
|
||||
const targetFiles = this.configFiles.map((config) => config.targetFile);
|
||||
|
||||
// 使用 prettier 格式化
|
||||
try {
|
||||
execSync(`npx prettier --write ${targetFiles.join(' ')}`, {
|
||||
cwd: this.projectRoot,
|
||||
encoding: 'utf8',
|
||||
stdio: 'pipe',
|
||||
});
|
||||
console.log('✅ Prettier 格式化完成');
|
||||
} catch {
|
||||
console.log('⚠️ Prettier 格式化失败,尝试使用 ESLint...');
|
||||
}
|
||||
|
||||
// 使用 eslint 修复
|
||||
try {
|
||||
const featuresDir = path.join(this.projectRoot, 'packages/react-native/src/features');
|
||||
execSync(`npx eslint "${featuresDir}/*.{ts,tsx}" --fix`, {
|
||||
cwd: this.projectRoot,
|
||||
encoding: 'utf8',
|
||||
stdio: 'pipe',
|
||||
});
|
||||
console.log('✅ ESLint 修复完成');
|
||||
} catch {
|
||||
console.log('⚠️ ESLint 修复跳过');
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('❌ 格式化失败:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步所有配置文件
|
||||
*/
|
||||
async syncAll(options: { format?: boolean } = {}): Promise<boolean> {
|
||||
console.log('\n🔄 开始同步特性配置文件...\n');
|
||||
|
||||
const results = await Promise.all(this.configFiles.map((config) => this.syncFile(config)));
|
||||
|
||||
const allSuccess = results.every(Boolean);
|
||||
|
||||
if (allSuccess) {
|
||||
console.log('\n✅ 所有配置文件同步完成');
|
||||
|
||||
// 格式化生成的文件
|
||||
if (options.format !== false) {
|
||||
await this.formatFiles();
|
||||
}
|
||||
} else {
|
||||
console.log('\n❌ 部分配置文件同步失败');
|
||||
}
|
||||
|
||||
return allSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
// 主函数
|
||||
async function main() {
|
||||
try {
|
||||
const syncer = new FeatureConfigSyncer();
|
||||
const success = await syncer.syncAll();
|
||||
process.exit(success ? 0 : 1);
|
||||
} catch (error) {
|
||||
console.error('💥 执行失败:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果直接运行此脚本
|
||||
if (require.main === module) {
|
||||
// eslint-disable-next-line unicorn/prefer-top-level-await
|
||||
main().catch((error) => {
|
||||
console.error('❌ 主函数执行失败:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
// 导出类供其他脚本使用
|
||||
export default FeatureConfigSyncer;
|
||||
Reference in New Issue
Block a user