« 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--.eslintrc.json1
-rw-r--r--src/content/dependencies/generateArtistInfoPage.js297
-rw-r--r--src/content/dependencies/generateArtistInfoPageChunk.js44
-rw-r--r--src/content/dependencies/generateArtistInfoPageChunkItem.js50
-rw-r--r--src/content/dependencies/generateArtistInfoPageOtherArtistLinks.js23
-rw-r--r--src/content/dependencies/generateArtistInfoPageTracksChunkedList.js187
6 files changed, 416 insertions, 186 deletions
diff --git a/.eslintrc.json b/.eslintrc.json
index f104d38..6367ba7 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -10,6 +10,7 @@
   },
   "rules": {
     "indent": ["off"],
+    "no-unused-labels": ["off"],
     "no-unused-vars": ["error", {
       "argsIgnorePattern": "^_",
       "destructuredArrayIgnorePattern": "^"
diff --git a/src/content/dependencies/generateArtistInfoPage.js b/src/content/dependencies/generateArtistInfoPage.js
index 888da2f..19cc261 100644
--- a/src/content/dependencies/generateArtistInfoPage.js
+++ b/src/content/dependencies/generateArtistInfoPage.js
@@ -1,14 +1,9 @@
-import {empty, filterProperties, unique} from '../../util/sugar.js';
-
-import {
-  chunkByProperties,
-  getTotalDuration,
-  sortAlbumsTracksChronologically,
-  sortFlashesChronologically,
-} from '../../util/wiki-data.js';
+import {empty, unique} from '../../util/sugar.js';
+import {getTotalDuration} from '../../util/wiki-data.js';
 
 export default {
   contentDependencies: [
+    'generateArtistInfoPageTracksChunkedList',
     'generateArtistNavLinks',
     'generateContentHeading',
     'generateCoverArtwork',
@@ -41,61 +36,7 @@ export default {
     relations.artistNavLinks =
       relation('generateArtistNavLinks', artist);
 
-    function getContributionDescriptions(...contribArrays) {
-      const ownContribs =
-        contribArrays
-          .map(contribs => contribs.find(({who}) => who === artist))
-          .filter(Boolean);
-
-      const contributionDescriptions =
-        ownContribs
-          .map(({what}) => what)
-          .filter(Boolean);
-
-      if (empty(contributionDescriptions)) {
-        return {};
-      }
-
-      return {contributionDescriptions};
-    }
-
-    function getOtherArtistLinks(...contribArrays) {
-      const otherArtistContribs =
-        contribArrays
-          .map(contribs => contribs.filter(({who}) => who !== artist))
-          .flat();
-
-      if (empty(otherArtistContribs)) {
-        return {};
-      }
-
-      const otherArtistLinks =
-        otherArtistContribs
-          .map(({who}) => relation('linkArtist', who));
-
-      return {otherArtistLinks};
-    }
-
-    function sortContributionEntries(entries, sortFunction) {
-      const things = unique(entries.map(({thing}) => thing));
-      sortFunction(things);
-
-      const outputArrays = [];
-      const thingToOutputArray = new Map();
-
-      for (const thing of things) {
-        const array = [];
-        thingToOutputArray.set(thing, array);
-        outputArrays.push(array);
-      }
-
-      for (const entry of entries) {
-        thingToOutputArray.get(entry.thing).push(entry);
-      }
-
-      entries.splice(0, entries.length, ...outputArrays.flat());
-    }
-
+    /*
     function getGroupInfo(entries) {
       const allGroups = new Set();
       const groupToDuration = new Map();
@@ -122,6 +63,7 @@ export default {
 
       return groupInfo;
     }
+    */
 
     if (artist.hasAvatar) {
       relations.cover =
@@ -140,50 +82,25 @@ export default {
           relation('linkExternal', url));
     }
 
-    const trackContributionEntries = [
-      ...artist.tracksAsArtist.map(track => ({
-        date: track.date,
-        thing: track,
-        album: track.album,
-        duration: track.duration,
-        rerelease: track.originalReleaseTrack !== null,
-        trackLink: relation('linkTrack', track),
-        ...getContributionDescriptions(track.artistContribs),
-        ...getOtherArtistLinks(track.artistContribs),
-      })),
-
-      ...artist.tracksAsContributor.map(track => ({
-        date: track.date,
-        thing: track,
-        album: track.album,
-        duration: track.duration,
-        rerelease: track.originalReleaseTrack !== null,
-        trackLink: relation('linkTrack', track),
-        ...getContributionDescriptions(track.contributorContribs),
-        ...getOtherArtistLinks(track.contributorContribs),
-      })),
-    ];
-
-    sortContributionEntries(trackContributionEntries, sortAlbumsTracksChronologically);
+    if (!empty(artist.tracksAsArtist) || !empty(artist.tracksAsContributor)) {
+      const tracks = sections.tracks = {};
+      tracks.heading = relation('generateContentHeading');
+      tracks.list = relation('generateArtistInfoPageTracksChunkedList', artist);
+    }
 
+    /*
     const trackContributionChunks =
-      chunkByProperties(trackContributionEntries, ['album', 'date'])
-        .map(({album, date, chunk}) => ({
-          albumLink: relation('linkAlbum', album),
-          date: +date,
-          duration: getTotalDuration(chunk),
-          entries: chunk
-            .map(entry =>
-              filterProperties(entry, [
-                'contributionDescriptions',
-                'duration',
-                'otherArtistLinks',
-                'rerelease',
-                'trackLink',
-              ])),
-        }));
-
-    const trackGroupInfo = getGroupInfo(trackContributionEntries, 'duration');
+      query.trackContributionChunks.map(({album, chunk}) => ({
+        albumLink: relation('linkAlbum', album),
+        entries:
+          chunk.map(entry => ({
+            // ...getContributionDescription(entry.contribs),
+            ...getOtherArtistLinks(entry.contribs),
+            trackLink: relation('linkTrack', entry.track),
+          })),
+      }));
+
+    const trackGroupInfo = getGroupInfo(query.trackContributionEntries, 'duration');
 
     if (!empty(trackContributionChunks)) {
       const tracks = sections.tracks = {};
@@ -202,7 +119,7 @@ export default {
         date: album.coverArtDate,
         thing: album,
         album: album,
-        ...getContributionDescriptions(album.coverArtistContribs),
+        // ...getContributionDescription(album.coverArtistContribs),
         ...getOtherArtistLinks(album.coverArtistContribs),
       })),
 
@@ -211,7 +128,7 @@ export default {
         date: album.coverArtDate,
         thing: album,
         album: album,
-        ...getContributionDescriptions(album.wallpaperArtistContribs),
+        // ...getContributionDescription(album.wallpaperArtistContribs),
         ...getOtherArtistLinks(album.wallpaperArtistContribs),
       })),
 
@@ -220,7 +137,7 @@ export default {
         date: album.coverArtDate,
         thing: album,
         album: album,
-        ...getContributionDescriptions(album.bannerArtistContribs),
+        // ...getContributionDescription(album.bannerArtistContribs),
         ...getOtherArtistLinks(album.bannerArtistContribs),
       })),
 
@@ -231,7 +148,7 @@ export default {
         album: track.album,
         rerelease: track.originalReleaseTrack !== null,
         trackLink: relation('linkTrack', track),
-        ...getContributionDescriptions(track.coverArtistContribs),
+        // ...getContributionDescription(track.coverArtistContribs),
         ...getOtherArtistLinks(track.coverArtistContribs),
       })),
     ];
@@ -246,7 +163,7 @@ export default {
           entries:
             chunk.map(entry =>
               filterProperties(entry, [
-                'contributionDescriptions',
+                'contributionDescription',
                 'kind',
                 'otherArtistLinks',
                 'rerelease',
@@ -287,7 +204,7 @@ export default {
           thing: flash,
           act: flash.act,
           flashLink: relation('linkFlash', flash),
-          ...getContributionDescriptions(flash.contributorContribs),
+          // ...getContributionDescription(flash.contributorContribs),
         })),
       ];
 
@@ -303,7 +220,7 @@ export default {
             entries:
               chunk.map(entry =>
                 filterProperties(entry, [
-                  'contributionDescriptions',
+                  'contributionDescription',
                   'flashLink',
                 ])),
           }));
@@ -314,7 +231,9 @@ export default {
         flashes.chunks = flashChunks;
       }
     }
+    */
 
+    /*
     // Commentary doesn't use the detailed contribution system where multiple
     // artists are collaboratively credited for the same piece, so there isn't
     // really anything special to do for processing or presenting it.
@@ -358,6 +277,7 @@ export default {
       commentary.heading = relation('generateContentHeading');
       commentary.chunks = commentaryChunks;
     }
+    */
 
     return relations;
   },
@@ -376,65 +296,38 @@ export default {
     data.totalTrackCount = allTracks.length;
     data.totalDuration = getTotalDuration(allTracks, {originalReleasesOnly: true});
 
-    return data;
-  },
-
-  generate(data, relations, {html, language}) {
-    const {sections: sec} = relations;
-
-    function addAccentsToEntry({
-      rerelease,
-      entry,
-      otherArtistLinks,
-      contributionDescriptions,
-    }) {
-      if (rerelease) {
-        return language.$('artistPage.creditList.entry.rerelease', {entry});
-      }
+    /*
+    data.trackContributionInfo =
+      query.trackContributionChunks
+        .map(({date, chunk}) => ({
+          date: +date,
+          duration: accumulateSum(chunk, ({track}) => track.duration),
+          tracks: chunk.map(({track, contribs}) => ({
+            ...getContributionDescription(contribs),
+            rerelease: track.originalReleaseTrack !== null,
+            duration: track.duration,
+          }))
+        }))
+    */
 
-      const options = {entry};
-      const parts = ['artistPage.creditList.entry'];
+    return data;
 
-      if (otherArtistLinks) {
-        parts.push('withArtists');
-        options.artists = language.formatConjunctionList(otherArtistLinks);
-      }
+    /*
+    function getContributionDescription(contribs) {
+      const ownContrib =
+        contribs.find(({who}) => who === artist);
 
-      if (contributionDescriptions) {
-        parts.push('withContribution');
-        options.contribution = language.formatUnitList(contributionDescriptions);
-      }
-
-      if (parts.length === 1) {
-        return entry;
+      if (!ownContrib) {
+        return {};
       }
 
-      return language.formatString(parts.join('.'), options);
+      return {contributionDescription: ownContrib.what};
     }
+    */
+  },
 
-    function addAccentsToAlbumLink({
-      albumLink,
-      date,
-      duration,
-      entries,
-    }) {
-      const options = {album: albumLink};
-      const parts = ['artistPage.creditList.album'];
-
-      if (date) {
-        parts.push('withDate');
-        options.date = language.formatDate(new Date(date));
-      }
-
-      if (duration) {
-        parts.push('withDuration');
-        options.duration = language.formatDuration(duration, {
-          approximate: entries.length > 1,
-        });
-      }
-
-      return language.formatString(parts.join('.'), options);
-    }
+  generate(data, relations, {html, language}) {
+    const {sections: sec} = relations;
 
     return relations.layout
       .slots({
@@ -536,31 +429,60 @@ export default {
                             })))),
                 })),
 
-            html.tag('dl',
-              sec.tracks.chunks.map(({albumLink, date, duration, entries}) => [
-                html.tag('dt',
-                  addAccentsToAlbumLink({albumLink, date, duration, entries})),
+            sec.tracks.list,
 
-                html.tag('dd',
-                  html.tag('ul',
-                    entries
-                      .map(({trackLink, duration, ...properties}) => ({
-                        entry:
-                          (duration
-                            ? language.$('artistPage.creditList.entry.track.withDuration', {
-                                track: trackLink,
-                                duration: language.formatDuration(duration),
-                              })
-                            : language.$('artistPage.creditList.entry.track', {
-                                track: trackLink,
-                              })),
-                        ...properties,
-                      }))
-                      .map(addAccentsToEntry)
-                      .map(entry => html.tag('li', entry)))),
-              ])),
+            /*
+            html.tag('dl',
+              stitchArrays({
+                chunkAlbumLink:         relations.sections.tracks.chunkAlbumLink,
+                trackLinks:             relations.sections.tracks.trackLinks,
+                trackOtherArtistLinks:  relations.sections.tracks.trackOtherArtistLinks,
+                chunkDate:        data.sections.tracks.chunkDates,
+                chunkDuration:    data.sections.tracks.chunkDurations,
+                chunkApproximate: data.sections.tracks.chunkApproximates,
+                trackDurations:   data.sections.tracks.trackDurations,
+              }).map(({
+                  chunkAlbumLink,
+                  trackLinks,
+                  trackOtherArtistLinks,
+                  chunkDate,
+                  chunkDuration,
+                  chunkApproximate,
+                  trackDurations,
+                }) => [
+                  html.tag('dt',
+                    addAccentsToAlbumLink({
+                      albumLink: chunkAlbumLink,
+                      date: chunkDate,
+                      duration: chunkDuration,
+                      approximate: chunkApproximate,
+                    })),
+
+                  html.tag('dd',
+                    html.tag('ul',
+                      stitchArrays({
+                        trackLink:         trackLinks,
+                        otherArtistLinks:  trackOtherArtistLinks,
+                        duration:          trackDurations,
+                      }).map(({trackLink, duration, ...properties}) => ({
+                          entry:
+                            (duration
+                              ? language.$('artistPage.creditList.entry.track.withDuration', {
+                                  track: trackLink,
+                                  duration: language.formatDuration(duration),
+                                })
+                              : language.$('artistPage.creditList.entry.track', {
+                                  track: trackLink,
+                                })),
+                          ...properties,
+                        }))
+                        .map(addAccentsToEntry)
+                        .map(entry => html.tag('li', entry)))),
+                ])),
+            */
           ],
 
+          /*
           sec.artworks && [
             sec.artworks.heading
               .slots({
@@ -652,7 +574,9 @@ export default {
                       .map(row => html.tag('li', row)))),
               ])),
           ],
+          */
 
+          /*
           sec.commentary && [
             sec.commentary.heading
               .slots({
@@ -681,6 +605,7 @@ export default {
                       .map(entry => html.tag('li', entry)))),
               ])),
           ],
+          */
         ],
 
         navLinkStyle: 'hierarchical',
