diff --git a/src/store.test.ts b/src/store.test.ts index 12d977d..31d5ce7 100644 --- a/src/store.test.ts +++ b/src/store.test.ts @@ -353,12 +353,16 @@ describe("handelize", () => { }); test("handles unicode characters", () => { - // Pure unicode with no alphanumerics throws error - expect(() => handelize("日本語.md")).toThrow("no valid filename content"); - // Mixed unicode/ascii preserves the ascii parts - expect(handelize("café-notes.md")).toBe("caf-notes.md"); - expect(handelize("naïve.md")).toBe("na-ve.md"); - expect(handelize("日本語-notes.md")).toBe("notes.md"); + // Pure unicode filenames are now supported (Unicode letters/numbers preserved) + expect(handelize("日本語.md")).toBe("日本語.md"); + expect(handelize("腾讯混元.md")).toBe("腾讯混元.md"); + expect(handelize("한국어.md")).toBe("한국어.md"); + // Mixed unicode/ascii preserves all letters + expect(handelize("café-notes.md")).toBe("café-notes.md"); + expect(handelize("naïve.md")).toBe("naïve.md"); + expect(handelize("日本語-notes.md")).toBe("日本語-notes.md"); + // Folder paths with unicode + expect(handelize("中文/文档.md")).toBe("中文/文档.md"); }); test("handles dates and times in filenames", () => { diff --git a/src/store.ts b/src/store.ts index ffc8bef..dfb81c7 100644 --- a/src/store.ts +++ b/src/store.ts @@ -603,11 +603,11 @@ export function handelize(path: string): string { } // Check for paths that are just extensions or only dots/special chars - // A valid path must have at least one alphanumeric character before processing + // A valid path must have at least one letter or number (including Unicode) before processing const segments = path.split('/').filter(Boolean); const lastSegment = segments[segments.length - 1] || ''; const filenameWithoutExt = lastSegment.replace(/\.[^.]+$/, ''); - const hasValidContent = /[a-zA-Z0-9]/.test(filenameWithoutExt); + const hasValidContent = /[\p{L}\p{N}]/u.test(filenameWithoutExt); if (!hasValidContent) { throw new Error(`handelize: path "${path}" has no valid filename content`); } @@ -626,14 +626,14 @@ export function handelize(path: string): string { const nameWithoutExt = ext ? segment.slice(0, -ext.length) : segment; const cleanedName = nameWithoutExt - .replace(/[\W_]+/g, '-') // Replace non-word chars with dash + .replace(/[^\p{L}\p{N}]+/gu, '-') // Replace non-letter/number chars with dash (Unicode-aware) .replace(/^-+|-+$/g, ''); // Remove leading/trailing dashes return cleanedName + ext; } else { // For directories, just clean normally return segment - .replace(/[\W_]+/g, '-') + .replace(/[^\p{L}\p{N}]+/gu, '-') // Unicode-aware .replace(/^-+|-+$/g, ''); } })