mirror of
https://github.com/LHY0125/PathEditor.git
synced 2026-06-29 18:15:55 +08:00
chore: 同步 v5.0 基础设施完善到 v5.1
从 v5.0 cherry-pick 的开源项目基础设施改进: 新增配置文件: - .editorconfig, .gitattributes, .prettierrc, .markdownlint.json - commitlint.config.js 新增 GitHub 社区文件: - .github/dependabot.yml — 依赖自动更新 - .github/CODEOWNERS — 自动 PR 审查分配 - .github/FUNDING.yml — 开源赞助入口 新增文档: - ROADMAP.md — 路线图 - SUPPORT.md — 帮助指南 - docs/screenshots/ — 应用截图 新增 Git Hooks: - .husky/pre-commit — lint-staged 自动格式化+修复 - .husky/commit-msg — commitlint 校验 CI 强化: - 新增 Prettier 格式检查 - 新增 Vitest 覆盖率 + Codecov 上报 - 保留 v5.1 已有的 rust-cache + jsdom 全局环境 修复: - index.html 标题 v4.0 → v5.1 - PathEditDialog set-state-in-effect 改用 useRef prevOpen 守卫 - merge-preview.test.tsx no-explicit-any 修复 - 所有 TS/TSX 文件 Prettier 格式化统一 v5.1 保留特性: - @tanstack/react-virtual 虚拟滚动 - jsdom 全局测试环境 - Swatinem/rust-cache CI 加速 - 105 测试全部通过
This commit is contained in:
@@ -28,8 +28,8 @@ export function exportToJson(data: ExportData): string {
|
||||
const obj = {
|
||||
version,
|
||||
timestamp: new Date().toISOString(),
|
||||
system: data.system.map(e => ({ path: e.path, enabled: e.enabled })),
|
||||
user: data.user.map(e => ({ path: e.path, enabled: e.enabled })),
|
||||
system: data.system.map((e) => ({ path: e.path, enabled: e.enabled })),
|
||||
user: data.user.map((e) => ({ path: e.path, enabled: e.enabled })),
|
||||
};
|
||||
return JSON.stringify(obj, null, 2);
|
||||
}
|
||||
@@ -179,10 +179,14 @@ export function importFromJson(content: string): ImportResult {
|
||||
};
|
||||
|
||||
if (Array.isArray(obj.system)) {
|
||||
result.system = obj.system.map(parseEntry).filter((e): e is { path: string; enabled: boolean } => e !== null);
|
||||
result.system = obj.system
|
||||
.map(parseEntry)
|
||||
.filter((e): e is { path: string; enabled: boolean } => e !== null);
|
||||
}
|
||||
if (Array.isArray(obj.user)) {
|
||||
result.user = obj.user.map(parseEntry).filter((e): e is { path: string; enabled: boolean } => e !== null);
|
||||
result.user = obj.user
|
||||
.map(parseEntry)
|
||||
.filter((e): e is { path: string; enabled: boolean } => e !== null);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -210,10 +214,7 @@ export function importFromTxt(content: string): PathEntry[] {
|
||||
|
||||
// ── 自动检测导入 ──
|
||||
|
||||
export function importFromContent(
|
||||
content: string,
|
||||
filepath: string,
|
||||
): ImportResult {
|
||||
export function importFromContent(content: string, filepath: string): ImportResult {
|
||||
const lower = filepath.toLowerCase();
|
||||
if (lower.endsWith('.csv')) {
|
||||
return importFromCsv(content);
|
||||
|
||||
@@ -21,7 +21,11 @@ export function analyzePaths(
|
||||
const lower = entry.path.toLowerCase();
|
||||
const isDuplicate = seen.has(lower);
|
||||
seen.add(lower);
|
||||
result.push({ isValid: validateFn(entry.path), isDuplicate, isEnvVar: entry.path.includes('%') });
|
||||
result.push({
|
||||
isValid: validateFn(entry.path),
|
||||
isDuplicate,
|
||||
isEnvVar: entry.path.includes('%'),
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
+31
-7
@@ -5,7 +5,16 @@
|
||||
import type { PathEntry } from './path-entry';
|
||||
|
||||
export const OperationType = {
|
||||
ADD: 0, DELETE: 1, EDIT: 2, MOVE_UP: 3, MOVE_DOWN: 4, CLEAN: 5, CLEAR: 6, IMPORT: 7, TOGGLE: 8, IMPORT_BOTH: 9,
|
||||
ADD: 0,
|
||||
DELETE: 1,
|
||||
EDIT: 2,
|
||||
MOVE_UP: 3,
|
||||
MOVE_DOWN: 4,
|
||||
CLEAN: 5,
|
||||
CLEAR: 6,
|
||||
IMPORT: 7,
|
||||
TOGGLE: 8,
|
||||
IMPORT_BOTH: 9,
|
||||
} as const;
|
||||
export type OperationType = (typeof OperationType)[keyof typeof OperationType];
|
||||
|
||||
@@ -47,7 +56,10 @@ export class UndoRedoManager {
|
||||
this.current = this.records.length - 1;
|
||||
}
|
||||
|
||||
undo(sysPaths: readonly PathEntry[], userPaths: readonly PathEntry[]): [PathEntry[], PathEntry[]] | null {
|
||||
undo(
|
||||
sysPaths: readonly PathEntry[],
|
||||
userPaths: readonly PathEntry[],
|
||||
): [PathEntry[], PathEntry[]] | null {
|
||||
if (this.current < 0) return null;
|
||||
|
||||
const rec = this.records[this.current];
|
||||
@@ -103,7 +115,10 @@ export class UndoRedoManager {
|
||||
return [sys, user];
|
||||
}
|
||||
|
||||
redo(sysPaths: readonly PathEntry[], userPaths: readonly PathEntry[]): [PathEntry[], PathEntry[]] | null {
|
||||
redo(
|
||||
sysPaths: readonly PathEntry[],
|
||||
userPaths: readonly PathEntry[],
|
||||
): [PathEntry[], PathEntry[]] | null {
|
||||
if (this.current >= this.records.length - 1) return null;
|
||||
|
||||
this.current++;
|
||||
@@ -159,8 +174,17 @@ export class UndoRedoManager {
|
||||
return [sys, user];
|
||||
}
|
||||
|
||||
canUndo(): boolean { return this.current >= 0; }
|
||||
canRedo(): boolean { return this.current < this.records.length - 1; }
|
||||
clear(): void { this.records = []; this.current = -1; }
|
||||
get historyLength(): number { return this.records.length; }
|
||||
canUndo(): boolean {
|
||||
return this.current >= 0;
|
||||
}
|
||||
canRedo(): boolean {
|
||||
return this.current < this.records.length - 1;
|
||||
}
|
||||
clear(): void {
|
||||
this.records = [];
|
||||
this.current = -1;
|
||||
}
|
||||
get historyLength(): number {
|
||||
return this.records.length;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user