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; } // A date token is either YYYY-MM-DD or YYYYMMDD with a plausible month/day range. function tryParseDate(s: string): string | undefined { if (/^\d{4}-\d{2}-\d{2}$/.test(s)) { const m = parseInt(s.slice(5, 7)); const d = parseInt(s.slice(8, 10)); if (m >= 1 && m <= 12 && d >= 1 && d <= 31) return s; } else if (/^\d{8}$/.test(s)) { const m = parseInt(s.slice(4, 6)); const d = parseInt(s.slice(6, 8)); if (m >= 1 && m <= 12 && d >= 1 && d <= 31) return `${s.slice(0, 4)}-${s.slice(4, 6)}-${s.slice(6, 8)}`; } return undefined; } const NAME_PART = /^\p{L}+$/u; /** * Parses a structured filename and extracts a date and person name. * * Supported conventions (date-first or date-last, compound last names supported): * YYYY-MM-DD_Lastname_Firstname.ext * YYYYMMDD_Lastname_Firstname.ext * YYYYMMDD_de_Gruyter_Walter.ext ← compound last name: lastName="de Gruyter" * Lastname_Firstname_YYYY-MM-DD.ext * Lastname_Firstname_YYYYMMDD.ext * de_Gruyter_Walter_YYYYMMDD.ext ← compound last name: lastName="de Gruyter" * * Algorithm: split on "_", identify the date token (first or last segment), * treat the outermost remaining segment as firstName, rest as lastName parts. * Returns {} for anything that doesn't match cleanly. */ export function parseFilename(filename: string): FilenameParseResult { const dot = filename.lastIndexOf('.'); if (dot < 0) return {}; // no extension — not a real file const stem = filename.slice(0, dot); const parts = stem.split('_'); // Minimum: date + at least one lastName segment + firstName = 3 parts if (parts.length < 3) return {}; let dateIso: string; let nameParts: string[]; const dateFromFirst = tryParseDate(parts[0]); if (dateFromFirst) { dateIso = dateFromFirst; nameParts = parts.slice(1); } else { const dateFromLast = tryParseDate(parts[parts.length - 1]); if (!dateFromLast) return {}; dateIso = dateFromLast; nameParts = parts.slice(0, -1); } // Need at least lastName + firstName after removing the date if (nameParts.length < 2) return {}; // All name segments must be pure letters (covers umlauts via \p{L}) if (!nameParts.every((p) => NAME_PART.test(p))) return {}; const firstName = nameParts[nameParts.length - 1]; const lastName = nameParts.slice(0, -1).join(' '); const personName = `${firstName} ${lastName}`; const suggestedTitle = `${personName} (${isoToGerman(dateIso)})`; return { dateIso, personName, suggestedTitle }; } export function stripExtension(filename: string): string { return filename.replace(/\.[^/.]+$/, ''); }