« 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/composite/wiki-properties/wikiData.js34
-rw-r--r--src/data/things/album.js19
-rw-r--r--src/data/things/art-tag.js9
-rw-r--r--src/data/things/artist.js19
-rw-r--r--src/data/things/composite.js14
-rw-r--r--src/data/things/flash.js18
-rw-r--r--src/data/things/group.js16
-rw-r--r--src/data/things/homepage-layout.js16
-rw-r--r--src/data/things/track.js24
-rw-r--r--src/data/things/validators.js40
-rw-r--r--src/data/things/wiki-info.js4
11 files changed, 161 insertions, 52 deletions
diff --git a/src/data/composite/wiki-properties/wikiData.js b/src/data/composite/wiki-properties/wikiData.js
index 4ea47785..5cea49a0 100644
--- a/src/data/composite/wiki-properties/wikiData.js
+++ b/src/data/composite/wiki-properties/wikiData.js
@@ -1,17 +1,29 @@
 // General purpose wiki data constructor, for properties like artistData,
 // trackData, etc.
 
-import {validateArrayItems, validateInstanceOf} from '#validators';
+import {input, templateCompositeFrom} from '#composite';
+import {validateWikiData} from '#validators';
 
-// TODO: Not templateCompositeFrom.
+import {inputThingClass} from '#composite/wiki-data';
 
-// TODO: This should validate with validateWikiData.
+// TODO: Kludge.
+import Thing from '../../things/thing.js';
 
