« get me outta code hell

hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/data/composite/things/contribution/index.js1
-rw-r--r--src/data/composite/things/contribution/withContributionArtist.js31
-rw-r--r--src/data/composite/wiki-data/withResolvedContribs.js57
-rw-r--r--src/data/things/contribution.js97
-rw-r--r--src/data/things/index.js2
5 files changed, 169 insertions, 19 deletions
diff --git a/src/data/composite/things/contribution/index.js b/src/data/composite/things/contribution/index.js
new file mode 100644
index 00000000..c0506a2b
--- /dev/null
+++ b/src/data/composite/things/contribution/index.js
@@ -0,0 +1 @@
+export {default as withContributionArtist} from './withContributionArtist.js';
diff --git a/src/data/composite/things/contribution/withContributionArtist.js b/src/data/composite/things/contribution/withContributionArtist.js
new file mode 100644
index 00000000..9e588936
--- /dev/null
+++ b/src/data/composite/things/contribution/withContributionArtist.js
@@ -0,0 +1,31 @@
+import {input, templateCompositeFrom} from '#composite';
+import find from '#find';
+
+import {withPropertyFromObject} from '#composite/data';
+import {withResolvedReference} from '#composite/wiki-data';
+
+export default templateCompositeFrom({
+  annotation: `withOwnContributionArtist`,
+
+  inputs: {
+    ref: input({type: 'string'}),
+  },
+
+  outputs: ['#artist'],
+
+  steps: () => [
+    withPropertyFromObject({
+      object: 'thing',
+      property: input.value('artistData'),
+      internal: input.value(true),
+    }),
+
+    withResolvedReference({
+      ref: input('ref'),
+      data: '#thing.artistData',
+      find: input.value(find.artist),
+    }).outputs({
+      '#resolvedReference': '#artist',
+    }),
+  ],
+});
diff --git a/src/data/composite/wiki-data/withResolvedContribs.js b/src/data/composite/wiki-data/withResolvedContribs.js
index 95266382..7ff7b1bc 100644
--- a/src/data/composite/wiki-data/withResolvedContribs.js
+++ b/src/data/composite/wiki-data/withResolvedContribs.js
@@ -7,17 +7,11 @@
 import {input, templateCompositeFrom} from '#composite';
 import find from '#find';
 import {filterMultipleArrays, stitchArrays} from '#sugar';
+import thingConstructors from '#things';
 import {is, isContributionList} from '#validators';
 
-import {
-  raiseOutputWithoutDependency,
-} from '#composite/control-flow';
-
-import {
-  withPropertiesFromList,
-} from '#composite/data';
-
-import withResolvedReferenceList from './withResolvedReferenceList.js';
+import {raiseOutputWithoutDependency} from '#composite/control-flow';
+import {withPropertiesFromList} from '#composite/data';
 
 export default templateCompositeFrom({
   annotation: `withResolvedContribs`,
@@ -51,15 +45,6 @@ export default templateCompositeFrom({
       prefix: input.value('#contribs'),
     }),
 
-    withResolvedReferenceList({
-      list: '#contribs.artist',
-      data: 'artistData',
-      find: input.value(find.artist),
-      notFoundMode: input('notFoundMode'),
-    }).outputs({
-      ['#resolvedReferenceList']: '#contribs.artist',
-    }),
-
     {
       dependencies: ['#contribs.artist', '#contribs.annotation'],
 
@@ -68,11 +53,45 @@ export default templateCompositeFrom({
         ['#contribs.annotation']: annotation,
       }) {
         filterMultipleArrays(artist, annotation, (artist, _annotation) => artist);
+
         return continuation({
-          ['#resolvedContribs']:
+          ['#details']:
             stitchArrays({artist, annotation}),
         });
       },
     },
+
+    {
+      dependencies: ['#details', input.myself()],
+
+      compute: (continuation, {
+        ['#details']: details,
+        [input.myself()]: myself,
+      }) => continuation({
+        ['#contributions']:
+          details.map(details => {
+            const contrib = new thingConstructors.Contribution();
+
+            Object.assign(contrib, {
+              ...details,
+              thing: myself,
+            });
+
+            return contrib;
+          }),
+      }),
+    },
+
+    {
+      dependencies: ['#contributions'],
+
+      compute: (continuation, {
+        ['#contributions']: contributions,
+      }) => continuation({
+        ['#resolvedContribs']:
+          contributions
+            .filter(contrib => contrib.artist),
+      }),
+    },
   ],
 });
