« get me outta code hell

data: fix many validation errors - hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
diff options
context:
space:
mode:
author(quasar) nebula <qznebula@protonmail.com>2023-09-20 17:33:50 -0300
committer(quasar) nebula <qznebula@protonmail.com>2023-09-20 17:33:50 -0300
commitcc4bf401f4d1df63ce33191ae82af6327c7da568 (patch)
treef66797c86a8d3470295463ef5e060fdd18c5c726
parente0cec3ff368175341526ff1b3c849f82e377b286 (diff)
data: fix many validation errors
-rw-r--r--src/data/things/album.js70
-rw-r--r--src/data/things/artist.js5
-rw-r--r--src/data/things/composite.js113
-rw-r--r--src/data/things/flash.js9
-rw-r--r--src/data/things/group.js9
-rw-r--r--src/data/things/homepage-layout.js8
-rw-r--r--src/data/things/index.js7
-rw-r--r--src/data/things/thing.js8
-rw-r--r--src/data/things/track.js52
-rw-r--r--src/data/things/wiki-info.js5
10 files changed, 172 insertions, 114 deletions
diff --git a/src/data/things/album.js b/src/data/things/album.js
index ec133a3..44af5cb 100644
--- a/src/data/things/album.js
+++ b/src/data/things/album.js
@@ -10,9 +10,9 @@ import {
   exposeUpdateValueOrContinue,
   input,
   fillMissingListItems,
-  withFlattenedArray,
+  withFlattenedList,
   withPropertiesFromList,
-  withUnflattenedArray,
+  withUnflattenedList,
 } from '#composite';
 
 import Thing, {
@@ -101,8 +101,15 @@ export class Album extends Thing {
     additionalFiles: additionalFiles(),
 
     trackSections: [
-      exitWithoutDependency({dependency: 'trackData', value: []}),
-      exitWithoutUpdateValue({value: [], mode: 'empty'}),
+      exitWithoutDependency({
+        dependency: 'trackData',
+        value: input.value([]),
+      }),
+
+      exitWithoutUpdateValue({
+        mode: input.value('empty'),
+        value: input.value([]),
+      }),
 
       withPropertiesFromList({
         list: input.updateValue(),
@@ -119,32 +126,27 @@ export class Album extends Thing {
       fillMissingListItems({list: '#sections.isDefaultTrackSection', value: false}),
       fillMissingListItems({list: '#sections.color', dependency: 'color'}),
 
-      withFlattenedArray({
-        from: '#sections.tracks',
-        into: '#trackRefs',
-        intoIndices: '#sections.startIndex',
+      withFlattenedList({
+        list: '#sections.tracks',
+      }).outputs({
+        ['#flattenedList']: '#trackRefs',
+        ['#flattenedIndices']: '#sections.startIndex',
       }),
 
-      {
-        dependencies: ['#trackRefs'],
-        compute: ({'#trackRefs': tracks}, continuation) => {
-          console.log(tracks);
-          return continuation();
-        }
-      },
-
       withResolvedReferenceList({
         list: '#trackRefs',
         data: 'trackData',
-        notFoundMode: 'null',
-        find: find.track,
-        into: '#tracks',
+        notFoundMode: input.value('null'),
+        find: input.value(find.track),
+      }).outputs({
+        ['#resolvedReferenceList']: '#tracks',
       }),
 
-      withUnflattenedArray({
-        from: '#tracks',
-        fromIndices: '#sections.startIndex',
-        into: '#sections.tracks',
+      withUnflattenedList({
+        list: '#tracks',
+        indices: '#sections.startIndex',
+      }).outputs({
+        ['#unflattenedList']: '#sections.tracks',
       }),
 
       {
@@ -191,14 +193,14 @@ export class Album extends Thing {
     bannerArtistContribs: contributionList(),
 
     groups: referenceList({
-      class: Group,
-      find: find.group,
+      class: input.value(Group),
+      find: input.value(find.group),
       data: 'groupData',
     }),
 
     artTags: referenceList({
-      class: ArtTag,
-      find: find.artTag,
+      class: input.value(ArtTag),
+      find: input.value(find.artTag),
       data: 'artTagData',
     }),
 
@@ -218,8 +220,16 @@ export class Album extends Thing {
     hasBannerArt: contribsPresent({contribs: 'bannerArtistContribs'}),
 
     tracks: [
-      exitWithoutDependency({dependency: 'trackData', value: []}),
-      exitWithoutDependency({dependency: 'trackSections', mode: 'empty', value: []}),
+      exitWithoutDependency({
+        dependency: 'trackData',
+        value: input.value([]),
+      }),
+
+      exitWithoutDependency({
+        dependency: 'trackSections',
+        mode: input.value('empty'),
+        value: input.value([]),
+      }),
 
       {
         dependencies: ['trackSections'],
@@ -233,7 +243,7 @@ export class Album extends Thing {
       withResolvedReferenceList({
         list: '#trackRefs',
         data: 'trackData',
-        find: find.track,
+        find: input.value(find.track),
       }),
 
       exposeDependency({dependency: '#resolvedReferenceList'}),
diff --git a/src/data/things/artist.js b/src/data/things/artist.js
index 7a9dbd3..085e566 100644
--- a/src/data/things/artist.js
+++ b/src/data/things/artist.js
@@ -1,3 +1,4 @@
+import {input} from '#composite';
 import find from '#find';
 import {isName, validateArrayItems} from '#validators';
 
@@ -35,8 +36,8 @@ export class Artist extends Thing {
     isAlias: flag(),
 
     aliasedArtist: singleReference({
-      class: Artist,
-      find: find.artist,
+      class: input.value(Artist),
+      find: input.value(find.artist),
       data: 'artistData',
     }),
 
diff --git a/src/data/things/composite.js b/src/data/things/composite.js
index fbdc52f..83879c5 100644
--- a/src/data/things/composite.js
+++ b/src/data/things/composite.js
@@ -1,10 +1,16 @@
 import {inspect} from 'node:util';
 
 import {colors} from '#cli';
-import {isArray, oneOf} from '#validators';
 import {TupleMap} from '#wiki-data';
 
 import {
+  isArray,
+  isWholeNumber,
+  oneOf,
+  validateArrayItems,
+} from '#validators';
+
+import {
   decorateErrorWithIndex,
   empty,
   filterProperties,
@@ -1876,72 +1882,93 @@ export const excludeFromList = templateCompositeFrom({
 // Flattens an array with one level of nested arrays, providing as dependencies
 // both the flattened array as well as the original starting indices of each
 // successive source array.
-export function withFlattenedArray({
-  from,
-  into = '#flattenedArray',
-  intoIndices = '#flattenedIndices',
-}) {
-  return {
-    annotation: `withFlattenedArray`,
-    flags: {expose: true, compose: true},
+export const withFlattenedList = templateCompositeFrom({
+  annotation: `withFlattenedList`,
 
-    expose: {
-      mapDependencies: {from},
-      mapContinuation: {into, intoIndices},
+  inputs: {
+    list: input({type: 'array'}),
+  },
 
-      compute({from: sourceArray}, continuation) {
-        const into = sourceArray.flat();
-        const intoIndices = [];
+  outputs: ['#flattenedList', '#flattenedIndices'],
 
+  steps: () => [
+    {
+      dependencies: [input('list')],
+      compute(continuation, {
+        [input('list')]: sourceList,
+      }) {
+        const flattenedList = sourceList.flat();
+        const indices = [];
         let lastEndIndex = 0;
         for (const {length} of sourceArray) {
-          intoIndices.push(lastEndIndex);
+          indices.push(lastEndIndex);
           lastEndIndex += length;
         }
 
-        return continuation({into, intoIndices});
+        return continuation({
+          ['#flattenedList']: flattenedList,
+          ['#flattenedIndices']: indices,
+        });
       },
     },
-  };
-}
+  ],
+});
 
 // After mapping the contents of a flattened array in-place (being careful to
 // retain the original indices by replacing unmatched results with null instead
 // of filtering them out), this function allows for recombining them. It will
 // filter out null and undefined items by default (pass {filter: false} to
 // disable this).
-export function withUnflattenedArray({
-  from,
-  fromIndices = '#flattenedIndices',
-  into = '#unflattenedArray',
-  filter = true,
-}) {
-  return {
-    annotation: `withUnflattenedArray`,
-    flags: {expose: true, compose: true},
+export const withUnflattenedList = templateCompositeFrom({
+  annotation: `withUnflattenedList`,
 
-    expose: {
-      mapDependencies: {from, fromIndices},
-      mapContinuation: {into},
-      compute({from, fromIndices}, continuation) {
-        const arrays = [];
+  inputs: {
+    list: input({
+      type: 'array',
+      defaultDependency: '#flattenedList',
+    }),
+
+    indices: input({
+      validate: validateArrayItems(isWholeNumber),
+      defaultDependency: '#flattenedIndices',
+    }),
+
+    filter: input({
+      type: 'boolean',
+      defaultValue: true,
+    }),
+  },
 
-        for (let i = 0; i < fromIndices.length; i++) {
-          const startIndex = fromIndices[i];
+  outputs: ['#unflattenedList'],
+
+  steps: () => [
+    {
+      dependencies: [input('list'), input('indices')],
+      compute({
+        [input('list')]: list,
+        [input('indices')]: indices,
+        [input('filter')]: filter,
+      }) {
+        const unflattenedList = [];
+
+        for (let i = 0; i < indices.length; i++) {
+          const startIndex = indices[i];
           const endIndex =
-            (i === fromIndices.length - 1
-              ? from.length
-              : fromIndices[i + 1]);
+            (i === indices.length - 1
+              ? list.length
+              : indices[i + 1]);
 
-          const values = from.slice(startIndex, endIndex);
-          arrays.push(
+          const values = list.slice(startIndex, endIndex);
+          unflattenedList.push(
             (filter
               ? values.filter(value => value !== null && value !== undefined)
               : values));
         }
 
-        return continuation({into: arrays});
+        return continuation({
+          ['#unflattenedList']: unflattenedList,
+        });
       },
     },
-  };
-}
+  ],
+});
diff --git a/src/data/things/flash.js b/src/data/things/flash.js
index eb16d29..c3f9026 100644
--- a/src/data/things/flash.js
+++ b/src/data/things/flash.js
@@ -1,3 +1,4 @@
+import {input} from '#composite';
 import find from '#find';
 
 import {
@@ -61,8 +62,8 @@ export class Flash extends Thing {
     contributorContribs: contributionList(),
 
     featuredTracks: referenceList({
-      class: Track,
-      find: find.track,
+      class: input.value(Track),
+      find: input.value(find.track),
       data: 'trackData',
     }),
 
@@ -133,9 +134,9 @@ export class FlashAct extends Thing {
     },
 
     flashes: referenceList({
-      class: Flash,
+      class: input.value(Flash),
+      find: input.value(find.flash),
       data: 'flashData',
-      find: find.flash,
     }),
 
     // Update only
diff --git a/src/data/things/group.js b/src/data/things/group.js
index f53fa48..0b11780 100644
--- a/src/data/things/group.js
+++ b/src/data/things/group.js
@@ -1,3 +1,4 @@
+import {input} from '#composite';
 import find from '#find';
 
 import Thing, {
@@ -24,8 +25,8 @@ export class Group extends Thing {
     urls: urls(),
 
     featuredAlbums: referenceList({
-      class: Album,
-      find: find.album,
+      class: input.value(Album),
+      find: input.value(find.album),
       data: 'albumData',
     }),
 
@@ -87,8 +88,8 @@ export class GroupCategory extends Thing {
     color: color(),
 
     groups: referenceList({
-      class: Group,
-      find: find.group,
+      class: input.value(Group),
+      find: input.value(find.group),
       data: 'groupData',
     }),
 
diff --git a/src/data/things/homepage-layout.js b/src/data/things/homepage-layout.js
index 677a275..bade280 100644
--- a/src/data/things/homepage-layout.js
+++ b/src/data/things/homepage-layout.js
@@ -107,7 +107,7 @@ export class HomepageLayoutAlbumsRow extends HomepageLayoutRow {
       },
     },
 
-    sourceGroup: compositeFrom(`HomepageLayoutAlbumsRow.sourceGroup`, [
+    sourceGroup: [
       {
         flags: {expose: true, update: true, compose: true},
 
@@ -133,11 +133,11 @@ export class HomepageLayoutAlbumsRow extends HomepageLayoutRow {
       }),
 
       exposeDependency({dependency: '#resolvedReference'}),
-    ]),
+    ],
 
     sourceAlbums: referenceList({
-      class: Album,
-      find: find.album,
+      class: input.value(Album),
+      find: input.value(find.album),
       data: 'albumData',
     }),
 
diff --git a/src/data/things/index.js b/src/data/things/index.js
index 4d8d9d1..f908653 100644
--- a/src/data/things/index.js
+++ b/src/data/things/index.js
@@ -135,7 +135,12 @@ function evaluatePropertyDescriptors() {
 
       for (const [key, value] of Object.entries(results)) {
         if (Array.isArray(value)) {
-          results[key] = compositeFrom(`${constructor.name}.${key}`, value);
+          results[key] = compositeFrom({
+            annotation: `${constructor.name}.${key}`,
+            compose: false,
+            steps: value,
+          });
+
           continue;
         }
       }
diff --git a/src/data/things/thing.js b/src/data/things/thing.js
index cff2f49..a75ff3e 100644
--- a/src/data/things/thing.js
+++ b/src/data/things/thing.js
@@ -211,7 +211,7 @@ export function contributionList() {
 
     update: {validate: isContributionList},
 
-    steps: () => [
+    steps: [
       withResolvedContribs({from: input.updateValue()}),
       exposeDependencyOrContinue({dependency: '#resolvedContribs'}),
       exposeConstant({value: []}),
@@ -468,8 +468,6 @@ export const withResolvedContribs = templateCompositeFrom({
     // todo: validate
     from: input(),
 
-    findFunction: input({type: 'function'}),
-
     notFoundMode: input({
       validate: oneOf('exit', 'filter', 'null'),
       defaultValue: 'null',
@@ -496,7 +494,7 @@ export const withResolvedContribs = templateCompositeFrom({
     withResolvedReferenceList({
       list: '#contribs.who',
       data: 'artistData',
-      find: input('find'),
+      find: input.value(find.artist),
       notFoundMode: input('notFoundMode'),
     }).outputs({
       ['#resolvedReferenceList']: '#contribs.who',
@@ -728,7 +726,7 @@ export const withReverseReferenceList = templateCompositeFrom({
   steps: () => [
     exitWithoutDependency({
       dependency: input('data'),
-      value: [],
+      value: input.value([]),
     }),
 
     {
diff --git a/src/data/things/track.js b/src/data/things/track.js
index 37b3628..05b762b 100644
--- a/src/data/things/track.js
+++ b/src/data/things/track.js
@@ -6,6 +6,7 @@ import {empty} from '#sugar';
 
 import {
   exitWithoutDependency,
+  excludeFromList,
   exposeConstant,
   exposeDependency,
   exposeDependencyOrContinue,
@@ -17,6 +18,7 @@ import {
 } from '#composite';
 
 import {
+  isBoolean,
   isColor,
   isContributionList,
   isDate,
@@ -136,7 +138,11 @@ export class Track extends Thing {
     // is specified, this value is null.
     coverArtDate: [
       withHasUniqueCoverArt(),
-      exitWithoutDependency({dependency: '#hasUniqueCoverArt', mode: 'falsy'}),
+
+      exitWithoutDependency({
+        dependency: '#hasUniqueCoverArt',
+        mode: input.value('falsy'),
+      }),
 
       exposeUpdateValueOrContinue({
         validate: input.value(isDate),
@@ -154,8 +160,8 @@ export class Track extends Thing {
     midiProjectFiles: additionalFiles(),
 
     originalReleaseTrack: singleReference({
-      class: Track,
-      find: find.track,
+      class: input.value(Track),
+      find: input.value(find.track),
       data: 'trackData',
     }),
 
@@ -163,8 +169,8 @@ export class Track extends Thing {
     // util.inspect display, if it isn't indirectly available (by way of being
     // included in an album's track list).
     dataSourceAlbum: singleReference({
-      class: Album,
-      find: find.album,
+      class: input.value(Album),
+      find: input.value(find.album),
       data: 'albumData',
     }),
 
@@ -208,25 +214,27 @@ export class Track extends Thing {
 
     referencedTracks: [
       inheritFromOriginalRelease({property: 'referencedTracks'}),
+
       referenceList({
-        class: Track,
-        find: find.track,
+        class: input.value(Track),
+        find: input.value(find.track),
         data: 'trackData',
       }),
     ],
 
     sampledTracks: [
       inheritFromOriginalRelease({property: 'sampledTracks'}),
+
       referenceList({
-        class: Track,
-        find: find.track,
+        class: input.value(Track),
+        find: input.value(find.track),
         data: 'trackData',
       }),
     ],
 
     artTags: referenceList({
-      class: ArtTag,
-      find: find.artTag,
+      class: input.value(ArtTag),
+      find: input.value(find.artTag),
       data: 'artTagData',
     }),
 
@@ -266,8 +274,14 @@ export class Track extends Thing {
     ],
 
     otherReleases: [
-      exitWithoutDependency({dependency: 'trackData', mode: 'empty'}),
-      withOriginalRelease({selfIfOriginal: true}),
+      exitWithoutDependency({
+        dependency: 'trackData',
+        mode: input.value('empty'),
+      }),
+
+      withOriginalRelease({
+        selfIfOriginal: input.value(true),
+      }),
 
       {
         flags: {expose: true},
@@ -594,14 +608,14 @@ export const withHasUniqueCoverArt = templateCompositeFrom({
           : continuation()),
     },
 
-    withResolvedContribs
-      .inputs({from: 'coverArtistContribs'})
-      .outputs({into: '#coverArtistContribs'}),
+    withResolvedContribs({
+      from: 'coverArtistContribs',
+    }),
 
     {
-      dependencies: ['#coverArtistContribs'],
+      dependencies: ['#resolvedContribs'],
       compute: (continuation, {
-        ['#coverArtistContribs']: contribsFromTrack,
+        ['#resolvedContribs']: contribsFromTrack,
       }) =>
         (empty(contribsFromTrack)
           ? continuation()
@@ -640,7 +654,7 @@ export const exitWithoutUniqueCoverArt = templateCompositeFrom({
 
     exitWithoutDependency({
       dependency: '#hasUniqueCoverArt',
-      mode: 'falsy',
+      mode: input.value('falsy'),
       value: input('value'),
     }),
   ],
diff --git a/src/data/things/wiki-info.js b/src/data/things/wiki-info.js
index 7c2de32..c764b52 100644
--- a/src/data/things/wiki-info.js
+++ b/src/data/things/wiki-info.js
@@ -1,3 +1,4 @@
+import {input} from '#composite';
 import find from '#find';
 import {isLanguageCode, isName, isURL} from '#validators';
 
@@ -45,8 +46,8 @@ export class WikiInfo extends Thing {
     },
 
     divideTrackListsByGroups: referenceList({
-      class: Group,
-      find: find.group,
+      class: input.value(Group),
+      find: input.value(find.group),
       data: 'groupData',
     }),