-export default function(thingClass) {
-  return {
-    flags: {update: true},
-    update: {
-      validate: validateArrayItems(validateInstanceOf(thingClass)),
-    },
-  };
-}
+export default templateCompositeFrom({
+  annotation: `wikiData`,
+
+  compose: false,
+
+  inputs: {
+    class: inputThingClass(),
+  },
+
+  update: ({
+    [input.staticValue('class')]: thingClass,
+  }) => {
+    const referenceType = thingClass[Thing.referenceType];
+    return {validate: validateWikiData({referenceType})};
+  },
+
+  steps: () => [],
+});
diff --git a/src/data/things/album.js b/src/data/things/album.js
index 546fda3b..af3eb042 100644
--- a/src/data/things/album.js
+++ b/src/data/things/album.js
@@ -121,10 +121,21 @@ export class Album extends Thing {
 
     // Update only
 
-    artistData: wikiData(Artist),
-    artTagData: wikiData(ArtTag),
-    groupData: wikiData(Group),
-    trackData: wikiData(Track),
+    artistData: wikiData({
+      class: input.value(Artist),
+    }),
+
+    artTagData: wikiData({
+      class: input.value(ArtTag),
+    }),
+
+    groupData: wikiData({
+      class: input.value(Group),
+    }),
+
+    trackData: wikiData({
+      class: input.value(Track),
+    }),
 
     // Expose only
 
diff --git a/src/data/things/art-tag.js b/src/data/things/art-tag.js
index 8901ab39..f9e5f0f3 100644
--- a/src/data/things/art-tag.js
+++ b/src/data/things/art-tag.js
@@ -40,8 +40,13 @@ export class ArtTag extends Thing {
 
     // Update only
 
-    albumData: wikiData(Album),
-    trackData: wikiData(Track),
+    albumData: wikiData({
+      class: input.value(Album),
+    }),
+
+    trackData: wikiData({
+      class: input.value(Track),
+    }),
 
     // Expose only
 
diff --git a/src/data/things/artist.js b/src/data/things/artist.js
index ea19d2ba..e0350b86 100644
--- a/src/data/things/artist.js
+++ b/src/data/things/artist.js
@@ -45,10 +45,21 @@ export class Artist extends Thing {
 
     // Update only
 
-    albumData: wikiData(Album),
-    artistData: wikiData(Artist),
-    flashData: wikiData(Flash),
-    trackData: wikiData(Track),
+    albumData: wikiData({
+      class: input.value(Album),
+    }),
+
+    artistData: wikiData({
+      class: input.value(Artist),
+    }),
+
+    flashData: wikiData({
+      class: input.value(Flash),
+    }),
+
+    trackData: wikiData({
+      class: input.value(Track),
+    }),
 
     // Expose only
 
diff --git a/src/data/things/composite.js b/src/data/things/composite.js
index 51525bc1..113f0a4f 100644
--- a/src/data/things/composite.js
+++ b/src/data/things/composite.js
@@ -637,6 +637,10 @@ export function compositeFrom(description) {
 
   const compositionNests = description.compose ?? true;
 
+  if (compositionNests && empty(steps)) {
+    aggregate.push(new TypeError(`Expected at least one step`));
+  }
+
   // Steps default to exposing if using a shorthand syntax where flags aren't
   // specified at all.
   const stepsExpose =
@@ -802,8 +806,8 @@ export function compositeFrom(description) {
     });
   }
 
-  if (!compositionNests && !anyStepsCompute && !anyStepsTransform) {
-    aggregate.push(new TypeError(`Expected at least one step to compute or transform`));
+  if (!compositionNests && !compositionUpdates && !anyStepsCompute) {
+    aggregate.push(new TypeError(`Expected at least one step to compute`));
   }
 
   aggregate.close();
@@ -1241,8 +1245,10 @@ export function compositeFrom(description) {
         expose.cache = base.cacheComposition;
       }
     } else if (compositionUpdates) {
-      expose.transform = (value, dependencies) =>
-        _wrapper(value, null, dependencies);
+      if (!empty(steps)) {
+        expose.transform = (value, dependencies) =>
+          _wrapper(value, null, dependencies);
+      }
     } else {
       expose.compute = (dependencies) =>
         _wrapper(noTransformSymbol, null, dependencies);
diff --git a/src/data/things/flash.js b/src/data/things/flash.js
index e2afcef4..1bdda6c8 100644
--- a/src/data/things/flash.js
+++ b/src/data/things/flash.js
@@ -95,9 +95,17 @@ export class Flash extends Thing {
 
     // Update only
 
-    artistData: wikiData(Artist),
-    trackData: wikiData(Track),
-    flashActData: wikiData(FlashAct),
+    artistData: wikiData({
+      class: input.value(Artist),
+    }),
+
+    trackData: wikiData({
+      class: input.value(Track),
+    }),
+
+    flashActData: wikiData({
+      class: input.value(FlashAct),
+    }),
 
     // Expose only
 
@@ -159,6 +167,8 @@ export class FlashAct extends Thing {
 
     // Update only
 
-    flashData: wikiData(Flash),
+    flashData: wikiData({
+      class: input.value(Flash),
+    }),
   })
 }
diff --git a/src/data/things/group.js b/src/data/things/group.js
index 8764a9db..75469bbd 100644
--- a/src/data/things/group.js
+++ b/src/data/things/group.js
@@ -34,8 +34,13 @@ export class Group extends Thing {
 
     // Update only
 
-    albumData: wikiData(Album),
-    groupCategoryData: wikiData(GroupCategory),
+    albumData: wikiData({
+      class: input.value(Album),
+    }),
+
+    groupCategoryData: wikiData({
+      class: input.value(GroupCategory),
+    }),
 
     // Expose only
 
@@ -83,12 +88,15 @@ export class Group extends Thing {
 }
 
 export class GroupCategory extends Thing {
+  static [Thing.referenceType] = 'group-category';
   static [Thing.friendlyName] = `Group Category`;
 
   static [Thing.getPropertyDescriptors] = ({Group}) => ({
     // Update & expose
 
     name: name('Unnamed Group Category'),
+    directory: directory(),
+
     color: color(),
 
     groups: referenceList({
@@ -99,6 +107,8 @@ export class GroupCategory extends Thing {
 
     // Update only
 
-    groupData: wikiData(Group),
+    groupData: wikiData({
+      class: input.value(Group),
+    }),
   });
 }
diff --git a/src/data/things/homepage-layout.js b/src/data/things/homepage-layout.js
index bfa971ca..59c069bd 100644
--- a/src/data/things/homepage-layout.js
+++ b/src/data/things/homepage-layout.js
@@ -70,11 +70,17 @@ export class HomepageLayoutRow extends Thing {
 
     // Update only
 
-    // These aren't necessarily used by every HomepageLayoutRow subclass, but
-    // for convenience of providing this data, every row accepts all wiki data
-    // arrays depended upon by any subclass's behavior.
-    albumData: wikiData(Album),
-    groupData: wikiData(Group),
+    // These wiki data arrays aren't necessarily used by every subclass, but
+    // to the convenience of providing these, the superclass accepts all wiki
+    // data arrays depended upon by any subclass.
+
+    albumData: wikiData({
+      class: input.value(Album),
+    }),
+
+    groupData: wikiData({
+      class: input.value(Group),
+    }),
   });
 }
 
diff --git a/src/data/things/track.js b/src/data/things/track.js
index db325a17..8d310611 100644
--- a/src/data/things/track.js
+++ b/src/data/things/track.js
@@ -256,11 +256,25 @@ export class Track extends Thing {
 
     // Update only
 
-    albumData: wikiData(Album),
-    artistData: wikiData(Artist),
-    artTagData: wikiData(ArtTag),
-    flashData: wikiData(Flash),
-    trackData: wikiData(Track),
+    albumData: wikiData({
+      class: input.value(Album),
+    }),
+
+    artistData: wikiData({
+      class: input.value(Artist),
+    }),
+
+    artTagData: wikiData({
+      class: input.value(ArtTag),
+    }),
+
+    flashData: wikiData({
+      class: input.value(Flash),
+    }),
+
+    trackData: wikiData({
+      class: input.value(Track),
+    }),
 
     // Expose only
 
diff --git a/src/data/things/validators.js b/src/data/things/validators.js
index ee301f15..f60c363c 100644
--- a/src/data/things/validators.js
+++ b/src/data/things/validators.js
@@ -433,18 +433,38 @@ export function validateWikiData({
         OK = true; return true;
       }
 
-      const allRefTypes =
-        new Set(array.map(object =>
-          object.constructor[Symbol.for('Thing.referenceType')]));
+      const allRefTypes = new Set();
 
-      if (allRefTypes.has(undefined)) {
-        if (allRefTypes.size === 1) {
-          throw new TypeError(`Expected array of wiki data objects, got array of other objects`);
+      let foundThing = false;
+      let foundOtherObject = false;
+
+      for (const object of array) {
+        const {[Symbol.for('Thing.referenceType')]: referenceType} = object.constructor;
+
+        if (referenceType === undefined) {
+          foundOtherObject = true;
+
+          // Early-exit if a Thing has been found - nothing more can be learned.
+          if (foundThing) {
+            throw new TypeError(`Expected array of wiki data objects, got mixed items`);
+          }
         } else {
-          throw new TypeError(`Expected array of wiki data objects, got mixed items`);
+          foundThing = true;
+
+          // Early-exit if a non-Thing object has been found - nothing more can
+          // be learned.
+          if (foundOtherObject) {
+            throw new TypeError(`Expected array of wiki data objects, got mixed items`);
+          }
+
+          allRefTypes.add(referenceType);
         }
       }
 
+      if (foundOtherObject && !foundThing) {
+        throw new TypeError(`Expected array of wiki data objects, got array of other objects`);
+      }
+
       if (allRefTypes.size > 1) {
         if (allowMixedTypes) {
           OK = true; return true;
@@ -464,8 +484,10 @@ export function validateWikiData({
         throw new TypeError(`Expected array of unmixed reference types, got multiple: ${types()}`);
       }
 
-      if (referenceType && !allRefTypes.has(referenceType)) {
-        throw new TypeError(`Expected array of ${referenceType}, got array of ${allRefTypes[0]}`)
+      const onlyRefType = Array.from(allRefTypes)[0];
+
+      if (referenceType && onlyRefType !== referenceType) {
+        throw new TypeError(`Expected array of ${referenceType}, got array of ${onlyRefType}`)
       }
 
       OK = true; return true;
diff --git a/src/data/things/wiki-info.js b/src/data/things/wiki-info.js
index 6286a267..89053d62 100644
--- a/src/data/things/wiki-info.js
+++ b/src/data/things/wiki-info.js
@@ -64,6 +64,8 @@ export class WikiInfo extends Thing {
 
     // Update only
 
-    groupData: wikiData(Group),
+    groupData: wikiData({
+      class: input.value(Group),
+    }),
   });
 }