refactor: core 模块适配 PathEntry — path-manager、import-export 类型迁移

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-27 13:45:05 +08:00
parent ab2d0da20c
commit 611a36fb98
2 changed files with 34 additions and 30 deletions
+23 -21
View File
@@ -2,11 +2,13 @@
* 导入导出模块 — 对应 C 版 import_export.c * 导入导出模块 — 对应 C 版 import_export.c
* 支持 JSON、CSV、TXT 三种格式 * 支持 JSON、CSV、TXT 三种格式
*/ */
import type { PathEntry } from './path-entry';
export type ExportFormat = 'json' | 'csv' | 'txt'; export type ExportFormat = 'json' | 'csv' | 'txt';
export interface ExportData { export interface ExportData {
system: string[]; system: PathEntry[];
user: string[]; user: PathEntry[];
} }
/** 根据文件扩展名检测格式 */ /** 根据文件扩展名检测格式 */
@@ -24,8 +26,8 @@ export function exportToJson(data: ExportData): string {
version: '1.0', version: '1.0',
type: 'PathEditor', type: 'PathEditor',
exported: new Date().toISOString(), exported: new Date().toISOString(),
system: data.system, system: data.system.map(e => e.path),
user: data.user, user: data.user.map(e => e.path),
}; };
return JSON.stringify(obj, null, 2); return JSON.stringify(obj, null, 2);
} }
@@ -37,11 +39,11 @@ export function exportToCsv(data: ExportData): string {
// UTF-8 BOM // UTF-8 BOM
lines.push('type,path'); lines.push('type,path');
for (const path of data.system) { for (const entry of data.system) {
lines.push(`system,${escapeCsvField(path)}`); lines.push(`system,${escapeCsvField(entry.path)}`);
} }
for (const path of data.user) { for (const entry of data.user) {
lines.push(`user,${escapeCsvField(path)}`); lines.push(`user,${escapeCsvField(entry.path)}`);
} }
return lines.join('\n') + '\n'; return lines.join('\n') + '\n';
@@ -57,8 +59,8 @@ function escapeCsvField(field: string): string {
// ── CSV 导入 ── // ── CSV 导入 ──
export interface ImportResult { export interface ImportResult {
system: string[]; system: PathEntry[];
user: string[]; user: PathEntry[];
} }
export function importFromCsv(content: string): ImportResult { export function importFromCsv(content: string): ImportResult {
@@ -91,9 +93,9 @@ export function importFromCsv(content: string): ImportResult {
if (path.length === 0) continue; if (path.length === 0) continue;
if (type === 'system') { if (type === 'system') {
result.system.push(path); result.system.push({ path, enabled: true });
} else if (type === 'user') { } else if (type === 'user') {
result.user.push(path); result.user.push({ path, enabled: true });
} }
// 未知类型忽略 // 未知类型忽略
} }
@@ -157,14 +159,14 @@ export function importFromJson(content: string): ImportResult {
if (typeof obj !== 'object' || obj === null) return result; if (typeof obj !== 'object' || obj === null) return result;
if (Array.isArray(obj.system)) { if (Array.isArray(obj.system)) {
result.system = obj.system.filter( result.system = obj.system
(p: unknown) => typeof p === 'string' && p.trim().length > 0, .filter((p: unknown) => typeof p === 'string' && p.trim().length > 0)
); .map((p: string) => ({ path: p.trim(), enabled: true }));
} }
if (Array.isArray(obj.user)) { if (Array.isArray(obj.user)) {
result.user = obj.user.filter( result.user = obj.user
(p: unknown) => typeof p === 'string' && p.trim().length > 0, .filter((p: unknown) => typeof p === 'string' && p.trim().length > 0)
); .map((p: string) => ({ path: p.trim(), enabled: true }));
} }
return result; return result;
@@ -172,8 +174,8 @@ export function importFromJson(content: string): ImportResult {
// ── TXT 导入 ── // ── TXT 导入 ──
export function importFromTxt(content: string): string[] { export function importFromTxt(content: string): PathEntry[] {
const paths: string[] = []; const paths: PathEntry[] = [];
const lines = content.split(/\r?\n/); const lines = content.split(/\r?\n/);
for (let i = 0; i < lines.length; i++) { for (let i = 0; i < lines.length; i++) {
@@ -184,7 +186,7 @@ export function importFromTxt(content: string): string[] {
const trimmed = line.trim(); const trimmed = line.trim();
if (trimmed.length === 0 || trimmed.startsWith('#')) continue; if (trimmed.length === 0 || trimmed.startsWith('#')) continue;
paths.push(trimmed); paths.push({ path: trimmed, enabled: true });
} }
return paths; return paths;
+11 -9
View File
@@ -1,7 +1,9 @@
/** /**
* 路径管理器 — 不可变的 string[] 操作 * 路径管理器 — 不可变的 PathEntry[] 操作
*/ */
import type { PathEntry } from './path-entry';
export interface PathValidation { export interface PathValidation {
isValid: boolean; isValid: boolean;
isDuplicate: boolean; isDuplicate: boolean;
@@ -9,17 +11,17 @@ export interface PathValidation {
} }
export function analyzePaths( export function analyzePaths(
paths: readonly string[], paths: readonly PathEntry[],
validateFn: (path: string) => boolean, validateFn: (path: string) => boolean,
): PathValidation[] { ): PathValidation[] {
const result: PathValidation[] = []; const result: PathValidation[] = [];
const seen = new Set<string>(); const seen = new Set<string>();
for (const path of paths) { for (const entry of paths) {
const lower = path.toLowerCase(); const lower = entry.path.toLowerCase();
const isDuplicate = seen.has(lower); const isDuplicate = seen.has(lower);
seen.add(lower); seen.add(lower);
result.push({ isValid: validateFn(path), isDuplicate, isEnvVar: path.includes('%') }); result.push({ isValid: validateFn(entry.path), isDuplicate, isEnvVar: entry.path.includes('%') });
} }
return result; return result;
@@ -27,12 +29,12 @@ export function analyzePaths(
/** 从数组中移除无效和重复路径,返回 [新数组, 被移除的路径] */ /** 从数组中移除无效和重复路径,返回 [新数组, 被移除的路径] */
export function pathClean( export function pathClean(
paths: readonly string[], paths: readonly PathEntry[],
validateFn: (path: string) => boolean, validateFn: (path: string) => boolean,
): [string[], string[]] { ): [PathEntry[], PathEntry[]] {
const analysis = analyzePaths(paths, validateFn); const analysis = analyzePaths(paths, validateFn);
const kept: string[] = []; const kept: PathEntry[] = [];
const removed: string[] = []; const removed: PathEntry[] = [];
for (let i = 0; i < paths.length; i++) { for (let i = 0; i < paths.length; i++) {
const a = analysis[i]; const a = analysis[i];