From 3ed43ca00f4d074b1b584e3ededf1095c7c4b4e6 Mon Sep 17 00:00:00 2001 From: Hampus Date: Sat, 15 Aug 2026 20:06:19 +0200 Subject: [PATCH] fix(schema): keep the extension when a filename has repeated dots (#1642) --- packages/schema/src/primitives/FileValidators.ts | 2 +- .../src/primitives/tests/FileValidators.test.ts | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/schema/src/primitives/FileValidators.ts b/packages/schema/src/primitives/FileValidators.ts index 38825b3d0..c54212474 100644 --- a/packages/schema/src/primitives/FileValidators.ts +++ b/packages/schema/src/primitives/FileValidators.ts @@ -59,7 +59,7 @@ export function normalizeFilename(value: string): string { let normalized = normalizeString(value); normalized = normalized.replaceAll(String.fromCharCode(0), ''); normalized = normalized.replace(/[/\\]/g, '_'); - normalized = normalized.replace(/\.{2,}/g, '_'); + normalized = normalized.replace(/\.{2,}/g, '.'); while (normalized.includes('..')) { normalized = normalized.replace(/\.\./g, '_'); } diff --git a/packages/schema/src/primitives/tests/FileValidators.test.ts b/packages/schema/src/primitives/tests/FileValidators.test.ts index 04d4aa82c..536d67e9a 100644 --- a/packages/schema/src/primitives/tests/FileValidators.test.ts +++ b/packages/schema/src/primitives/tests/FileValidators.test.ts @@ -38,11 +38,18 @@ describe('FilenameType', () => { expect(result.data).toBe('path_to_file.txt'); } }); - it('replaces double dots with underscores', () => { + it('collapses repeated dots into a single dot', () => { const result = FilenameType.safeParse('..file..txt'); expect(result.success).toBe(true); if (result.success) { - expect(result.data).not.toContain('..'); + expect(result.data).toBe('.file.txt'); + } + }); + it('keeps the extension when the name contains repeated dots', () => { + const result = FilenameType.safeParse('video..mp4'); + expect(result.success).toBe(true); + if (result.success) { + expect(result.data).toBe('video.mp4'); } }); it('handles Windows reserved names by prefixing', () => {