diff --git a/app/src/lib/url/legacy.ts b/app/src/lib/url/legacy.ts new file mode 100644 index 0000000..5e3cbd3 --- /dev/null +++ b/app/src/lib/url/legacy.ts @@ -0,0 +1,16 @@ +/** + * Erkennt Legacy-Hugo-URLs der Form /YYYY/MM/DD/.html oder .../.html/ + * und gibt den dtag-Teil zurück. Für alle anderen Pfade: null. + */ +export function parseLegacyUrl(path: string): string | null { + const match = path.match(/^\/\d{4}\/\d{2}\/\d{2}\/([^/]+?)\.html\/?$/); + if (!match) return null; + return decodeURIComponent(match[1]); +} + +/** + * Erzeugt die kanonische kurze Post-URL //. + */ +export function canonicalPostPath(dtag: string): string { + return `/${encodeURIComponent(dtag)}/`; +} diff --git a/app/tests/unit/legacy-url.test.ts b/app/tests/unit/legacy-url.test.ts new file mode 100644 index 0000000..a1fd8b3 --- /dev/null +++ b/app/tests/unit/legacy-url.test.ts @@ -0,0 +1,45 @@ +import { describe, expect, it } from 'vitest'; +import { parseLegacyUrl, canonicalPostPath } from '$lib/url/legacy'; + +describe('parseLegacyUrl', () => { + it('extrahiert dtag aus der Hugo-URL-Form mit Trailing-Slash', () => { + expect(parseLegacyUrl('/2025/03/04/dezentrale-oep-oer.html/')).toBe( + 'dezentrale-oep-oer', + ); + }); + + it('extrahiert dtag aus der Hugo-URL-Form ohne Trailing-Slash', () => { + expect(parseLegacyUrl('/2024/01/26/offenheit-das-wesentliche.html')).toBe( + 'offenheit-das-wesentliche', + ); + }); + + it('returned null für die kanonische kurze Form', () => { + expect(parseLegacyUrl('/dezentrale-oep-oer/')).toBeNull(); + }); + + it('returned null für leeren Pfad', () => { + expect(parseLegacyUrl('/')).toBeNull(); + }); + + it('returned null für andere Strukturen', () => { + expect(parseLegacyUrl('/tag/OER/')).toBeNull(); + expect(parseLegacyUrl('/some/random/path/')).toBeNull(); + }); + + it('decodiert percent-encoded dtags', () => { + expect(parseLegacyUrl('/2024/05/12/mit%20leerzeichen.html/')).toBe( + 'mit leerzeichen', + ); + }); +}); + +describe('canonicalPostPath', () => { + it('erzeugt // mit encodeURIComponent', () => { + expect(canonicalPostPath('dezentrale-oep-oer')).toBe('/dezentrale-oep-oer/'); + }); + + it('kodiert Sonderzeichen', () => { + expect(canonicalPostPath('mit leerzeichen')).toBe('/mit%20leerzeichen/'); + }); +});