Files
ZenEcho b48e639490 feat: 引入共享类型与工具层,重构代码结构并优化用户体验
- 新增 `shared/` 目录,统一管理前后端共享的类型定义与工具函数,消除重复代码
- 重构 IPC 数据传输,使用 `toIpcSafeSnapshot` 确保序列化安全
- 新增系统托盘独立窗口 (`/tray` 路由) 与主窗口关闭行为设置,提升用户体验
- 优化 Sing-box 配置校验错误提示,增强可读性
- 修复订阅更新无新节点时的提示逻辑
- 更新项目依赖与构建配置,支持共享层路径别名 (`@shared`)
- 补充单元测试,完善国际化词条
2026-03-01 16:50:40 +08:00

68 lines
2.1 KiB
TypeScript

/**
* 标准化进程名称
*
* 去除路径前缀,只保留文件名,并去除首尾空格。
*
* @param processName - 原始进程名或路径
* @returns 标准化后的进程文件名 (如 'game.exe')
*/
export function normalizeProcessName(processName: string): string {
const raw = String(processName || '').trim()
if (!raw) return ''
const normalized = raw.replace(/\\/g, '/')
return (normalized.split('/').pop() || normalized).trim()
}
/**
* 标准化进程名列表
*
* 对列表中的每个进程名进行标准化,去重,
* 并同时保留小写版本以支持忽略大小写的匹配。
*
* @param processNames - 原始进程名列表
* @returns 处理后的去重进程名列表
*/
export function normalizeProcessNames(processNames: string[]): string[] {
const set = new Set<string>()
for (const item of processNames) {
const normalized = normalizeProcessName(item)
if (!normalized) continue
for (const alias of expandProcessAliases(normalized)) {
set.add(alias)
const lower = alias.toLowerCase()
if (lower !== alias) set.add(lower)
}
}
return Array.from(set)
}
/**
* 扩展进程名别名
*
* 例如输入 "chrome",自动扩展为 ["chrome", "chrome.exe"]
* 以容错用户输入时省略 .exe 后缀的情况。
*/
export function expandProcessAliases(processName: string): string[] {
const value = String(processName || '').trim()
if (!value) return []
const aliases = new Set<string>([value])
// Tolerate users entering "chrome" instead of "chrome.exe" on Windows.
if (!value.includes('.') && !value.includes('/') && !value.includes('\\')) {
aliases.add(`${value}.exe`)
}
return Array.from(aliases)
}
/**
* 比较两个字符串数组是否相等 (忽略顺序)
*/
export function areStringArraysEqual(a: unknown, b: unknown): boolean {
if (!Array.isArray(a) || !Array.isArray(b)) return false
if (a.length !== b.length) return false
const left = [...a].map(v => String(v)).sort()
const right = [...b].map(v => String(v)).sort()
return left.every((v, i) => v === right[i])
}