Revert "fix: improve VS Code config synchronization and code formatting"

This reverts commit 463e430a3d.
This commit is contained in:
Jason
2025-09-18 17:57:32 +08:00
parent 463e430a3d
commit eca14db58c
7 changed files with 106 additions and 195 deletions

View File

@@ -26,8 +26,8 @@ export function AppSwitcher({ activeApp, onSwitch }: AppSwitcherProps) {
<ClaudeIcon <ClaudeIcon
size={16} size={16}
className={ className={
activeApp === "claude" activeApp === "claude"
? "text-[#D97757] dark:text-[#D97757] transition-colors duration-200" ? "text-[#D97757] dark:text-[#D97757] transition-colors duration-200"
: "text-gray-500 dark:text-gray-400 group-hover:text-[#D97757] dark:group-hover:text-[#D97757] transition-colors duration-200" : "text-gray-500 dark:text-gray-400 group-hover:text-[#D97757] dark:group-hover:text-[#D97757] transition-colors duration-200"
} }
/> />

View File

@@ -62,7 +62,7 @@ const JsonEditor: React.FC<JsonEditorProps> = ({
return diagnostics; return diagnostics;
}), }),
[showValidation], [showValidation]
); );
useEffect(() => { useEffect(() => {

View File

@@ -128,26 +128,25 @@ const ProviderForm: React.FC<ProviderFormProps> = ({
const [settingsConfigError, setSettingsConfigError] = useState(""); const [settingsConfigError, setSettingsConfigError] = useState("");
// 用于跟踪是否正在通过通用配置更新 // 用于跟踪是否正在通过通用配置更新
const isUpdatingFromCommonConfig = useRef(false); const isUpdatingFromCommonConfig = useRef(false);
// Codex 通用配置状态 // Codex 通用配置状态
const [useCodexCommonConfig, setUseCodexCommonConfig] = useState(false); const [useCodexCommonConfig, setUseCodexCommonConfig] = useState(false);
const [codexCommonConfigSnippet, setCodexCommonConfigSnippetState] = const [codexCommonConfigSnippet, setCodexCommonConfigSnippetState] = useState<string>(() => {
useState<string>(() => { if (typeof window === "undefined") {
if (typeof window === "undefined") {
return DEFAULT_CODEX_COMMON_CONFIG_SNIPPET;
}
try {
const stored = window.localStorage.getItem(
CODEX_COMMON_CONFIG_STORAGE_KEY,
);
if (stored && stored.trim()) {
return stored;
}
} catch {
// ignore localStorage 读取失败
}
return DEFAULT_CODEX_COMMON_CONFIG_SNIPPET; return DEFAULT_CODEX_COMMON_CONFIG_SNIPPET;
}); }
try {
const stored = window.localStorage.getItem(
CODEX_COMMON_CONFIG_STORAGE_KEY,
);
if (stored && stored.trim()) {
return stored;
}
} catch {
// ignore localStorage 读取失败
}
return DEFAULT_CODEX_COMMON_CONFIG_SNIPPET;
});
const [codexCommonConfigError, setCodexCommonConfigError] = useState(""); const [codexCommonConfigError, setCodexCommonConfigError] = useState("");
const isUpdatingFromCodexCommonConfig = useRef(false); const isUpdatingFromCodexCommonConfig = useRef(false);
// -1 表示自定义null 表示未选择,>= 0 表示预设索引 // -1 表示自定义null 表示未选择,>= 0 表示预设索引
@@ -218,11 +217,7 @@ const ProviderForm: React.FC<ProviderFormProps> = ({
useEffect(() => { useEffect(() => {
if (initialData) { if (initialData) {
if (!isCodex) { if (!isCodex) {
const configString = JSON.stringify( const configString = JSON.stringify(initialData.settingsConfig, null, 2);
initialData.settingsConfig,
null,
2,
);
const hasCommon = hasCommonConfigSnippet( const hasCommon = hasCommonConfigSnippet(
configString, configString,
commonConfigSnippet, commonConfigSnippet,
@@ -240,9 +235,7 @@ const ProviderForm: React.FC<ProviderFormProps> = ({
}; };
if (config.env) { if (config.env) {
setClaudeModel(config.env.ANTHROPIC_MODEL || ""); setClaudeModel(config.env.ANTHROPIC_MODEL || "");
setClaudeSmallFastModel( setClaudeSmallFastModel(config.env.ANTHROPIC_SMALL_FAST_MODEL || "");
config.env.ANTHROPIC_SMALL_FAST_MODEL || "",
);
setBaseUrl(config.env.ANTHROPIC_BASE_URL || ""); // 初始化基础 URL setBaseUrl(config.env.ANTHROPIC_BASE_URL || ""); // 初始化基础 URL
// 初始化 Kimi 模型选择 // 初始化 Kimi 模型选择
@@ -261,13 +254,7 @@ const ProviderForm: React.FC<ProviderFormProps> = ({
setUseCodexCommonConfig(hasCommon); setUseCodexCommonConfig(hasCommon);
} }
} }
}, [ }, [initialData, commonConfigSnippet, codexCommonConfigSnippet, isCodex, codexConfig]);
initialData,
commonConfigSnippet,
codexCommonConfigSnippet,
isCodex,
codexConfig,
]);
// 当选择预设变化时,同步类别 // 当选择预设变化时,同步类别
useEffect(() => { useEffect(() => {
@@ -510,7 +497,7 @@ const ProviderForm: React.FC<ProviderFormProps> = ({
isUpdatingFromCommonConfig.current = false; isUpdatingFromCommonConfig.current = false;
}, 0); }, 0);
} }
// 保存通用配置到 localStorage // 保存通用配置到 localStorage
if (!validationError && typeof window !== "undefined") { if (!validationError && typeof window !== "undefined") {
try { try {
@@ -542,7 +529,10 @@ const ProviderForm: React.FC<ProviderFormProps> = ({
setBaseUrl(""); // 清空基础 URL setBaseUrl(""); // 清空基础 URL
// 同步通用配置状态 // 同步通用配置状态
const hasCommon = hasCommonConfigSnippet(configString, commonConfigSnippet); const hasCommon = hasCommonConfigSnippet(
configString,
commonConfigSnippet,
);
setUseCommonConfig(hasCommon); setUseCommonConfig(hasCommon);
setCommonConfigError(""); setCommonConfigError("");
@@ -653,7 +643,10 @@ const ProviderForm: React.FC<ProviderFormProps> = ({
updateSettingsConfigValue(configString); updateSettingsConfigValue(configString);
// 同步通用配置开关 // 同步通用配置开关
const hasCommon = hasCommonConfigSnippet(configString, commonConfigSnippet); const hasCommon = hasCommonConfigSnippet(
configString,
commonConfigSnippet,
);
setUseCommonConfig(hasCommon); setUseCommonConfig(hasCommon);
}; };
@@ -688,12 +681,11 @@ const ProviderForm: React.FC<ProviderFormProps> = ({
// Codex: 处理通用配置开关 // Codex: 处理通用配置开关
const handleCodexCommonConfigToggle = (checked: boolean) => { const handleCodexCommonConfigToggle = (checked: boolean) => {
const { updatedConfig, error: snippetError } = const { updatedConfig, error: snippetError } = updateTomlCommonConfigSnippet(
updateTomlCommonConfigSnippet( codexConfig,
codexConfig, codexCommonConfigSnippet,
codexCommonConfigSnippet, checked,
checked, );
);
if (snippetError) { if (snippetError) {
setCodexCommonConfigError(snippetError); setCodexCommonConfigError(snippetError);
@@ -761,7 +753,10 @@ const ProviderForm: React.FC<ProviderFormProps> = ({
// 保存 Codex 通用配置到 localStorage // 保存 Codex 通用配置到 localStorage
if (typeof window !== "undefined") { if (typeof window !== "undefined") {
try { try {
window.localStorage.setItem(CODEX_COMMON_CONFIG_STORAGE_KEY, value); window.localStorage.setItem(
CODEX_COMMON_CONFIG_STORAGE_KEY,
value,
);
} catch { } catch {
// ignore localStorage 写入失败 // ignore localStorage 写入失败
} }
@@ -1182,9 +1177,7 @@ const ProviderForm: React.FC<ProviderFormProps> = ({
useCommonConfig={useCodexCommonConfig} useCommonConfig={useCodexCommonConfig}
onCommonConfigToggle={handleCodexCommonConfigToggle} onCommonConfigToggle={handleCodexCommonConfigToggle}
commonConfigSnippet={codexCommonConfigSnippet} commonConfigSnippet={codexCommonConfigSnippet}
onCommonConfigSnippetChange={ onCommonConfigSnippetChange={handleCodexCommonConfigSnippetChange}
handleCodexCommonConfigSnippetChange
}
commonConfigError={codexCommonConfigError} commonConfigError={codexCommonConfigError}
authError={codexAuthError} authError={codexAuthError}
/> />

View File

@@ -60,7 +60,7 @@ const ClaudeConfigEditor: React.FC<ClaudeConfigEditorProps> = ({
// 支持按下 ESC 关闭弹窗 // 支持按下 ESC 关闭弹窗
useEffect(() => { useEffect(() => {
if (!isCommonConfigModalOpen) return; if (!isCommonConfigModalOpen) return;
const onKeyDown = (e: KeyboardEvent) => { const onKeyDown = (e: KeyboardEvent) => {
if (e.key === "Escape") { if (e.key === "Escape") {
e.preventDefault(); e.preventDefault();
@@ -120,13 +120,15 @@ const ClaudeConfigEditor: React.FC<ClaudeConfigEditorProps> = ({
rows={12} rows={12}
/> />
{configError && ( {configError && (
<p className="text-xs text-red-500 dark:text-red-400">{configError}</p> <p className="text-xs text-red-500 dark:text-red-400">
{configError}
</p>
)} )}
<p className="text-xs text-gray-500 dark:text-gray-400"> <p className="text-xs text-gray-500 dark:text-gray-400">
Claude Code settings.json Claude Code settings.json
</p> </p>
{isCommonConfigModalOpen && ( {isCommonConfigModalOpen && (
<div <div
className="fixed inset-0 z-50 flex items-center justify-center" className="fixed inset-0 z-50 flex items-center justify-center"
onMouseDown={(e) => { onMouseDown={(e) => {
if (e.target === e.currentTarget) closeModal(); if (e.target === e.currentTarget) closeModal();
@@ -134,7 +136,7 @@ const ClaudeConfigEditor: React.FC<ClaudeConfigEditorProps> = ({
> >
{/* Backdrop - 统一背景样式 */} {/* Backdrop - 统一背景样式 */}
<div className="absolute inset-0 bg-black/50 dark:bg-black/70 backdrop-blur-sm" /> <div className="absolute inset-0 bg-black/50 dark:bg-black/70 backdrop-blur-sm" />
{/* Modal - 统一窗口样式 */} {/* Modal - 统一窗口样式 */}
<div className="relative bg-white dark:bg-gray-900 rounded-xl shadow-lg max-w-2xl w-full mx-4 max-h-[90vh] overflow-hidden flex flex-col"> <div className="relative bg-white dark:bg-gray-900 rounded-xl shadow-lg max-w-2xl w-full mx-4 max-h-[90vh] overflow-hidden flex flex-col">
{/* Header - 统一标题栏样式 */} {/* Header - 统一标题栏样式 */}
@@ -151,7 +153,7 @@ const ClaudeConfigEditor: React.FC<ClaudeConfigEditorProps> = ({
<X size={18} /> <X size={18} />
</button> </button>
</div> </div>
{/* Content - 统一内容区域样式 */} {/* Content - 统一内容区域样式 */}
<div className="flex-1 overflow-auto p-6 space-y-4"> <div className="flex-1 overflow-auto p-6 space-y-4">
<p className="text-sm text-gray-500 dark:text-gray-400"> <p className="text-sm text-gray-500 dark:text-gray-400">
@@ -169,7 +171,7 @@ const ClaudeConfigEditor: React.FC<ClaudeConfigEditorProps> = ({
</p> </p>
)} )}
</div> </div>
{/* Footer - 统一底部按钮样式 */} {/* Footer - 统一底部按钮样式 */}
<div className="flex items-center justify-end gap-3 p-6 border-t border-gray-200 dark:border-gray-800 bg-gray-100 dark:bg-gray-800"> <div className="flex items-center justify-end gap-3 p-6 border-t border-gray-200 dark:border-gray-800 bg-gray-100 dark:bg-gray-800">
<button <button

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect, useRef } from "react"; import React, { useState, useEffect } from "react";
import { X, Save } from "lucide-react"; import { X, Save } from "lucide-react";
import { extractBaseUrlFromToml } from "../../utils/providerConfigUtils"; import { extractBaseUrlFromToml } from "../../utils/providerConfigUtils";
@@ -34,7 +34,6 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
const [vscodeError, setVscodeError] = useState(""); const [vscodeError, setVscodeError] = useState("");
const [vscodeSuccess, setVscodeSuccess] = useState(""); const [vscodeSuccess, setVscodeSuccess] = useState("");
const [isWritingVscode, setIsWritingVscode] = useState(false); const [isWritingVscode, setIsWritingVscode] = useState(false);
const lastAppliedBaseUrlRef = useRef<string | null>(null);
useEffect(() => { useEffect(() => {
if (commonConfigError && !isCommonConfigModalOpen) { if (commonConfigError && !isCommonConfigModalOpen) {
@@ -50,61 +49,6 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
return () => window.clearTimeout(timer); return () => window.clearTimeout(timer);
}, [vscodeSuccess]); }, [vscodeSuccess]);
const ensureVscodeApiAvailable = () => {
if (typeof window === "undefined" || !window.api?.writeVscodeSettings) {
setVscodeError("当前环境暂不支持写入 VS Code 配置");
return false;
}
return true;
};
const applyVscodeConfig = async (
baseUrl: string,
successMessage = "已写入 VS Code 配置",
) => {
if (!ensureVscodeApiAvailable()) {
return false;
}
setIsWritingVscode(true);
try {
const success = await window.api.writeVscodeSettings(baseUrl);
if (success) {
setVscodeSuccess(successMessage);
lastAppliedBaseUrlRef.current = baseUrl;
return true;
}
setVscodeError("写入 VS Code 配置失败,请稍后重试");
} catch (error) {
setVscodeError(`写入 VS Code 配置失败: ${String(error)}`);
} finally {
setIsWritingVscode(false);
}
return false;
};
const removeVscodeConfig = async () => {
if (!ensureVscodeApiAvailable()) {
return false;
}
setIsWritingVscode(true);
try {
const success = await window.api.writeVscodeSettings();
if (success) {
setVscodeSuccess("已移除 VS Code 配置");
lastAppliedBaseUrlRef.current = null;
return true;
}
setVscodeError("移除 VS Code 配置失败,请稍后重试");
} catch (error) {
setVscodeError(`移除 VS Code 配置失败: ${String(error)}`);
} finally {
setIsWritingVscode(false);
}
return false;
};
const handleVscodeConfigToggle = async (checked: boolean) => { const handleVscodeConfigToggle = async (checked: boolean) => {
if (isWritingVscode) return; if (isWritingVscode) return;
@@ -112,6 +56,12 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
setVscodeError(""); setVscodeError("");
setVscodeSuccess(""); setVscodeSuccess("");
if (typeof window === "undefined" || !window.api?.writeVscodeSettings) {
setVscodeError("当前环境暂不支持写入 VS Code 配置");
setWriteVscodeConfig(!checked);
return;
}
if (checked) { if (checked) {
const trimmed = configValue.trim(); const trimmed = configValue.trim();
if (!trimmed) { if (!trimmed) {
@@ -127,70 +77,46 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
return; return;
} }
const success = await applyVscodeConfig(baseUrl);
if (!success) {
setWriteVscodeConfig(false);
}
return;
}
const success = await removeVscodeConfig();
if (!success) {
setWriteVscodeConfig(true);
}
};
useEffect(() => {
if (!writeVscodeConfig || isWritingVscode) {
return;
}
const trimmed = configValue.trim();
if (!trimmed) {
return;
}
const baseUrl = extractBaseUrlFromToml(trimmed);
if (!baseUrl) {
setVscodeError("未在 config.toml 中找到 base_url 字段");
setWriteVscodeConfig(false);
return;
}
if (lastAppliedBaseUrlRef.current === baseUrl) {
return;
}
const sync = async () => {
// 直接调用 API 而不依赖 applyVscodeConfig 函数,避免闭包问题
if (typeof window === "undefined" || !window.api?.writeVscodeSettings) {
setVscodeError("当前环境暂不支持写入 VS Code 配置");
return;
}
setIsWritingVscode(true); setIsWritingVscode(true);
try { try {
const success = await window.api.writeVscodeSettings(baseUrl); const success = await window.api.writeVscodeSettings(baseUrl);
if (success) { if (success) {
setVscodeSuccess("已更新 VS Code 配置"); setVscodeSuccess("已写入 VS Code 配置");
lastAppliedBaseUrlRef.current = baseUrl;
} else { } else {
setVscodeError("写入 VS Code 配置失败,请稍后重试"); setVscodeError("写入 VS Code 配置失败,请稍后重试");
setWriteVscodeConfig(false);
} }
} catch (error) { } catch (error) {
setVscodeError(`写入 VS Code 配置失败: ${String(error)}`); setVscodeError(`写入 VS Code 配置失败: ${String(error)}`);
setWriteVscodeConfig(false);
} finally { } finally {
setIsWritingVscode(false); setIsWritingVscode(false);
} }
};
sync(); return;
}, [configValue, writeVscodeConfig, isWritingVscode]); }
setIsWritingVscode(true);
try {
const success = await window.api.writeVscodeSettings();
if (success) {
setVscodeSuccess("已移除 VS Code 配置");
} else {
setVscodeError("移除 VS Code 配置失败,请稍后重试");
setWriteVscodeConfig(true);
}
} catch (error) {
setVscodeError(`移除 VS Code 配置失败: ${String(error)}`);
setWriteVscodeConfig(true);
} finally {
setIsWritingVscode(false);
}
};
// 支持按下 ESC 关闭弹窗 // 支持按下 ESC 关闭弹窗
useEffect(() => { useEffect(() => {
if (!isCommonConfigModalOpen) return; if (!isCommonConfigModalOpen) return;
const onKeyDown = (e: KeyboardEvent) => { const onKeyDown = (e: KeyboardEvent) => {
if (e.key === "Escape") { if (e.key === "Escape") {
e.preventDefault(); e.preventDefault();
@@ -236,7 +162,9 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
data-enable-grammarly="false" data-enable-grammarly="false"
/> />
{authError && ( {authError && (
<p className="text-xs text-red-500 dark:text-red-400">{authError}</p> <p className="text-xs text-red-500 dark:text-red-400">
{authError}
</p>
)} )}
<p className="text-xs text-gray-500 dark:text-gray-400"> <p className="text-xs text-gray-500 dark:text-gray-400">
Codex auth.json Codex auth.json
@@ -251,7 +179,7 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
> >
config.toml (TOML) config.toml (TOML)
</label> </label>
{/* 右侧对齐的双列布局 - 使用flex而非grid以更好控制宽度 */} {/* 右侧对齐的双列布局 - 使用flex而非grid以更好控制宽度 */}
<div className="flex gap-3"> <div className="flex gap-3">
{/* 左列VS Code 配置 */} {/* 左列VS Code 配置 */}
@@ -273,16 +201,13 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
</p> </p>
)} )}
{vscodeError && ( {vscodeError && (
<p <p className="text-xs text-red-500 dark:text-red-400 text-right truncate" title={vscodeError}>
className="text-xs text-red-500 dark:text-red-400 text-right truncate"
title={vscodeError}
>
{vscodeError} {vscodeError}
</p> </p>
)} )}
</div> </div>
</div> </div>
{/* 右列:通用配置 - 不设置宽度,让内容自然收缩 */} {/* 右列:通用配置 - 不设置宽度,让内容自然收缩 */}
<div className="flex flex-col items-end space-y-1"> <div className="flex flex-col items-end space-y-1">
<label className="inline-flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400 cursor-pointer"> <label className="inline-flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400 cursor-pointer">
@@ -302,17 +227,14 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
</button> </button>
{commonConfigError && !isCommonConfigModalOpen && ( {commonConfigError && !isCommonConfigModalOpen && (
<p <p className="text-xs text-red-500 dark:text-red-400 mt-1 max-w-[120px] truncate" title={commonConfigError}>
className="text-xs text-red-500 dark:text-red-400 mt-1 max-w-[120px] truncate"
title={commonConfigError}
>
{commonConfigError} {commonConfigError}
</p> </p>
)} )}
</div> </div>
</div> </div>
</div> </div>
<textarea <textarea
id="codexConfig" id="codexConfig"
value={configValue} value={configValue}
@@ -336,7 +258,7 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
</div> </div>
{isCommonConfigModalOpen && ( {isCommonConfigModalOpen && (
<div <div
className="fixed inset-0 z-50 flex items-center justify-center" className="fixed inset-0 z-50 flex items-center justify-center"
onMouseDown={(e) => { onMouseDown={(e) => {
if (e.target === e.currentTarget) closeModal(); if (e.target === e.currentTarget) closeModal();
@@ -344,7 +266,7 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
> >
{/* Backdrop - 统一背景样式 */} {/* Backdrop - 统一背景样式 */}
<div className="absolute inset-0 bg-black/50 dark:bg-black/70 backdrop-blur-sm" /> <div className="absolute inset-0 bg-black/50 dark:bg-black/70 backdrop-blur-sm" />
{/* Modal - 统一窗口样式 */} {/* Modal - 统一窗口样式 */}
<div className="relative bg-white dark:bg-gray-900 rounded-xl shadow-lg max-w-2xl w-full mx-4 max-h-[90vh] overflow-hidden flex flex-col"> <div className="relative bg-white dark:bg-gray-900 rounded-xl shadow-lg max-w-2xl w-full mx-4 max-h-[90vh] overflow-hidden flex flex-col">
{/* Header - 统一标题栏样式 */} {/* Header - 统一标题栏样式 */}
@@ -361,7 +283,7 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
<X size={18} /> <X size={18} />
</button> </button>
</div> </div>
{/* Content - 统一内容区域样式 */} {/* Content - 统一内容区域样式 */}
<div className="flex-1 overflow-auto p-6 space-y-4"> <div className="flex-1 overflow-auto p-6 space-y-4">
<p className="text-sm text-gray-500 dark:text-gray-400"> <p className="text-sm text-gray-500 dark:text-gray-400">
@@ -390,7 +312,7 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
</p> </p>
)} )}
</div> </div>
{/* Footer - 统一底部按钮样式 */} {/* Footer - 统一底部按钮样式 */}
<div className="flex items-center justify-end gap-3 p-6 border-t border-gray-200 dark:border-gray-800 bg-gray-100 dark:bg-gray-800"> <div className="flex items-center justify-end gap-3 p-6 border-t border-gray-200 dark:border-gray-800 bg-gray-100 dark:bg-gray-800">
<button <button

View File

@@ -35,4 +35,4 @@ export const extractErrorMessage = (error: unknown): string => {
} }
return ""; return "";
}; };

View File

@@ -22,10 +22,7 @@ const deepMerge = (
return target; return target;
}; };
const deepRemove = ( const deepRemove = (target: Record<string, any>, source: Record<string, any>) => {
target: Record<string, any>,
source: Record<string, any>,
) => {
Object.entries(source).forEach(([key, value]) => { Object.entries(source).forEach(([key, value]) => {
if (!(key in target)) return; if (!(key in target)) return;
@@ -62,7 +59,7 @@ const isSubset = (target: any, source: any): boolean => {
const deepClone = <T>(obj: T): T => { const deepClone = <T>(obj: T): T => {
if (obj === null || typeof obj !== "object") return obj; if (obj === null || typeof obj !== "object") return obj;
if (obj instanceof Date) return new Date(obj.getTime()) as T; if (obj instanceof Date) return new Date(obj.getTime()) as T;
if (obj instanceof Array) return obj.map((item) => deepClone(item)) as T; if (obj instanceof Array) return obj.map(item => deepClone(item)) as T;
if (obj instanceof Object) { if (obj instanceof Object) {
const clonedObj = {} as T; const clonedObj = {} as T;
for (const key in obj) { for (const key in obj) {
@@ -81,10 +78,7 @@ export interface UpdateCommonConfigResult {
} }
// 验证JSON配置格式 // 验证JSON配置格式
export const validateJsonConfig = ( export const validateJsonConfig = (value: string, fieldName: string = "配置"): string => {
value: string,
fieldName: string = "配置",
): string => {
if (!value.trim()) { if (!value.trim()) {
return ""; return "";
} }
@@ -129,7 +123,7 @@ export const updateCommonConfigSnippet = (
error: snippetError, error: snippetError,
}; };
} }
const snippet = JSON.parse(snippetString) as Record<string, any>; const snippet = JSON.parse(snippetString) as Record<string, any>;
if (enabled) { if (enabled) {
@@ -253,23 +247,23 @@ export const updateTomlCommonConfigSnippet = (
const removeTomlCommonConfig = (tomlString: string): string => { const removeTomlCommonConfig = (tomlString: string): string => {
const startIdx = tomlString.indexOf(COMMON_CONFIG_MARKER_START); const startIdx = tomlString.indexOf(COMMON_CONFIG_MARKER_START);
const endIdx = tomlString.indexOf(COMMON_CONFIG_MARKER_END); const endIdx = tomlString.indexOf(COMMON_CONFIG_MARKER_END);
if (startIdx === -1 || endIdx === -1) { if (startIdx === -1 || endIdx === -1) {
return tomlString; return tomlString;
} }
// 找到标记前的换行符(如果有) // 找到标记前的换行符(如果有)
let realStartIdx = startIdx; let realStartIdx = startIdx;
if (startIdx > 0 && tomlString[startIdx - 1] === "\n") { if (startIdx > 0 && tomlString[startIdx - 1] === '\n') {
realStartIdx = startIdx - 1; realStartIdx = startIdx - 1;
} }
// 找到标记后的换行符(如果有) // 找到标记后的换行符(如果有)
let realEndIdx = endIdx + COMMON_CONFIG_MARKER_END.length; let realEndIdx = endIdx + COMMON_CONFIG_MARKER_END.length;
if (realEndIdx < tomlString.length && tomlString[realEndIdx] === "\n") { if (realEndIdx < tomlString.length && tomlString[realEndIdx] === '\n') {
realEndIdx = realEndIdx + 1; realEndIdx = realEndIdx + 1;
} }
return tomlString.slice(0, realStartIdx) + tomlString.slice(realEndIdx); return tomlString.slice(0, realStartIdx) + tomlString.slice(realEndIdx);
}; };
@@ -279,19 +273,19 @@ export const hasTomlCommonConfigSnippet = (
snippetString: string, snippetString: string,
): boolean => { ): boolean => {
if (!snippetString.trim()) return false; if (!snippetString.trim()) return false;
const startIdx = tomlString.indexOf(COMMON_CONFIG_MARKER_START); const startIdx = tomlString.indexOf(COMMON_CONFIG_MARKER_START);
const endIdx = tomlString.indexOf(COMMON_CONFIG_MARKER_END); const endIdx = tomlString.indexOf(COMMON_CONFIG_MARKER_END);
if (startIdx === -1 || endIdx === -1 || startIdx >= endIdx) { if (startIdx === -1 || endIdx === -1 || startIdx >= endIdx) {
return false; return false;
} }
// 提取标记之间的内容 // 提取标记之间的内容
const existingSnippet = tomlString const existingSnippet = tomlString
.slice(startIdx + COMMON_CONFIG_MARKER_START.length, endIdx) .slice(startIdx + COMMON_CONFIG_MARKER_START.length, endIdx)
.trim(); .trim();
return existingSnippet === snippetString.trim(); return existingSnippet === snippetString.trim();
}; };