Files
cc-switch/src/utils/formatters.ts
T
千羽 c49cfa5ac5 feat(deeplink): 深链支持用量查询配置 (#400)
## 新增功能
- 深链导入支持用量查询配置参数:
  - `usageEnabled`: 是否启用用量查询
  - `usageScript`: Base64 编码的用量查询脚本
  - `usageApiKey`: 用量查询专用 API Key
  - `usageBaseUrl`: 用量查询专用 Base URL
  - `usageAccessToken`: 访问令牌(NewAPI 模板)
  - `usageUserId`: 用户 ID(NewAPI 模板)
  - `usageAutoInterval`: 自动查询间隔(分钟)

## 修改文件
- **mod.rs**: DeepLinkImportRequest 结构体添加用量查询字段
- **parser.rs**: 解析 URL 中的用量查询参数
- **provider.rs**: 构建 ProviderMeta 包含 UsageScript 配置
- **deeplink.ts**: 添加 TypeScript 类型定义
- **DeepLinkImportDialog.tsx**: 确认对话框显示用量查询配置

## Bug 修复
- **formatters.ts**: 修复 formatJSON() 格式化时删除 "env" 键的问题

## 深链格式示例
```
ccswitch://v1/import?resource=provider&app=claude&name=xxx&usageEnabled=true&usageScript={base64}&usageAutoInterval=30
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-14 21:52:13 +08:00

80 lines
2.2 KiB
TypeScript

/**
* 格式化 JSON 字符串
* @param value - 原始 JSON 字符串
* @returns 格式化后的 JSON 字符串(2 空格缩进)
* @throws 如果 JSON 格式无效
*/
export function formatJSON(value: string): string {
const trimmed = value.trim();
if (!trimmed) {
return "";
}
const parsed = JSON.parse(trimmed);
return JSON.stringify(parsed, null, 2);
}
/**
* 智能解析 MCP JSON 配置
* 支持两种格式:
* 1. 纯配置对象:{ "command": "npx", "args": [...], ... }
* 2. 带键名包装: "server-name": { "command": "npx", ... } 或 { "server-name": {...} }
*
* @param jsonText - JSON 字符串
* @returns { id?: string, config: object, formattedConfig: string }
* @throws 如果 JSON 格式无效
*/
export function parseSmartMcpJson(jsonText: string): {
id?: string;
config: any;
formattedConfig: string;
} {
let trimmed = jsonText.trim();
if (!trimmed) {
return { config: {}, formattedConfig: "" };
}
// 如果是键值对片段("key": {...}),包装成完整对象
if (trimmed.startsWith('"') && !trimmed.startsWith("{")) {
trimmed = `{${trimmed}}`;
}
const parsed = JSON.parse(trimmed);
// 如果是单键对象且值是对象,提取键名和配置
const keys = Object.keys(parsed);
if (
keys.length === 1 &&
parsed[keys[0]] &&
typeof parsed[keys[0]] === "object" &&
!Array.isArray(parsed[keys[0]])
) {
const id = keys[0];
const config = parsed[id];
return {
id,
config,
formattedConfig: JSON.stringify(config, null, 2),
};
}
// 否则直接使用
return {
config: parsed,
formattedConfig: JSON.stringify(parsed, null, 2),
};
}
/**
* TOML 格式化功能已禁用
*
* 原因:smol-toml 的 parse/stringify 会丢失所有注释和原有排版。
* 由于 TOML 常用于配置文件,注释是重要的文档说明,丢失注释会造成严重的用户体验问题。
*
* 未来可选方案:
* - 使用 @ltd/j-toml(支持注释保留,但需额外依赖和复杂的 API)
* - 实现仅格式化缩进/空白的轻量级方案
* - 使用 toml-eslint-parser + 自定义生成器
*
* 暂时建议:依赖现有的 TOML 语法校验(useCodexTomlValidation),不提供格式化功能。
*/