« get me outta code hell

hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/content/dependencies/generateAdditionalFilesList.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/content/dependencies/generateAdditionalFilesList.js')
-rw-r--r--src/content/dependencies/generateAdditionalFilesList.js97
1 files changed, 97 insertions, 0 deletions
diff --git a/src/content/dependencies/generateAdditionalFilesList.js b/src/content/dependencies/generateAdditionalFilesList.js
new file mode 100644
index 00000000..d280a633
--- /dev/null
+++ b/src/content/dependencies/generateAdditionalFilesList.js
@@ -0,0 +1,97 @@
+import {empty} from '../../util/sugar.js';
+
+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`);
+    }
+  };
+}
+
+export default {
+  extraDependencies: ['html', 'language'],
+
+  data(additionalFiles) {
+    return {
+      // Additional files are already a serializable format.
+      additionalFiles,
+    };
+  },
+
+  slots: {
+    fileLinks: {
+      validate: v => validateFileMapping(v, v.isHTML),
+    },
+
+    fileSizes: {
+      validate: v => validateFileMapping(v, v.isWholeNumber),
+    },
+  },
+
+  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],
+                    })))))),
+      ]));
+  },
+};