Skip to content

Commit 0cc765d

Browse files
committed
Claude opus:improve:Rime-Wanxiang-Updater代码重构优化
1 parent 1b295e5 commit 0cc765d

14 files changed

Lines changed: 362 additions & 573 deletions

Rime-Wanxiang-Updater/components/HomeView.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
Path,
2020
} from "scripting"
2121

22-
import { loadConfig, saveConfig, type AppConfig, type ProSchemeKey } from "../utils/config"
22+
import { loadConfig, saveConfig, type AppConfig, type ProSchemeKey, PRO_KEYS } from "../utils/config"
2323
import { SettingsView } from "./SettingsView"
2424
import { loadMetaAsync, type MetaBundle } from "../utils/meta"
2525
import { detectRimeDir, verifyInstallPathAccess, collectRimeCandidates } from "../utils/hamster"
@@ -67,7 +67,7 @@ function pctFromFraction(f?: number) {
6767
return `${(v * 100).toFixed(2)}%`
6868
}
6969

70-
const PRO_KEYS: ProSchemeKey[] = ["moqi", "flypy", "zrm", "tiger", "wubi", "hanxin", "shouyou"]
70+
7171

7272
function selectedSchemeFromConfig(cfg: AppConfig): string {
7373
return cfg.schemeEdition === "base" ? "base" : `pro (${cfg.proSchemeKey})`

Rime-Wanxiang-Updater/components/SettingsView.tsx

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ import {
2525
type AppConfig,
2626
type ProSchemeKey,
2727
type InputMethod,
28+
PRO_KEYS,
2829
} from "../utils/config"
30+
import { callMaybeAsync, normalizePath } from "../utils/common"
2931
import { detectRimeDir, collectRimeCandidates } from "../utils/hamster"
3032
import { clearMetaForRoot, loadMetaAsync } from "../utils/meta"
3133
import { clearExtractedFilesForRoot } from "../utils/extracted_cache"
@@ -38,7 +40,7 @@ type AlertState = {
3840
actions: AlertNode
3941
}
4042

41-
const PRO_KEYS: ProSchemeKey[] = ["moqi", "flypy", "zrm", "tiger", "wubi", "hanxin", "shouyou"]
43+
4244
const INPUT_METHODS: { label: string; value: InputMethod }[] = [
4345
{ label: "仓输入法", value: "hamster" },
4446
{ label: "元书输入法", value: "hamster3" },
@@ -83,9 +85,7 @@ function normalizeInputMethodFromMeta(meta: any, detectedEngine: string): InputM
8385
return undefined
8486
}
8587

86-
function normalizePath(p: string): string {
87-
return String(p ?? "").trim().replace(/\/+$/, "")
88-
}
88+
8989

9090
async function collectMetaCandidatesAsync(base: AppConfig, detected?: string): Promise<string[]> {
9191
const out: string[] = []
@@ -103,18 +103,7 @@ async function collectMetaCandidatesAsync(base: AppConfig, detected?: string): P
103103
return Array.from(new Set(out))
104104
}
105105

106-
function isPromiseLike(v: any): v is Promise<any> {
107-
return !!v && typeof v === "object" && typeof v.then === "function"
108-
}
109106

110-
async function callMaybeAsync(fn: any, thisArg: any, args: any[]) {
111-
try {
112-
const r = fn.apply(thisArg, args)
113-
return isPromiseLike(r) ? await r : r
114-
} catch {
115-
return undefined
116-
}
117-
}
118107

119108
function CenterRowButton(props: {
120109
title: string
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
// File: utils/common.tsx
2+
// 公共工具函数,消除跨文件重复代码
3+
import { Runtime } from "./runtime"
4+
5+
// ===== 运行时访问 =====
6+
7+
export function FM(): any {
8+
return (globalThis as any).FileManager ?? Runtime.FileManager
9+
}
10+
11+
export function storage(): any {
12+
return (globalThis as any).Storage ?? Runtime.Storage
13+
}
14+
15+
// ===== 异步兼容 =====
16+
17+
export function sleep(ms: number) {
18+
return new Promise<void>((r) => setTimeout(r, ms))
19+
}
20+
21+
export async function callMaybeAsync(fn: any, thisArg: any, args: any[]) {
22+
try {
23+
const r = fn.apply(thisArg, args)
24+
if (r && typeof r === "object" && typeof r.then === "function") return await r
25+
return r
26+
} catch {
27+
return undefined
28+
}
29+
}
30+
31+
// ===== 路径工具 =====
32+
33+
export function normalizePath(p: string): string {
34+
return String(p ?? "").trim().replace(/\/+$/, "")
35+
}
36+
37+
export function basename(p: string): string {
38+
const x = String(p ?? "")
39+
const i = x.lastIndexOf("/")
40+
return i >= 0 ? x.slice(i + 1) : x
41+
}
42+
43+
export function dirname(p: string): string {
44+
const x = String(p ?? "")
45+
const i = x.lastIndexOf("/")
46+
if (i <= 0) return ""
47+
return x.slice(0, i)
48+
}
49+
50+
// ===== 文件操作兼容 =====
51+
52+
export async function removePathLoose(path: string) {
53+
const fm = FM()
54+
try {
55+
if (typeof fm?.removeSync === "function") {
56+
fm.removeSync(path)
57+
return
58+
}
59+
if (typeof fm?.remove === "function") {
60+
await fm.remove(path)
61+
return
62+
}
63+
if (typeof fm?.delete === "function") {
64+
await fm.delete(path)
65+
return
66+
}
67+
} catch { }
68+
}
69+
70+
export function tempDownloadPath(fileName: string): string {
71+
const fm = FM()
72+
const base = String(fm?.temporaryDirectory ?? "/tmp")
73+
const safeName = String(fileName ?? "asset.bin").replace(/[\\/]/g, "_")
74+
return `${base}/wanxiang_tmp_${Date.now()}_${safeName}`
75+
}
76+
77+
export async function getFileSize(fm: any, path: string): Promise<number> {
78+
if (typeof fm?.fileSizeSync === "function") return Number(fm.fileSizeSync(path) ?? 0)
79+
if (typeof fm?.fileSize === "function") return Number((await fm.fileSize(path)) ?? 0)
80+
if (typeof fm?.statSync === "function") return Number(fm.statSync(path)?.size ?? 0)
81+
if (typeof fm?.stat === "function") return Number((await fm.stat(path))?.size ?? 0)
82+
if (typeof fm?.attributesSync === "function") {
83+
const a = fm.attributesSync(path)
84+
return Number(a?.size ?? a?.fileSize ?? 0)
85+
}
86+
if (typeof fm?.attributes === "function") {
87+
const a = await fm.attributes(path)
88+
return Number(a?.size ?? a?.fileSize ?? 0)
89+
}
90+
throw new Error("无法获取文件大小(FileManager 缺少 fileSize/stat/attributes)")
91+
}
92+
93+
// ===== 模式匹配 =====
94+
95+
export function escapeRe(s: string) {
96+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
97+
}
98+
99+
export function compilePatterns(patterns: string[]): RegExp[] {
100+
const list: RegExp[] = []
101+
for (const raw of patterns ?? []) {
102+
const p = String(raw ?? "").trim()
103+
if (!p) continue
104+
try {
105+
list.push(new RegExp(p))
106+
continue
107+
} catch { }
108+
list.push(new RegExp("^" + p.split("*").map(escapeRe).join(".*") + "$", "i"))
109+
}
110+
return list
111+
}
112+
113+
export function matchAny(v: string, patterns: RegExp[]): boolean {
114+
for (const re of patterns) {
115+
if (re.test(v)) return true
116+
}
117+
return false
118+
}
119+
120+
// ===== GitHub/CNB 工具 =====
121+
122+
export function pickGithubSha256FromDigest(digest?: string): string | undefined {
123+
if (!digest) return undefined
124+
const m = String(digest).match(/sha256\s*:\s*([0-9a-fA-F]{32,})/i)
125+
return m?.[1]
126+
}
127+
128+
export function globToRegExp(glob: string): RegExp {
129+
const esc = glob.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")
130+
return new RegExp("^" + esc + "$", "i")
131+
}
132+
133+
export function pickExpectedSize(asset: any): number | undefined {
134+
const candidates = [
135+
asset?.size,
136+
asset?.fileSize,
137+
asset?.contentLength,
138+
asset?.bytes,
139+
asset?.asset?.size,
140+
asset?.asset?.fileSize,
141+
]
142+
for (const v of candidates) {
143+
const n = typeof v === "string" ? Number(v) : v
144+
if (typeof n === "number" && Number.isFinite(n) && n > 0) return n
145+
}
146+
return undefined
147+
}

Rime-Wanxiang-Updater/utils/config.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ export type SchemeEdition = "base" | "pro"
66
export type ProSchemeKey = "moqi" | "flypy" | "zrm" | "tiger" | "wubi" | "hanxin" | "shouyou"
77
export type InputMethod = "hamster" | "hamster3"
88

9+
export const PRO_KEYS: ProSchemeKey[] = ["moqi", "flypy", "zrm", "tiger", "wubi", "hanxin", "shouyou"]
10+
911
export type AppConfig = {
1012
hamsterRootPath: string
1113
hamsterBookmarkName: string

0 commit comments

Comments
 (0)