mirror of
https://github.com/LHY0125/PathEditor.git
synced 2026-06-29 01:45:54 +08:00
refactor: core 模块适配 PathEntry — path-manager、import-export 类型迁移
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+23
-21
@@ -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;
|
||||||
|
|||||||
@@ -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];
|
||||||
|
|||||||
Reference in New Issue
Block a user