« get me outta code hell

hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/data/things
diff options
context:
space:
mode:
Diffstat (limited to 'src/data/things')
-rw-r--r--src/data/things/album.js24
-rw-r--r--src/data/things/artist.js5
-rw-r--r--src/data/things/homepage-layout.js4
-rw-r--r--src/data/things/language.js10
-rw-r--r--src/data/things/thing.js16
-rw-r--r--src/data/things/validators.js49
6 files changed, 75 insertions, 33 deletions
diff --git a/src/data/things/album.js b/src/data/things/album.js
index 2a188f2d..d371f51f 100644
--- a/src/data/things/album.js
+++ b/src/data/things/album.js
@@ -1,5 +1,6 @@
 import Thing from './thing.js';
 
+import {empty} from '../../util/sugar.js';
 import find from '../../util/find.js';
 
 export class Album extends Thing {
@@ -34,12 +35,12 @@ export class Album extends Thing {
       update: {validate: isDate},
 
       expose: {
-        dependencies: ['date', 'hasCoverArt'],
+        dependencies: ['date', 'coverArtistContribsByRef'],
         transform: (coverArtDate, {
+          coverArtistContribsByRef,
           date,
-          hasCoverArt,
         }) =>
-          (hasCoverArt
+          (!empty(coverArtistContribsByRef)
             ? coverArtDate ?? date ?? null
             : null),
       },
@@ -103,7 +104,6 @@ export class Album extends Thing {
       update: {validate: isDimensions},
     },
 
-    hasCoverArt: Thing.common.flag(true),
     hasTrackArt: Thing.common.flag(true),
     hasTrackNumbers: Thing.common.flag(true),
     isListedOnHomepage: Thing.common.flag(true),
@@ -123,18 +123,16 @@ export class Album extends Thing {
 
     artistContribs: Thing.common.dynamicContribs('artistContribsByRef'),
     coverArtistContribs: Thing.common.dynamicContribs('coverArtistContribsByRef'),
-    trackCoverArtistContribs: Thing.common.dynamicContribs(
-      'trackCoverArtistContribsByRef'
-    ),
-    wallpaperArtistContribs: Thing.common.dynamicContribs(
-      'wallpaperArtistContribsByRef'
-    ),
-    bannerArtistContribs: Thing.common.dynamicContribs(
-      'bannerArtistContribsByRef'
-    ),
+    trackCoverArtistContribs: Thing.common.dynamicContribs('trackCoverArtistContribsByRef'),
+    wallpaperArtistContribs: Thing.common.dynamicContribs('wallpaperArtistContribsByRef'),
+    bannerArtistContribs: Thing.common.dynamicContribs('bannerArtistContribsByRef'),
 
     commentatorArtists: Thing.common.commentatorArtists(),
 
+    hasCoverArt: Thing.common.contribsPresent('coverArtistContribsByRef'),
+    hasWallpaperArt: Thing.common.contribsPresent('wallpaperArtistContribsByRef'),
+    hasBannerArt: Thing.common.contribsPresent('bannerArtistContribsByRef'),
+
     tracks: {
       flags: {expose: true},
 
diff --git a/src/data/things/artist.js b/src/data/things/artist.js
index 303f33f3..f144b21f 100644
--- a/src/data/things/artist.js
+++ b/src/data/things/artist.js
@@ -27,9 +27,8 @@ export class Artist extends Thing {
 
     aliasNames: {
       flags: {update: true, expose: true},
-      update: {
-        validate: validateArrayItems(isName),
-      },
+      update: {validate: validateArrayItems(isName)},
+      expose: {transform: (names) => names ?? []},
     },
 
     isAlias: Thing.common.flag(),
diff --git a/src/data/things/homepage-layout.js b/src/data/things/homepage-layout.js
index c18e8110..a79dd77a 100644
--- a/src/data/things/homepage-layout.js
+++ b/src/data/things/homepage-layout.js
@@ -68,10 +68,10 @@ export class HomepageLayoutAlbumsRow extends HomepageLayoutRow {
     Group,
 
     validators: {
+      is,
       isCountingNumber,
       isString,
       validateArrayItems,
-      validateFromConstants,
     },
   } = opts) => ({
     ...HomepageLayoutRow[Thing.getPropertyDescriptors](opts),
@@ -95,7 +95,7 @@ export class HomepageLayoutAlbumsRow extends HomepageLayoutRow {
       flags: {update: true, expose: true},
 
       update: {
-        validate: validateFromConstants('grid', 'carousel'),
+        validate: is('grid', 'carousel'),
       },
 
       expose: {
diff --git a/src/data/things/language.js b/src/data/things/language.js
index 3086ad2e..7755c505 100644
--- a/src/data/things/language.js
+++ b/src/data/things/language.js
@@ -101,7 +101,7 @@ export class Language extends Thing {
         dependencies: ['strings', 'inheritedStrings', 'escapeHTML'],
         compute({strings, inheritedStrings, escapeHTML}) {
           if (!(strings || inheritedStrings) || !escapeHTML) return null;
-          const allStrings = {...(inheritedStrings ?? {}), ...(strings ?? {})};
+          const allStrings = {...inheritedStrings, ...strings};
           return Object.fromEntries(
             Object.entries(allStrings).map(([k, v]) => [k, escapeHTML(v)])
           );
@@ -252,19 +252,19 @@ export class Language extends Thing {
   // Conjunction list: A, B, and C
   formatConjunctionList(array) {
     this.assertIntlAvailable('intl_listConjunction');
-    return this.intl_listConjunction.format(array);
+    return this.intl_listConjunction.format(array.map(arr => arr.toString()));
   }
 
   // Disjunction lists: A, B, or C
   formatDisjunctionList(array) {
     this.assertIntlAvailable('intl_listDisjunction');
-    return this.intl_listDisjunction.format(array);
+    return this.intl_listDisjunction.format(array.map(arr => arr.toString()));
   }
 
   // Unit lists: A, B, C
   formatUnitList(array) {
     this.assertIntlAvailable('intl_listUnit');
-    return this.intl_listUnit.format(array);
+    return this.intl_listUnit.format(array.map(arr => arr.toString()));
   }
 
   // File sizes: 42.5 kB, 127.2 MB, 4.13 GB, 998.82 TB
@@ -311,6 +311,8 @@ const countHelper = (stringKey, argName = stringKey) =>
 Object.assign(Language.prototype, {
   countAdditionalFiles: countHelper('additionalFiles', 'files'),
   countAlbums: countHelper('albums'),
+  countArtworks: countHelper('artworks'),
+  countFlashes: countHelper('flashes'),
   countCommentaryEntries: countHelper('commentaryEntries', 'entries'),
   countContributions: countHelper('contributions'),
   countCoverArts: countHelper('coverArts'),
diff --git a/src/data/things/thing.js b/src/data/things/thing.js
index 9c59436e..5004f4e6 100644
--- a/src/data/things/thing.js
+++ b/src/data/things/thing.js
@@ -23,6 +23,7 @@ import {
 
 import {inspect} from 'util';
 import {color} from '../../util/cli.js';
+import {empty} from '../../util/sugar.js';
 import {getKebabCase} from '../../util/wiki-data.js';
 
 import find from '../../util/find.js';
@@ -63,6 +64,7 @@ export default class Thing extends CacheableObject {
     urls: () => ({
       flags: {update: true, expose: true},
       update: {validate: validateArrayItems(isURL)},
+      expose: {transform: (value) => value ?? []},
     }),
 
     // A file extension! Or the default, if provided when calling this.
@@ -312,6 +314,20 @@ export default class Thing extends CacheableObject {
       },
     }),
 
+    // Nice 'n simple shorthand for an exposed-only flag which is true when any
+    // contributions are present in the specified property.
+    contribsPresent: (contribsByRefProperty) => ({
+      flags: {expose: true},
+      expose: {
+        dependencies: [contribsByRefProperty],
+        compute({
+          [contribsByRefProperty]: contribsByRef,
+        }) {
+          return !empty(contribsByRef);
+        },
+      }
+    }),
+
     // Neat little shortcut for "reversing" the reference lists stored on other
     // things - for example, tracks specify a "referenced tracks" property, and
     // you would use this to compute a corresponding "referenced *by* tracks"
diff --git a/src/data/things/validators.js b/src/data/things/validators.js
index b116120a..14092102 100644
--- a/src/data/things/validators.js
+++ b/src/data/things/validators.js
@@ -112,7 +112,12 @@ export function isInstance(value, constructor) {
 }
 
 export function isDate(value) {
-  return isInstance(value, Date);
+  isInstance(value, Date);
+
+  if (isNaN(value))
+    throw new TypeError(`Expected valid date`);
+
+  return true;
 }
 
 export function isObject(value) {
@@ -133,6 +138,34 @@ export function isArray(value) {
   return true;
 }
 
+// This one's shaped a bit different from other "is" functions.
+// More like validate functions, it returns a function.
+export function is(...values) {
+  if (Array.isArray(values)) {
+    values = new Set(values);
+  }
+
+  if (values.size === 1) {
+    const expected = Array.from(values)[0];
+
+    return (value) => {
+      if (value !== expected) {
+        throw new TypeError(`Expected ${expected}, got ${value}`);
+      }
+
+      return true;
+    };
+  }
+
+  return (value) => {
+    if (!values.has(value)) {
+      throw new TypeError(`Expected one of ${Array.from(values).join(' ')}, got ${value}`);
+    }
+
+    return true;
+  };
+}
+
 function validateArrayItemsHelper(itemValidator) {
   return (item, index) => {
     try {
@@ -162,18 +195,12 @@ export function validateArrayItems(itemValidator) {
   };
 }
 
-export function validateInstanceOf(constructor) {
-  return (object) => isInstance(object, constructor);
+export function arrayOf(itemValidator) {
+  return validateArrayItems(itemValidator);
 }
 
-export function validateFromConstants(...values) {
-  return (value) => {
-    if (!values.includes(value)) {
-      throw new TypeError(`Expected one of ${values.join(', ')}`);
-    }
-
-    return true;
-  };
+export function validateInstanceOf(constructor) {
+  return (object) => isInstance(object, constructor);
 }
 
 // Wiki data (primitives & non-primitives)