diff --git a/src/data/things/contribution.js b/src/data/things/contribution.js
new file mode 100644
index 00000000..dc7f2157
--- /dev/null
+++ b/src/data/things/contribution.js
@@ -0,0 +1,97 @@
+import {inspect} from 'node:util';
+
+import CacheableObject from '#cacheable-object';
+import {colors} from '#cli';
+import {input} from '#composite';
+import {empty} from '#sugar';
+import Thing from '#thing';
+import {isStringNonEmpty, isThing, validateReference} from '#validators';
+
+import {exposeDependency} from '#composite/control-flow';
+import {withResolvedReference} from '#composite/wiki-data';
+
+import {withContributionArtist} from '#composite/things/contribution';
+
+export class Contribution extends Thing {
+  static [Thing.getPropertyDescriptors] = () => ({
+    // Update & expose
+
+    thing: {
+      flags: {update: true, expose: true},
+      update: {validate: isThing},
+    },
+
+    artist: [
+      withContributionArtist({
+        ref: input.updateValue({
+          validate: validateReference('artist'),
+        }),
+      }),
+
+      exposeDependency({
+        dependency: '#artist',
+      }),
+    ],
+
+    annotation: {
+      flags: {update: true, expose: true},
+      update: {validate: isStringNonEmpty},
+    },
+  });
+
+  [inspect.custom](depth, options, inspect) {
+    const parts = [];
+    const accentParts = [];
+
+    parts.push(Thing.prototype[inspect.custom].apply(this));
+
+    if (this.annotation) {
+      accentParts.push(colors.green(`"${this.annotation}"`));
+    }
+
+    let artistRef;
+    if (depth >= 0) {
+      let artist;
+      try {
+        artist = this.artist;
+      } catch (_error) {
+        // Computing artist might crash for any reason - don't distract from
+        // other errors as a result of inspecting this contribution.
+      }
+
+      if (artist) {
+        artistRef =
+          colors.blue(Thing.getReference(artist));
+      }
+    } else {
+      artistRef =
+        colors.green(CacheableObject.getUpdateValue(this, 'artist'));
+    }
+
+    if (artistRef) {
+      accentParts.push(`by ${artistRef}`);
+    }
+
+    if (this.thing) {
+      if (depth >= 0) {
+        const newOptions = {
+          ...options,
+          depth:
+            (options.depth === null
+              ? null
+              : options.depth - 1),
+        };
+
+        accentParts.push(`to ${inspect(this.thing, newOptions)}`);
+      } else {
+        accentParts.push(`to ${colors.blue(Thing.getReference(this.thing))}`);
+      }
+    }
+
+    if (!empty(accentParts)) {
+      parts.push(` (${accentParts.join(', ')})`);
+    }
+
+    return parts.join('');
+  }
+}
diff --git a/src/data/things/index.js b/src/data/things/index.js
index 4f87f492..f18e283a 100644
--- a/src/data/things/index.js
+++ b/src/data/things/index.js
@@ -11,6 +11,7 @@ import Thing from '#thing';
 import * as albumClasses from './album.js';
 import * as artTagClasses from './art-tag.js';
 import * as artistClasses from './artist.js';
+import * as contributionClasses from './contribution.js';
 import * as flashClasses from './flash.js';
 import * as groupClasses from './group.js';
 import * as homepageLayoutClasses from './homepage-layout.js';
@@ -24,6 +25,7 @@ const allClassLists = {
   'album.js': albumClasses,
   'art-tag.js': artTagClasses,
   'artist.js': artistClasses,
+  'contribution.js': contributionClasses,
   'flash.js': flashClasses,
   'group.js': groupClasses,
   'homepage-layout.js': homepageLayoutClasses,