« 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/content/dependencies/generateAdditionalFilesList.js99
-rw-r--r--src/content/dependencies/generateAdditionalFilesListChunk.js39
-rw-r--r--src/content/dependencies/generateAdditionalFilesListChunkItem.js30
-rw-r--r--src/content/dependencies/generateAlbumAdditionalFilesList.js88
4 files changed, 145 insertions, 111 deletions
diff --git a/src/content/dependencies/generateAdditionalFilesList.js b/src/content/dependencies/generateAdditionalFilesList.js
index fc24ee52..2737a410 100644
--- a/src/content/dependencies/generateAdditionalFilesList.js
+++ b/src/content/dependencies/generateAdditionalFilesList.js
@@ -1,95 +1,24 @@
-import {empty} from '#sugar';
-
-function validateFileMapping(v, validateValue) {
-  return value => {
-    v.isObject(value);
-
-    const valueErrors = [];
-    for (const [fileKey, fileValue] of Object.entries(value)) {
-      if (fileValue === null) {
-        continue;
-      }
-
-      try {
-        validateValue(fileValue);
-      } catch (error) {
-        error.message = `(${fileKey}) ` + error.message;
-        valueErrors.push(error);
-      }
-    }
-
-    if (!empty(valueErrors)) {
-      throw new AggregateError(valueErrors, `Errors validating values`);
-    }
-  };
-}
+import {stitchArrays} from '#sugar';
 
 export default {
-  extraDependencies: ['html', 'language'],
-
-  data: (additionalFiles) => ({
-    // Additional files are already a serializable format.
-    additionalFiles,
-  }),
+  extraDependencies: ['html'],
 
   slots: {
-    fileLinks: {
-      validate: v => validateFileMapping(v, v.isHTML),
+    chunks: {
+      validate: v => v.strictArrayOf(v.isHTML),
     },
 
-    fileSizes: {
-      validate: v => validateFileMapping(v, v.isWholeNumber),
+    chunkItems: {
+      validate: v => v.strictArrayOf(v.isHTML),
     },
   },
 
-  generate(data, slots, {html, language}) {
-    if (!slots.fileLinks) {
-      return html.blank();
-    }
-
-    const filesWithLinks = new Set(
-      Object.entries(slots.fileLinks)
-        .filter(([key, value]) => value)
-        .map(([key]) => key));
-
-    if (empty(filesWithLinks)) {
-      return html.blank();
-    }
-
-    const filteredFileGroups = data.additionalFiles
-      .map(({title, description, files}) => ({
-        title,
-        description,
-        files: files.filter(f => filesWithLinks.has(f)),
-      }))
-      .filter(({files}) => !empty(files));
-
-    if (empty(filteredFileGroups)) {
-      return html.blank();
-    }
-
-    return html.tag('dl',
-      filteredFileGroups.flatMap(({title, description, files}) => [
-        html.tag('dt',
-          (description
-            ? language.$('releaseInfo.additionalFiles.entry.withDescription', {
-                title,
-                description,
-              })
-            : language.$('releaseInfo.additionalFiles.entry', {title}))),
-
-        html.tag('dd',
-          html.tag('ul',
-            files.map(file =>
-              html.tag('li',
-                (slots.fileSizes?.[file]
-                  ? language.$('releaseInfo.additionalFiles.file.withSize', {
-                      file: slots.fileLinks[file],
-                      size: language.formatFileSize(slots.fileSizes[file]),
-                    })
-                  : language.$('releaseInfo.additionalFiles.file', {
-                      file: slots.fileLinks[file],
-                    })))))),
-      ]));
-  },
+  generate: (slots, {html}) =>
+    html.tag('dl',
+      stitchArrays({
+        chunk: slots.chunks,
+        items: slots.chunkItems,
+      }).map(({chunk, items}) =>
+          chunk.clone()
+            .slot('items', items))),
 };
diff --git a/src/content/dependencies/generateAdditionalFilesListChunk.js b/src/content/dependencies/generateAdditionalFilesListChunk.js
new file mode 100644
index 00000000..bb16b778
--- /dev/null
+++ b/src/content/dependencies/generateAdditionalFilesListChunk.js
@@ -0,0 +1,39 @@
+export default {
+  extraDependencies: ['html', 'language'],
+
+  slots: {
+    title: {
+      type: 'html',
+      mutable: false,
+    },
+
+    description: {
+      type: 'html',
+      mutable: false,
+    },
+
+    items: {
+      validate: v => v.looseArrayOf(v.isHTML),
+    },
+  },
+
+  generate(slots, {html, language}) {
+    const titleParts = ['releaseInfo.additionalFiles.entry'];
+    const titleOptions = {title: slots.title};
+
+    if (!html.isBlank(slots.description)) {
+      titleParts.push('withDescription');
+      titleOptions.description = slots.description;
+    }
+
+    const dt =
+      html.tag('dt',
+        language.$(...titleParts, titleOptions));
+
+    const dd =
+      html.tag('dd',
+        html.tag('ul', slots.items));
+
+    return html.tags([dt, dd]);
+  },
+};
diff --git a/src/content/dependencies/generateAdditionalFilesListChunkItem.js b/src/content/dependencies/generateAdditionalFilesListChunkItem.js
new file mode 100644
index 00000000..c37d6bb2
--- /dev/null
+++ b/src/content/dependencies/generateAdditionalFilesListChunkItem.js
@@ -0,0 +1,30 @@
+export default {
+  extraDependencies: ['html', 'language'],
+
+  slots: {
+    fileLink: {
+      type: 'html',
+      mutable: false,
+    },
+
+    fileSize: {
+      validate: v => v.isWholeNumber,
+    },
+  },
+
+  generate(slots, {html, language}) {
+    const itemParts = ['releaseInfo.additionalFiles.file'];
+    const itemOptions = {file: slots.fileLink};
+
+    if (slots.fileSize) {
+      itemParts.push('withSize');
+      itemOptions.size = language.formatFileSize(slots.fileSize);
+    }
+
+    const li =
+      html.tag('li',
+        language.$(...itemParts, itemOptions));
+
+    return li;
+  },
+};
diff --git a/src/content/dependencies/generateAlbumAdditionalFilesList.js b/src/content/dependencies/generateAlbumAdditionalFilesList.js
index 06694c95..3ab0e27a 100644
--- a/src/content/dependencies/generateAlbumAdditionalFilesList.js
+++ b/src/content/dependencies/generateAlbumAdditionalFilesList.js
@@ -1,30 +1,48 @@
+import {stitchArrays} from '#sugar';
+
 export default {
   contentDependencies: [
     'generateAdditionalFilesList',
+    'generateAdditionalFilesListChunk',
+    'generateAdditionalFilesListChunkItem',
     'linkAlbumAdditionalFile',
   ],
 
   extraDependencies: ['getSizeOfAdditionalFile', 'html', 'urls'],
 
+  relations: (relation, album, additionalFiles) => ({
+    list:
+      relation('generateAdditionalFilesList', additionalFiles),
+
+    chunks:
+      additionalFiles
+        .map(() => relation('generateAdditionalFilesListChunk')),
+
+    chunkItems:
+      additionalFiles
+        .map(({files}) => files
+          .map(() => relation('generateAdditionalFilesListChunkItem'))),
+
+    chunkItemFileLinks:
+      additionalFiles
+        .map(({files}) => files
+          .map(file => relation('linkAlbumAdditionalFile', album, file))),
+  }),
+
   data: (album, additionalFiles) => ({
     albumDirectory: album.directory,
 
-    fileLocations:
-      additionalFiles.flatMap(({files}) => files),
-  }),
+    chunkTitles:
+      additionalFiles
+        .map(({title}) => title),
 
-  relations: (relation, album, additionalFiles) => ({
-    additionalFilesList:
-      relation('generateAdditionalFilesList', additionalFiles),
+    chunkDescriptions:
+      additionalFiles
+        .map(({description}) => description),
 
-    additionalFileLinks:
-      Object.fromEntries(
-        additionalFiles
-          .flatMap(({files}) => files)
-          .map(file => [
-            file,
-            relation('linkAlbumAdditionalFile', album, file),
-          ])),
+    chunkItemLocations:
+      additionalFiles
+        .map(({files}) => files),
   }),
 
   slots: {
@@ -32,17 +50,35 @@ export default {
   },
 
   generate: (data, relations, slots, {getSizeOfAdditionalFile, urls}) =>
-    relations.additionalFilesList.slots({
-      fileLinks: relations.additionalFileLinks,
-      fileSizes:
-        Object.fromEntries(data.fileLocations.map(file => [
-          file,
-          (slots.showFileSizes
-            ? getSizeOfAdditionalFile(
-                urls
-                  .from('media.root')
-                  .to('media.albumAdditionalFile', data.albumDirectory, file))
-            : 0),
-        ])),
+    relations.list.slots({
+      chunks:
+        stitchArrays({
+          chunk: relations.chunks,
+          title: data.chunkTitles,
+          description: data.chunkDescriptions,
+        }).map(({chunk, title, description}) =>
+            chunk.slots({title, description})),
+
+      chunkItems:
+        stitchArrays({
+          items: relations.chunkItems,
+          fileLinks: relations.chunkItemFileLinks,
+          locations: data.chunkItemLocations,
+        }).map(({items, fileLinks, locations}) =>
+            stitchArrays({
+              item: items,
+              fileLink: fileLinks,
+              location: locations,
+            }).map(({item, fileLink, location}) =>
+                item.slots({
+                  fileLink: fileLink,
+                  fileSize:
+                    (slots.showFileSizes
+                      ? getSizeOfAdditionalFile(
+                          urls
+                            .from('media.root')
+                            .to('media.albumAdditionalFile', data.albumDirectory, location))
+                      : 0),
+                }))),
     }),
 };