From 1ede66e5c0e9fec4a7dcd61dd0a03bf48f6a8ae5 Mon Sep 17 00:00:00 2001 From: sneak Date: Thu, 1 Oct 2026 21:11:05 +0000 Subject: [PATCH] Photo implements one method per PhotoExif field Photo now implements a mapped type with one method per PhotoExif field, each taking exif()'s options and giving that field's type, so the build's type check fails when PhotoExif has a field Photo has no method for, whatever the test fixtures hold. The test comment and TODO.md say so. Model: opus-5-5 --- TODO.md | 6 ++++-- src/library/read.ts | 9 ++++++++- test/library/content-library.test.ts | 4 ++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/TODO.md b/TODO.md index 6550ebd..3d1af8a 100644 --- a/TODO.md +++ b/TODO.md @@ -30,8 +30,10 @@ declares one. `dateTimeOriginal()`, `offsetTimeOriginal()`, `exposureTime()`, `fNumber()`, `iso()`, `focalLength()`, `orientation()`, `gpsLatitude()`, `gpsLongitude()` and `gpsAltitude()` (issue 148). Each calls `exif()` and returns its one - field, or undefined when the file lacks it. A test checks, on the JPEG and the - HEIC, that every field `exif()` returns has a method giving the same value. + field, or undefined when the file lacks it. `Photo` implements a type with one + method per `PhotoExif` field, so the build's type check fails when a field has + no method. A test checks, on the JPEG and the HEIC, that each method gives the + same value as `exif()`. - 2026-10-01: Each original's save path is `YYYY/YYYY-MM/YYYY-MM-DD/YYYY-MM-DD..` under the library's diff --git a/src/library/read.ts b/src/library/read.ts index 9ea594e..3aac9ce 100644 --- a/src/library/read.ts +++ b/src/library/read.ts @@ -42,11 +42,18 @@ const byNewest = (a: PhotoRecord, b: PhotoRecord): number => const byNewestAlbum = (a: AlbumRecord, b: AlbumRecord): number => b.updationTime - a.updationTime || b.collectionID - a.collectionID; +// A method for each `PhotoExif` field, named after it, taking the options +// `exif()` takes and giving that field. `Photo` implements it, so the build's +// type check fails when `PhotoExif` has a field `Photo` has no method for. +type PhotoExifMethods = { + [K in keyof PhotoExif]-?: (opts?: ContentOptions) => Promise; +}; + // A single photo. Field access mirrors `PhotoRecord`; `record()` returns the // underlying plain record for callers that need the IPC-safe value. `file` is // the membership the record is read from, so the save path carries the date of // `takenAt` and stays known after a refresh removes the file from the library. -export class Photo { +export class Photo implements PhotoExifMethods { constructor( private readonly rec: PhotoRecord, private readonly file: EnteFile, diff --git a/test/library/content-library.test.ts b/test/library/content-library.test.ts index cce917b..ffa0cc7 100644 --- a/test/library/content-library.test.ts +++ b/test/library/content-library.test.ts @@ -686,6 +686,10 @@ describe("Photo save path, local copy, content and EXIF", () => { await lib.close(); }); + // The build's type check, not this test, makes sure `Photo` has a method + // for every `PhotoExif` field, whatever the fixtures hold: `Photo` + // implements a type with one method per field. This test checks that each + // method gives the same value as exif(). it.each([ ["JPEG", JPEG_WITH_EXIF], ["HEIC", HEIC_WITH_EXIF],