« get me outta code hell

hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/data/things/thing.js22
-rw-r--r--src/data/things/track.js186
2 files changed, 116 insertions, 92 deletions
diff --git a/src/data/things/thing.js b/src/data/things/thing.js
index 111de550..5d14b296 100644
--- a/src/data/things/thing.js
+++ b/src/data/things/thing.js
@@ -250,14 +250,7 @@ export default class Thing extends CacheableObject {
       expose: {
         dependencies: ['artistData', contribsByRefProperty],
         compute: ({artistData, [contribsByRefProperty]: contribsByRef}) =>
-          contribsByRef && artistData
-            ? contribsByRef
-                .map(({who: ref, what}) => ({
-                  who: find.artist(ref, artistData),
-                  what,
-                }))
-                .filter(({who}) => who)
-            : [],
+          Thing.findArtistsFromContribs(contribsByRef, artistData),
       },
     }),
 
@@ -563,5 +556,18 @@ export default class Thing extends CacheableObject {
 
       return constructedDescriptor;
     },
+
+    withDynamicContribs: (contribsByRefProperty, dependencyName) => ({
+      flags: {expose: true, compose: true},
+
+      expose: {
+        dependencies: ['artistData', contribsByRefProperty],
+        compute: ({artistData, [contribsByRefProperty]: contribsByRef}, callback) =>
+          callback({
+            [dependencyName]:
+              Thing.findArtistsFromContribs(contribsByRef, artistData),
+          }),
+      },
+    }),
   };
 }
