From c8d83f45ac49d352b4b1ef14a2181a450b9da079 Mon Sep 17 00:00:00 2001 From: Memory <134070804+Memory2314@users.noreply.github.com> Date: Sat, 6 Sep 2025 19:27:00 +0800 Subject: [PATCH] fix: short-id parsing error --- src/main/config/app.ts | 6 +++--- src/main/config/controledMihomo.ts | 6 +++--- src/main/config/override.ts | 6 +++--- src/main/config/profile.ts | 15 ++++++--------- src/main/core/factory.ts | 15 +++------------ src/main/resolve/autoUpdater.ts | 4 ++-- src/main/utils/init.ts | 4 ++-- src/main/utils/yaml.ts | 13 +++++++++++++ 8 files changed, 35 insertions(+), 34 deletions(-) create mode 100644 src/main/utils/yaml.ts diff --git a/src/main/config/app.ts b/src/main/config/app.ts index eacc1a2..c90216e 100644 --- a/src/main/config/app.ts +++ b/src/main/config/app.ts @@ -1,6 +1,6 @@ import { readFile, writeFile } from 'fs/promises' import { appConfigPath } from '../utils/dirs' -import yaml from 'yaml' +import { parse, stringify } from '../utils/yaml' import { deepMerge } from '../utils/merge' import { defaultConfig } from '../utils/template' @@ -9,7 +9,7 @@ let appConfig: IAppConfig // config.yaml export async function getAppConfig(force = false): Promise { if (force || !appConfig) { const data = await readFile(appConfigPath(), 'utf-8') - appConfig = yaml.parse(data, { merge: true }) || defaultConfig + appConfig = parse(data) || defaultConfig } if (typeof appConfig !== 'object') appConfig = defaultConfig return appConfig @@ -20,5 +20,5 @@ export async function patchAppConfig(patch: Partial): Promise appConfig.nameserverPolicy = patch.nameserverPolicy } appConfig = deepMerge(appConfig, patch) - await writeFile(appConfigPath(), yaml.stringify(appConfig)) + await writeFile(appConfigPath(), stringify(appConfig)) } diff --git a/src/main/config/controledMihomo.ts b/src/main/config/controledMihomo.ts index ecc29de..c44e195 100644 --- a/src/main/config/controledMihomo.ts +++ b/src/main/config/controledMihomo.ts @@ -1,6 +1,6 @@ import { controledMihomoConfigPath } from '../utils/dirs' import { readFile, writeFile } from 'fs/promises' -import yaml from 'yaml' +import { parse, stringify } from '../utils/yaml' import { generateProfile } from '../core/factory' import { getAppConfig } from './app' import { defaultControledMihomoConfig } from '../utils/template' @@ -11,7 +11,7 @@ let controledMihomoConfig: Partial // mihomo.yaml export async function getControledMihomoConfig(force = false): Promise> { if (force || !controledMihomoConfig) { const data = await readFile(controledMihomoConfigPath(), 'utf-8') - controledMihomoConfig = yaml.parse(data, { merge: true }) || defaultControledMihomoConfig + controledMihomoConfig = parse(data) || defaultControledMihomoConfig // 确保配置包含所有必要的默认字段,处理升级场景 controledMihomoConfig = deepMerge(defaultControledMihomoConfig, controledMihomoConfig) @@ -46,5 +46,5 @@ export async function patchControledMihomoConfig(patch: Partial): } await generateProfile() - await writeFile(controledMihomoConfigPath(), yaml.stringify(controledMihomoConfig), 'utf-8') + await writeFile(controledMihomoConfigPath(), stringify(controledMihomoConfig), 'utf-8') } diff --git a/src/main/config/override.ts b/src/main/config/override.ts index 0b9fee0..dd20ea6 100644 --- a/src/main/config/override.ts +++ b/src/main/config/override.ts @@ -3,14 +3,14 @@ import { getControledMihomoConfig } from './controledMihomo' import { readFile, writeFile, rm } from 'fs/promises' import { existsSync } from 'fs' import axios from 'axios' -import yaml from 'yaml' +import { parse, stringify } from '../utils/yaml' let overrideConfig: IOverrideConfig // override.yaml export async function getOverrideConfig(force = false): Promise { if (force || !overrideConfig) { const data = await readFile(overrideConfigPath(), 'utf-8') - overrideConfig = yaml.parse(data, { merge: true }) || { items: [] } + overrideConfig = parse(data) || { items: [] } } if (typeof overrideConfig !== 'object') overrideConfig = { items: [] } return overrideConfig @@ -18,7 +18,7 @@ export async function getOverrideConfig(force = false): Promise export async function setOverrideConfig(config: IOverrideConfig): Promise { overrideConfig = config - await writeFile(overrideConfigPath(), yaml.stringify(overrideConfig), 'utf-8') + await writeFile(overrideConfigPath(), stringify(overrideConfig), 'utf-8') } export async function getOverrideItem(id: string | undefined): Promise { diff --git a/src/main/config/profile.ts b/src/main/config/profile.ts index 10f4be4..b3ae1f9 100644 --- a/src/main/config/profile.ts +++ b/src/main/config/profile.ts @@ -6,7 +6,7 @@ import { restartCore } from '../core/manager' import { getAppConfig } from './app' import { existsSync } from 'fs' import axios, { AxiosResponse } from 'axios' -import yaml from 'yaml' +import { parse, stringify } from '../utils/yaml' import { defaultProfile } from '../utils/template' import { subStorePort } from '../resolve/server' import { join } from 'path' @@ -17,7 +17,7 @@ let profileConfig: IProfileConfig // profile.yaml export async function getProfileConfig(force = false): Promise { if (force || !profileConfig) { const data = await readFile(profileConfigPath(), 'utf-8') - profileConfig = yaml.parse(data, { merge: true }) || { items: [] } + profileConfig = parse(data) || { items: [] } } if (typeof profileConfig !== 'object') profileConfig = { items: [] } return profileConfig @@ -25,7 +25,7 @@ export async function getProfileConfig(force = false): Promise { export async function setProfileConfig(config: IProfileConfig): Promise { profileConfig = config - await writeFile(profileConfigPath(), yaml.stringify(config), 'utf-8') + await writeFile(profileConfigPath(), stringify(config), 'utf-8') } export async function getProfileItem(id: string | undefined): Promise { @@ -198,7 +198,7 @@ export async function getProfileStr(id: string | undefined): Promise { if (existsSync(profilePath(id || 'default'))) { return await readFile(profilePath(id || 'default'), 'utf-8') } else { - return yaml.stringify(defaultProfile) + return stringify(defaultProfile) } } @@ -210,12 +210,9 @@ export async function setProfileStr(id: string, content: string): Promise export async function getProfile(id: string | undefined): Promise { const profile = await getProfileStr(id) - - // 替换 防止错误使用科学记数法解析 - const patchedProfile = profile.replace(/(\w+:\s*)(\d+E\d+)(\s|$)/gi, '$1"$2"$3') - let result = yaml.parse(patchedProfile, { merge: true }) || {} + let result = parse(profile) if (typeof result !== 'object') result = {} - return result + return result as IMihomoConfig } // attachment;filename=xxx.yaml; filename*=UTF-8''%xx%xx%xx diff --git a/src/main/core/factory.ts b/src/main/core/factory.ts index a5bb90c..1971a2e 100644 --- a/src/main/core/factory.ts +++ b/src/main/core/factory.ts @@ -14,7 +14,7 @@ import { mihomoWorkDir, overridePath } from '../utils/dirs' -import yaml from 'yaml' +import { parse, stringify } from '../utils/yaml' import { copyFile, mkdir, writeFile } from 'fs/promises' import { deepMerge } from '../utils/merge' import vm from 'vm' @@ -50,16 +50,7 @@ export async function generateProfile(): Promise { profile['log-level'] = 'info' } runtimeConfig = profile - - // 先正常生成 YAML 字符串 - let yamlStr = yaml.stringify(profile) - // 还原科学记数法的引号 - yamlStr = yamlStr.replace( - /(\w+:\s*)"(\d+E\d+)"(\s|$)/gi, - '$1$2$3' - ) - runtimeConfigStr = yamlStr - + runtimeConfigStr = stringify(profile) if (diffWorkDir) { await prepareProfileWorkDir(current) } @@ -104,7 +95,7 @@ async function overrideProfile( profile = runOverrideScript(profile, content, item) break case 'yaml': { - let patch = yaml.parse(content, { merge: true }) || {} + let patch = parse(content) || {} if (typeof patch !== 'object') patch = {} profile = deepMerge(profile, patch) break diff --git a/src/main/resolve/autoUpdater.ts b/src/main/resolve/autoUpdater.ts index 2b8d7fc..f9c3ba6 100644 --- a/src/main/resolve/autoUpdater.ts +++ b/src/main/resolve/autoUpdater.ts @@ -1,5 +1,5 @@ import axios from 'axios' -import yaml from 'yaml' +import { parse } from '../utils/yaml' import { app, shell } from 'electron' import { getControledMihomoConfig } from '../config' import { dataDir, exeDir, exePath, isPortable, resourcesFilesDir } from '../utils/dirs' @@ -26,7 +26,7 @@ export async function checkUpdate(): Promise { responseType: 'text' } ) - const latest = yaml.parse(res.data, { merge: true }) as IAppVersion + const latest = parse(res.data) as IAppVersion const currentVersion = app.getVersion() if (compareVersions(latest.version, currentVersion) > 0) { return latest diff --git a/src/main/utils/init.ts b/src/main/utils/init.ts index 3f6661c..6f5b739 100644 --- a/src/main/utils/init.ts +++ b/src/main/utils/init.ts @@ -21,7 +21,7 @@ import { defaultProfile, defaultProfileConfig } from './template' -import yaml from 'yaml' +import { stringify } from './yaml' import { mkdir, writeFile, rm, readdir, cp, stat, rename } from 'fs/promises' import { existsSync } from 'fs' import { exec } from 'child_process' @@ -134,7 +134,7 @@ async function initConfig(): Promise { for (const config of configs) { try { if (!existsSync(config.path)) { - await writeFile(config.path, yaml.stringify(config.content)) + await writeFile(config.path, stringify(config.content)) } } catch (error) { await initLogger.error(`Failed to create ${config.name} at ${config.path}`, error) diff --git a/src/main/utils/yaml.ts b/src/main/utils/yaml.ts new file mode 100644 index 0000000..039b1d7 --- /dev/null +++ b/src/main/utils/yaml.ts @@ -0,0 +1,13 @@ +import yaml from 'yaml' + +export const parse = (content: string): T => { + const processedContent = content.replace( + /(^|\{|,)(\s*short-id:\s*)(?!['"]|null\b|Null\b|NULL\b|~)([^"'\s,}\n]+)/gm, + '$1$2"$3"' + ) + return (yaml.parse(processedContent, { merge: true }) as T) || ({} as T) +} + +export function stringify(content: unknown): string { + return yaml.stringify(content) +} \ No newline at end of file