feat(filename): add parseFilename utility with full-pattern-only matching

Supports four patterns: date_lastname_firstname and lastname_firstname_date,
both with ISO (YYYY-MM-DD) and compact (YYYYMMDD) date formats.
Returns dateIso, personName and a formatted suggestedTitle.
Partial matches are rejected — unrecognised filenames return {}.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-03-26 15:17:16 +01:00
parent aab9e9a4b0
commit 8555193a79
2 changed files with 141 additions and 0 deletions

View File

@@ -0,0 +1,85 @@
import { describe, it, expect } from 'vitest';
import { parseFilename, stripExtension } from './filename';
describe('parseFilename', () => {
describe('YYYY-MM-DD_Lastname_Firstname pattern', () => {
it('extracts date and name', () => {
expect(parseFilename('1965-03-12_Mueller_Hans.pdf')).toEqual({
dateIso: '1965-03-12',
personName: 'Hans Mueller',
suggestedTitle: 'Hans Mueller (12.03.1965)'
});
});
it('handles umlauts in names', () => {
const result = parseFilename('2024-01-15_Müller_Jürgen.pdf');
expect(result.personName).toBe('Jürgen Müller');
});
});
describe('YYYYMMDD_Lastname_Firstname pattern', () => {
it('extracts date and name', () => {
expect(parseFilename('19650312_Mueller_Hans.pdf')).toEqual({
dateIso: '1965-03-12',
personName: 'Hans Mueller',
suggestedTitle: 'Hans Mueller (12.03.1965)'
});
});
});
describe('Lastname_Firstname_YYYY-MM-DD pattern', () => {
it('extracts date and name', () => {
expect(parseFilename('Mueller_Hans_1965-03-12.pdf')).toEqual({
dateIso: '1965-03-12',
personName: 'Hans Mueller',
suggestedTitle: 'Hans Mueller (12.03.1965)'
});
});
});
describe('Lastname_Firstname_YYYYMMDD pattern', () => {
it('extracts date and name', () => {
expect(parseFilename('Mueller_Hans_19650312.pdf')).toEqual({
dateIso: '1965-03-12',
personName: 'Hans Mueller',
suggestedTitle: 'Hans Mueller (12.03.1965)'
});
});
});
describe('non-matching filenames', () => {
it('returns empty for date-only filename', () => {
expect(parseFilename('1965-03-12.pdf')).toEqual({});
});
it('returns empty for name-only filename', () => {
expect(parseFilename('Mueller_Hans.pdf')).toEqual({});
});
it('returns empty for unstructured filename', () => {
expect(parseFilename('scan_001.pdf')).toEqual({});
});
it('returns empty for three name segments without date', () => {
expect(parseFilename('Mueller_Hans_Juergen.pdf')).toEqual({});
});
it('returns empty for filename without extension', () => {
expect(parseFilename('1965-03-12_Mueller_Hans')).toEqual({});
});
});
});
describe('stripExtension', () => {
it('removes the extension', () => {
expect(stripExtension('document.pdf')).toBe('document');
});
it('removes only the last extension', () => {
expect(stripExtension('archive.tar.gz')).toBe('archive.tar');
});
it('leaves names without extension unchanged', () => {
expect(stripExtension('nodotfile')).toBe('nodotfile');
});
});