diff --git a/src/content/dependencies/generateArtistInfoPageChunk.js b/src/content/dependencies/generateArtistInfoPageChunk.js
new file mode 100644
index 0000000..121cf43
--- /dev/null
+++ b/src/content/dependencies/generateArtistInfoPageChunk.js
@@ -0,0 +1,44 @@
+export default {
+  extraDependencies: ['html', 'language'],
+
+  slots: {
+    albumLink: {type: 'html'},
+
+    date: {validate: v => v.isDate},
+    duration: {validate: v => v.isDuration},
+    durationApproximate: {type: 'boolean'},
+
+    items: {type: 'html'},
+  },
+
+  generate(slots, {html, language}) {
+    let accentedLink = slots.albumLink;
+
+    accent: {
+      const options = {album: accentedLink};
+      const parts = ['artistPage.creditList.album'];
+
+      if (slots.date) {
+        parts.push('withDate');
+        options.date = language.formatDate(slots.date);
+      }
+
+      if (slots.duration) {
+        parts.push('withDuration');
+        options.duration =
+          language.formatDuration(slots.duration, {
+            approximate: slots.durationApproximate,
+          });
+      }
+
+      accentedLink = language.formatString(parts.join('.'), options);
+    }
+
+    return html.tags([
+      html.tag('dt', accentedLink),
+      html.tag('dd',
+        html.tag('ul',
+          slots.items)),
+    ]);
+  },
+};
diff --git a/src/content/dependencies/generateArtistInfoPageChunkItem.js b/src/content/dependencies/generateArtistInfoPageChunkItem.js
new file mode 100644
index 0000000..9004f18
--- /dev/null
+++ b/src/content/dependencies/generateArtistInfoPageChunkItem.js
@@ -0,0 +1,50 @@
+export default {
+  extraDependencies: ['html', 'language'],
+
+  slots: {
+    content: {type: 'html'},
+
+    otherArtistLinks: {validate: v => v.arrayOf(v.isHTML)},
+    contribution: {type: 'string'},
+    rerelease: {type: 'boolean'},
+  },
+
+  generate(slots, {html, language}) {
+    let accentedContent = slots.content;
+
+    accent: {
+      if (slots.rerelease) {
+        accentedContent =
+          language.$('artistPage.creditList.entry.rerelease', {
+            entry: accentedContent,
+          });
+
+        break accent;
+      }
+
+      const parts = ['artistPage.creditList.entry'];
+      const options = {entry: accentedContent};
+
+      if (slots.otherArtistLinks) {
+        parts.push('withArtists');
+        options.artists = language.formatConjunctionList(slots.otherArtistLinks);
+      }
+
+      if (slots.contribution) {
+        parts.push('withContribution');
+        options.contribution = slots.contribution;
+      }
+
+      if (parts.length === 1) {
+        break accent;
+      }
+
+      accentedContent = language.formatString(parts.join('.'), options);
+    }
+
+    return (
+      html.tag('li',
+        {class: slots.rerelease && 'rerelease'},
+        accentedContent));
+  },
+};
diff --git a/src/content/dependencies/generateArtistInfoPageOtherArtistLinks.js b/src/content/dependencies/generateArtistInfoPageOtherArtistLinks.js
new file mode 100644
index 0000000..7667dea
--- /dev/null
+++ b/src/content/dependencies/generateArtistInfoPageOtherArtistLinks.js
@@ -0,0 +1,23 @@
+import {empty} from '../../util/sugar.js';
+
+export default {
+  contentDependencies: ['linkArtist'],
+
+  relations(relation, contribs, artist) {
+    const otherArtistContribs = contribs.filter(({who}) => who !== artist);
+
+    if (empty(otherArtistContribs)) {
+      return {};
+    }
+
+    const otherArtistLinks =
+      otherArtistContribs
+        .map(({who}) => relation('linkArtist', who));
+
+    return {otherArtistLinks};
+  },
+
+  generate(relations) {
+    return relations.otherArtistLinks ?? null;
+  },
+};
diff --git a/src/content/dependencies/generateArtistInfoPageTracksChunkedList.js b/src/content/dependencies/generateArtistInfoPageTracksChunkedList.js
new file mode 100644
index 0000000..27d8a56
--- /dev/null
+++ b/src/content/dependencies/generateArtistInfoPageTracksChunkedList.js
@@ -0,0 +1,187 @@
+import {accumulateSum, stitchArrays, unique} from '../../util/sugar.js';
+import {chunkByProperties, sortAlbumsTracksChronologically} from '../../util/wiki-data.js';
+
+// TODO: This obviously needs to be more generalized.
+function sortContributionEntries(entries, sortFunction) {
+  const things = unique(entries.map(({thing}) => thing));
+  sortFunction(things);
+
+  const outputArrays = [];
+  const thingToOutputArray = new Map();
+
+  for (const thing of things) {
+    const array = [];
+    thingToOutputArray.set(thing, array);
+    outputArrays.push(array);
+  }
+
+  for (const entry of entries) {
+    thingToOutputArray.get(entry.thing).push(entry);
+  }
+
+  entries.splice(0, entries.length, ...outputArrays.flat());
+}
+
+export default {
+  contentDependencies: [
+    'generateArtistInfoPageChunk',
+    'generateArtistInfoPageChunkItem',
+    'generateArtistInfoPageOtherArtistLinks',
+    'linkAlbum',
+    'linkTrack',
+  ],
+
+  extraDependencies: ['html', 'language'],
+
+  query(artist) {
+    const entries = [
+      ...artist.tracksAsArtist.map(track => ({
+        track,
+        date: track.date,
+        thing: track,
+        album: track.album,
+        contribs: track.artistContribs,
+      })),
+
+      ...artist.tracksAsContributor.map(track => ({
+        track,
+        date: track.date,
+        thing: track,
+        album: track.album,
+        contribs: track.contributorContribs,
+      })),
+    ];
+
+    sortContributionEntries(entries, sortAlbumsTracksChronologically);
+
+    const chunks = chunkByProperties(entries, ['album', 'date']);
+
+    return {entries, chunks};
+  },
+
+  relations(relation, query, artist) {
+    return {
+      chunks:
+        query.chunks.map(() => relation('generateArtistInfoPageChunk')),
+
+      albumLinks:
+        query.chunks.map(({album}) => relation('linkAlbum', album)),
+
+      items:
+        query.chunks.map(({chunk}) =>
+          chunk.map(() => relation('generateArtistInfoPageChunkItem'))),
+
+      trackLinks:
+        query.chunks.map(({chunk}) =>
+          chunk.map(({track}) => relation('linkTrack', track))),
+
+      trackOtherArtistLinks:
+        query.chunks.map(({chunk}) =>
+          chunk.map(({contribs}) => relation('generateArtistInfoPageOtherArtistLinks', contribs, artist))),
+    };
+  },
+
+  data(query, artist) {
+    return {
+      chunkDates:
+        query.chunks.map(({date}) => date),
+
+      chunkDurations:
+        query.chunks.map(({chunk}) =>
+          accumulateSum(
+            chunk
+              .filter(({track}) => track.duration && track.originalReleaseTrack === null)
+              .map(({track}) => track.duration))),
+
+      chunkDurationsApproximate:
+        query.chunks.map(({chunk}) =>
+          chunk
+            .filter(({track}) => track.duration && track.originalReleaseTrack === null)
+            .length > 1),
+
+      trackDurations:
+        query.chunks.map(({chunk}) =>
+          chunk.map(({track}) => track.duration)),
+
+      trackContributions:
+        query.chunks.map(({chunk}) =>
+          chunk.map(({contribs}) =>
+            contribs
+              .find(({who}) => who === artist)
+              .what)),
+
+      trackRereleases:
+        query.chunks.map(({chunk}) =>
+          chunk.map(({track}) => track.originalReleaseTrack !== null)),
+    };
+  },
+
+  generate(data, relations, {html, language}) {
+    return html.tag('dl',
+      stitchArrays({
+        chunk: relations.chunks,
+        albumLink: relations.albumLinks,
+        date: data.chunkDates,
+        duration: data.chunkDurations,
+        durationApproximate: data.chunkDurationsApproximate,
+
+        items: relations.items,
+        trackLinks: relations.trackLinks,
+        trackOtherArtistLinks: relations.trackOtherArtistLinks,
+        trackDurations: data.trackDurations,
+        trackContributions: data.trackContributions,
+        trackRereleases: data.trackRereleases,
+      }).map(({
+          chunk,
+          albumLink,
+          date,
+          duration,
+          durationApproximate,
+
+          items,
+          trackLinks,
+          trackOtherArtistLinks,
+          trackDurations,
+          trackContributions,
+          trackRereleases,
+        }) =>
+          chunk.slots({
+            albumLink,
+            date,
+            duration,
+            durationApproximate,
+
+            items:
+              stitchArrays({
+                item: items,
+                trackLink: trackLinks,
+                otherArtistLinks: trackOtherArtistLinks,
+                duration: trackDurations,
+                contribution: trackContributions,
+                rerelease: trackRereleases,
+              }).map(({
+                  item,
+                  trackLink,
+                  otherArtistLinks,
+                  duration,
+                  contribution,
+                  rerelease,
+                }) =>
+                  item.slots({
+                    otherArtistLinks,
+                    contribution,
+                    rerelease,
+
+                    content:
+                      (duration
+                        ? language.$('artistPage.creditList.entry.track.withDuration', {
+                            track: trackLink,
+                            duration: language.formatDuration(duration),
+                          })
+                        : language.$('artistPage.creditList.entry.track', {
+                            track: trackLink,
+                          })),
+                  })),
+          })));
+  },
+};