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,56 @@
import { isoToGerman } from './date';
export interface FilenameParseResult {
/** ISO format: YYYY-MM-DD */
dateIso?: string;
/** "Firstname Lastname" — order reversed from filename convention */
personName?: string;
/** Ready-to-use title, e.g. "Hans Mueller (12.03.1965)" */
suggestedTitle?: string;
}
// Full-match patterns only. Name segments use Unicode letters (\p{L}) to cover umlauts etc.
// Order: date_lastname_firstname
const P_DATE_ISO_NAME = /^(\d{4}-\d{2}-\d{2})_(\p{L}+)_(\p{L}+)\.[^.]+$/u;
const P_DATE_COMPACT_NAME = /^(\d{8})_(\p{L}+)_(\p{L}+)\.[^.]+$/u;
// Order: lastname_firstname_date
const P_NAME_DATE_ISO = /^(\p{L}+)_(\p{L}+)_(\d{4}-\d{2}-\d{2})\.[^.]+$/u;
const P_NAME_DATE_COMPACT = /^(\p{L}+)_(\p{L}+)_(\d{8})\.[^.]+$/u;
function compactToIso(compact: string): string {
return `${compact.slice(0, 4)}-${compact.slice(4, 6)}-${compact.slice(6, 8)}`;
}
export function parseFilename(filename: string): FilenameParseResult {
let dateIso: string;
let lastName: string;
let firstName: string;
let m: RegExpMatchArray | null;
if ((m = P_DATE_ISO_NAME.exec(filename))) {
[, dateIso, lastName, firstName] = m;
} else if ((m = P_DATE_COMPACT_NAME.exec(filename))) {
dateIso = compactToIso(m[1]);
lastName = m[2];
firstName = m[3];
} else if ((m = P_NAME_DATE_ISO.exec(filename))) {
lastName = m[1];
firstName = m[2];
dateIso = m[3];
} else if ((m = P_NAME_DATE_COMPACT.exec(filename))) {
lastName = m[1];
firstName = m[2];
dateIso = compactToIso(m[3]);
} else {
return {};
}
const personName = `${firstName} ${lastName}`;
const suggestedTitle = `${personName} (${isoToGerman(dateIso!)})`;
return { dateIso: dateIso!, personName, suggestedTitle };
}
export function stripExtension(filename: string): string {
return filename.replace(/\.[^/.]+$/, '');
}