diff --git a/src/data/things/track.js b/src/data/things/track.js
index fe6af205..8aa7ba26 100644
--- a/src/data/things/track.js
+++ b/src/data/things/track.js
@@ -44,6 +44,26 @@ export class Track extends Thing {
     sampledTracksByRef: Thing.common.referenceList(Track),
     artTagsByRef: Thing.common.referenceList(ArtTag),
 
+    color: Thing.composite.from([
+      {
+        flags: {expose: true, compose: true},
+        expose: {
+          transform: (color, {}, continuation) =>
+            color ?? continuation(),
+        },
+      },
+
+      Track.composite.withAlbumProperties(['color']),
+
+      {
+        flags: {update: true, expose: true},
+        update: {validate: isColor},
+        expose: {
+          compute: ({album: {color}}) => color,
+        },
+      },
+    ]),
+
     // Disables presenting the track as though it has its own unique artwork.
     // This flag should only be used in select circumstances, i.e. to override
     // an album's trackCoverArtists. This flag supercedes that property, as well
@@ -55,7 +75,7 @@ export class Track extends Thing {
     // main artwork. (It does inherit `trackCoverArtFileExtension` if present
     // on the album.)
     coverArtFileExtension: Thing.composite.from([
-      Track.withAlbumProperties(['trackCoverArtistContribsByRef', 'trackCoverArtFileExtension']),
+      Track.composite.withAlbumProperties(['trackCoverArtistContribsByRef', 'trackCoverArtFileExtension']),
 
       {
         flags: {update: true, expos: true},
@@ -81,7 +101,7 @@ export class Track extends Thing {
     // the track's own coverArtDate or its album's trackArtDate, so if neither
     // is specified, this value is null.
     coverArtDate: Thing.composite.from([
-      Track.withAlbumProperties(['trackArtDate', 'trackCoverArtistContribsByRef']),
+      Track.composite.withAlbumProperties(['trackArtDate', 'trackCoverArtistContribsByRef']),
 
       {
         flags: {update: true, expose: true},
@@ -147,31 +167,25 @@ export class Track extends Thing {
       find.album
     ),
 
-    date: {
-      flags: {expose: true},
-
-      expose: {
-        dependencies: ['albumData', 'dateFirstReleased'],
-        compute: ({albumData, dateFirstReleased, [Track.instance]: track}) =>
-          dateFirstReleased ?? Track.findAlbum(track, albumData)?.date ?? null,
+    date: Thing.composite.from([
+      {
+        flags: {expose: true, compose: true},
+        expose: {
+          dependencies: ['dateFirstReleased'],
+          compute: ({dateFirstReleased}, continuation) =>
+            dateFirstReleased ?? continuation(),
+        },
       },
-    },
 
-    color: {
-      flags: {update: true, expose: true},
-
-      update: {validate: isColor},
+      Track.composite.withAlbumProperties(['date']),
 
-      expose: {
-        dependencies: ['albumData'],
-
-        transform: (color, {albumData, [Track.instance]: track}) =>
-          color ??
-            Track.findAlbum(track, albumData)
-              ?.trackSections.find(({tracks}) => tracks.includes(track))
-                ?.color ?? null,
+      {
+        flags: {expose: true},
+        expose: {
+          compute: ({album: {date}}) => date,
+        },
       },
-    },
+    ]),
 
     // Whether or not the track has "unique" cover artwork - a cover which is
     // specifically associated with this track in particular, rather than with
@@ -181,7 +195,7 @@ export class Track extends Thing {
     // the usual hasCoverArt to emphasize that it does not inherit from the
     // album.)
     hasUniqueCoverArt: Thing.composite.from([
-      Track.withAlbumProperties(['trackCoverArtistContribsByRef']),
+      Track.composite.withAlbumProperties(['trackCoverArtistContribsByRef']),
 
       {
         flags: {expose: true},
@@ -236,29 +250,27 @@ export class Track extends Thing {
     },
 
     artistContribs: Thing.composite.from([
-      Track.inheritFromOriginalRelease('artistContribs'),
+      Track.composite.inheritFromOriginalRelease('artistContribs'),
+
+      Thing.composite.withDynamicContribs('artistContribsByRef', 'artistContribs'),
+      Track.composite.withAlbumProperties(['artistContribs']),
 
       {
         flags: {expose: true},
         expose: {
-          dependencies: ['artistContribs'],
-
-          compute({
-            artistContribsByRef: contribsFromTrack,
-            album: {artistContribsByRef: contribsFromAlbum},
-          }) {
-            let contribsByRef = contribsFromTrack;
-            if (empty(contribsByRef)) contribsByRef = contribsFromAlbum;
-            if (empty(contribsByRef)) return null;
-
-            return Thing.findArtistsFromContribs(contribsByRef, artistData);
-          },
+          compute: ({
+            artistContribs: contribsFromTrack,
+            album: {artistContribs: contribsFromAlbum},
+          }) =>
+            (empty(contribsFromTrack)
+              ? contribsFromAlbum
+              : contribsFromTrack),
         },
       },
     ]),
 
     contributorContribs: Thing.composite.from([
-      Track.inheritFromOriginalRelease('contributorContribs'),
+      Track.composite.inheritFromOriginalRelease('contributorContribs'),
       Thing.common.dynamicContribs('contributorContribsByRef'),
     ]),
 
@@ -266,37 +278,41 @@ export class Track extends Thing {
     // typically varies by release and isn't defined by the musical qualities
     // of the track.
     coverArtistContribs: Thing.composite.from([
-      Track.withAlbumProperties(['trackCoverArtistContribsByRef']),
-
       {
-        flags: {expose: true},
+        flags: {expose: true, compose: true},
         expose: {
-          dependencies: ['coverArtistContribsByRef', 'disableUniqueCoverArt'],
-
-          compute({
-            coverArtistContribsByRef: contribsFromTrack,
-            disableUniqueCoverArt,
-            album: {trackCoverArtistContribsByRef: contribsFromAlbum},
-          }) {
-            if (disableUniqueCoverArt) return null;
+          dependencies: ['disableUniqueCoverArt'],
+          compute: ({disableUniqueCoverArt}, continuation) =>
+            (disableUniqueCoverArt
+              ? null
+              : continuation()),
+        },
+      },
 
-            let contribsByRef = contribsFromTrack;
-            if (empty(contribsByRef)) contribsByRef = contribsFromAlbum;
-            if (empty(contribsByRef)) return null;
+      Track.composite.withAlbumProperties(['trackCoverArtistContribs']),
+      Thing.composite.withDynamicContribs('coverArtistContribsByRef', 'coverArtistContribs'),
 
-            return Thing.findArtistsFromContribs(contribsByRef, artistData);
-          },
+      {
+        flags: {expose: true},
+        expose: {
+          compute: ({
+            coverArtistContribs: contribsFromTrack,
+            album: {trackCoverArtistContribs: contribsFromAlbum},
+          }) =>
+            (empty(contribsFromTrack)
+              ? contribsFromAlbum
+              : contribsFromTrack),
         },
       },
     ]),
 
     referencedTracks: Thing.composite.from([
-      Track.inheritFromOriginalRelease('referencedTracks'),
+      Track.composite.inheritFromOriginalRelease('referencedTracks'),
       Thing.common.dynamicThingsFromReferenceList('referencedTracksByRef', 'trackData', find.track),
     ]),
 
     sampledTracks: Thing.composite.from([
-      Track.inheritFromOriginalRelease('sampledTracks'),
+      Track.composite.inheritFromOriginalRelease('sampledTracks'),
       Thing.common.dynamicThingsFromReferenceList('sampledTracksByRef', 'trackData', find.track),
     ]),
 
@@ -351,44 +367,46 @@ export class Track extends Thing {
     ),
   });
 
-  static inheritFromOriginalRelease = originalProperty => ({
-    flags: {expose: true, compose: true},
+  static composite = {
+    inheritFromOriginalRelease: originalProperty => ({
+      flags: {expose: true, compose: true},
 
-    expose: {
-      dependencies: ['originalReleaseTrackByRef', 'trackData'],
+      expose: {
+        dependencies: ['originalReleaseTrackByRef', 'trackData'],
 
-      compute({originalReleaseTrackByRef, trackData}, callback) {
-        if (!originalReleaseTrackByRef) return callback();
+        compute({originalReleaseTrackByRef, trackData}, continuation) {
+          if (!originalReleaseTrackByRef) return continuation();
 
-        if (!trackData) return null;
-        const original = find.track(originalReleaseTrackByRef, trackData, {mode: 'quiet'});
-        if (!original) return null;
-        return original[originalProperty];
+          if (!trackData) return null;
+          const original = find.track(originalReleaseTrackByRef, trackData, {mode: 'quiet'});
+          if (!original) return null;
+          return original[originalProperty];
+        },
       },
-    },
-  });
+    }),
 
-  static withAlbumProperties = albumProperties => ({
-    flags: {expose: true, compose: true},
+    withAlbumProperties: albumProperties => ({
+      flags: {expose: true, compose: true},
 
-    expose: {
-      dependencies: ['albumData'],
+      expose: {
+        dependencies: ['albumData'],
 
-      compute({albumData, [Track.instance]: track}, callback) {
-        const album = albumData?.find((album) => album.tracks.includes(track));
+        compute({albumData, [Track.instance]: track}, continuation) {
+          const album = albumData?.find((album) => album.tracks.includes(track));
 
-        const filteredAlbum = Object.create(null);
-        for (const property of albumProperties) {
-          filteredAlbum[property] =
-            (album
-              ? album[property]
-              : null);
-        }
+          const filteredAlbum = Object.create(null);
+          for (const property of albumProperties) {
+            filteredAlbum[property] =
+              (album
+                ? album[property]
+                : null);
+          }
 
-        return callback({album: filteredAlbum});
+          return continuation({album: filteredAlbum});
+        },
       },
-    },
-  });
+    }),
+  };
 
   [inspect.custom]() {
     const base = Thing.prototype[inspect.custom].apply(this);