spa(task 4 polish): decodeURIComponent crash-safe, edge-case-tests
- decodeURIComponent in try/catch (malformed URI encoding crasht den SPA-Boot-Path nicht mehr, returned stattdessen null). - JSDoc präzisiert: erwartet nur Pfad ohne Query/Fragment. - Neue Tests: malformed %E0 → null, leerer dtag → null, round-trip Legacy → canonical. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
47decd9b70
commit
36dd76a88f
|
|
@ -1,11 +1,19 @@
|
||||||
/**
|
/**
|
||||||
* Erkennt Legacy-Hugo-URLs der Form /YYYY/MM/DD/<dtag>.html oder .../<dtag>.html/
|
* Erkennt Legacy-Hugo-URLs der Form /YYYY/MM/DD/<dtag>.html oder .../<dtag>.html/
|
||||||
* und gibt den dtag-Teil zurück. Für alle anderen Pfade: null.
|
* und gibt den dtag-Teil zurück. Für alle anderen Pfade: null.
|
||||||
|
*
|
||||||
|
* Erwartet nur den Pfad ohne Query/Fragment — wenn vorhanden vom Aufrufer
|
||||||
|
* trennen. `decodeURIComponent` wird defensiv gekapselt, damit malformed
|
||||||
|
* Percent-Encoding die SPA beim Boot nicht crasht.
|
||||||
*/
|
*/
|
||||||
export function parseLegacyUrl(path: string): string | null {
|
export function parseLegacyUrl(path: string): string | null {
|
||||||
const match = path.match(/^\/\d{4}\/\d{2}\/\d{2}\/([^/]+?)\.html\/?$/);
|
const match = path.match(/^\/\d{4}\/\d{2}\/\d{2}\/([^/]+?)\.html\/?$/);
|
||||||
if (!match) return null;
|
if (!match) return null;
|
||||||
|
try {
|
||||||
return decodeURIComponent(match[1]);
|
return decodeURIComponent(match[1]);
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,14 @@ describe('parseLegacyUrl', () => {
|
||||||
'mit leerzeichen',
|
'mit leerzeichen',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('gibt null zurück bei malformed percent-encoding (crash-sicher)', () => {
|
||||||
|
expect(parseLegacyUrl('/2024/01/26/%E0.html/')).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('gibt null zurück für leeren dtag', () => {
|
||||||
|
expect(parseLegacyUrl('/2024/01/26/.html/')).toBeNull();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('canonicalPostPath', () => {
|
describe('canonicalPostPath', () => {
|
||||||
|
|
@ -43,3 +51,11 @@ describe('canonicalPostPath', () => {
|
||||||
expect(canonicalPostPath('mit leerzeichen')).toBe('/mit%20leerzeichen/');
|
expect(canonicalPostPath('mit leerzeichen')).toBe('/mit%20leerzeichen/');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('round-trip parseLegacyUrl → canonicalPostPath', () => {
|
||||||
|
it('Legacy-URL wird zur kanonischen kurzen Form', () => {
|
||||||
|
const dtag = parseLegacyUrl('/2025/03/04/dezentrale-oep-oer.html/');
|
||||||
|
expect(dtag).not.toBeNull();
|
||||||
|
expect(canonicalPostPath(dtag!)).toBe('/dezentrale-oep-oer/');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue