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
This commit is contained in:
@@ -30,8 +30,10 @@ declares one.
|
|||||||
`dateTimeOriginal()`, `offsetTimeOriginal()`, `exposureTime()`, `fNumber()`,
|
`dateTimeOriginal()`, `offsetTimeOriginal()`, `exposureTime()`, `fNumber()`,
|
||||||
`iso()`, `focalLength()`, `orientation()`, `gpsLatitude()`, `gpsLongitude()`
|
`iso()`, `focalLength()`, `orientation()`, `gpsLatitude()`, `gpsLongitude()`
|
||||||
and `gpsAltitude()` (issue 148). Each calls `exif()` and returns its one
|
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
|
field, or undefined when the file lacks it. `Photo` implements a type with one
|
||||||
HEIC, that every field `exif()` returns has a method giving the same value.
|
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
|
- 2026-10-01: Each original's save path is
|
||||||
`YYYY/YYYY-MM/YYYY-MM-DD/YYYY-MM-DD.<fileID>.<ext>` under the library's
|
`YYYY/YYYY-MM/YYYY-MM-DD/YYYY-MM-DD.<fileID>.<ext>` under the library's
|
||||||
|
|||||||
+8
-1
@@ -42,11 +42,18 @@ const byNewest = (a: PhotoRecord, b: PhotoRecord): number =>
|
|||||||
const byNewestAlbum = (a: AlbumRecord, b: AlbumRecord): number =>
|
const byNewestAlbum = (a: AlbumRecord, b: AlbumRecord): number =>
|
||||||
b.updationTime - a.updationTime || b.collectionID - a.collectionID;
|
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<PhotoExif[K]>;
|
||||||
|
};
|
||||||
|
|
||||||
// A single photo. Field access mirrors `PhotoRecord`; `record()` returns the
|
// A single photo. Field access mirrors `PhotoRecord`; `record()` returns the
|
||||||
// underlying plain record for callers that need the IPC-safe value. `file` is
|
// 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
|
// 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.
|
// `takenAt` and stays known after a refresh removes the file from the library.
|
||||||
export class Photo {
|
export class Photo implements PhotoExifMethods {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly rec: PhotoRecord,
|
private readonly rec: PhotoRecord,
|
||||||
private readonly file: EnteFile,
|
private readonly file: EnteFile,
|
||||||
|
|||||||
@@ -686,6 +686,10 @@ describe("Photo save path, local copy, content and EXIF", () => {
|
|||||||
await lib.close();
|
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([
|
it.each([
|
||||||
["JPEG", JPEG_WITH_EXIF],
|
["JPEG", JPEG_WITH_EXIF],
|
||||||
["HEIC", HEIC_WITH_EXIF],
|
["HEIC", HEIC_WITH_EXIF],
|
||||||
|
|||||||
Reference in New Issue
Block a user