« get me outta code hell

data, content: additional file artists - hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/data/things/additional-file
diff options
context:
space:
mode:
author(quasar) nebula <qznebula@protonmail.com>2026-05-19 21:52:18 -0300
committer(quasar) nebula <qznebula@protonmail.com>2026-05-19 21:52:18 -0300
commite56b564efe888e028e4b01891d9074e8532360d2 (patch)
tree4525dd2a274f8320d94be5cfbf1b1ad8586420d2 /src/data/things/additional-file
parente518aba281c2deca085bcb1245f8da5448f28981 (diff)
data, content: additional file artists preview
Diffstat (limited to 'src/data/things/additional-file')
-rw-r--r--src/data/things/additional-file/AdditionalFile.js109
-rw-r--r--src/data/things/additional-file/MidiProjectFile.js28
-rw-r--r--src/data/things/additional-file/MiscellaneousAdditionalFile.js28
-rw-r--r--src/data/things/additional-file/SheetMusicFile.js28
-rw-r--r--src/data/things/additional-file/index.js5
5 files changed, 198 insertions, 0 deletions
diff --git a/src/data/things/additional-file/AdditionalFile.js b/src/data/things/additional-file/AdditionalFile.js
new file mode 100644
index 00000000..d137c741
--- /dev/null
+++ b/src/data/things/additional-file/AdditionalFile.js
@@ -0,0 +1,109 @@
+import {inspect} from 'node:util';
+
+import {colors} from '#cli';
+import {input, V} from '#composite';
+import Thing from '#thing';
+import {isString, validateArrayItems} from '#validators';
+import {parseContributors} from '#yaml';
+
+import {exposeConstant, exposeUpdateValueOrContinue}
+  from '#composite/control-flow';
+import {contributionList, contentString, simpleString, soupyFind, thing}
+  from '#composite/wiki-properties';
+
+export class AdditionalFile extends Thing {
+  static [Thing.friendlyName] = `Additional File`;
+
+  static [Thing.getPropertyDescriptors] = () => ({
+    // Update & expose
+
+    thing: thing(),
+
+    title: simpleString(),
+
+    description: contentString(),
+
+    folder: simpleString(),
+
+    filenames: [
+      exposeUpdateValueOrContinue({
+        validate: input.value(validateArrayItems(isString)),
+      }),
+
+      exposeConstant(V([])),
+    ],
+
+    artistContribs: contributionList({
+      // Subclasses override with the relevant artistProperty.
+      artistProperty: input.value(null),
+    }),
+
+    // Update only
+
+    find: soupyFind(),
+
+    // Expose only
+
+    isAdditionalFile: exposeConstant(V(true)),
+
+    // The date property is generally expected by contributions.
+    // Additional files don't actually support dates, but provide a null
+    // value for convenience.
+    date: {
+      flags: {expose: true},
+      expose: {compute: () => null},
+    },
+  });
+
+  static [Thing.yamlDocumentSpec] = {
+    fields: {
+      'Title': {property: 'title'},
+      'Description': {property: 'description'},
+
+      'Artists': {
+        property: 'artistContribs',
+        transform: parseContributors,
+      },
+
+      'Folder': {property: 'folder'},
+      'Files': {property: 'filenames'},
+    },
+  };
+
+  get paths() {
+    if (!this.thing) return null;
+    if (!this.thing.getOwnAdditionalFilePath) return null;
+
+    return (
+      this.filenames.map(filename =>
+        this.thing.getOwnAdditionalFilePath(this, filename)));
+  }
+
+  [inspect.custom](depth, options, inspect) {
+    const parts = [];
+
+    parts.push(this.constructor.name);
+
+    if (this.title) {
+      parts.push(` ${colors.green(`"${this.title}"`)}`);
+    }
+
+    if (this.thing) {
+      if (depth >= 0) {
+        const newOptions = {
+          ...options,
+          depth:
+            (options.depth === null
+              ? null
+              : options.depth - 1),
+        };
+
+        parts.push(` for ${inspect(this.thing, newOptions)}`);
+      } else {
+        parts.push(` for ${colors.blue(Thing.inspectReference(this.thing))}`);
+      }
+    }
+
+    return parts.join('');
+  }
+}
diff --git a/src/data/things/additional-file/MidiProjectFile.js b/src/data/things/additional-file/MidiProjectFile.js
new file mode 100644
index 00000000..8e7c19ca
--- /dev/null
+++ b/src/data/things/additional-file/MidiProjectFile.js
@@ -0,0 +1,28 @@
+import {input, V} from '#composite';
+import Thing from '#thing';
+
+import {exposeConstant} from '#composite/control-flow';
+import {contributionList, soupyReverse} from '#composite/wiki-properties';
+
+import {AdditionalFile} from './AdditionalFile.js';
+
+export class MidiProjectFile extends AdditionalFile {
+  static [Thing.wikiData] = 'midiProjectFileData';
+
+  static [Thing.getPropertyDescriptors] = () => ({
+    // Update & expose
+
+    artistContribs: contributionList({
+      artistProperty: input.value('midiProjectFileArtistContributions'),
+    }),
+
+    // Expose only
+
+    isMidiProjectFile: exposeConstant(V(true)),
+  });
+
+  static [Thing.reverseSpecs] = {
+    midiProjectFileArtistContributionsBy:
+      soupyReverse.contributionsBy('midiProjectFileData', 'artistContribs'),
+  };
+}
diff --git a/src/data/things/additional-file/MiscellaneousAdditionalFile.js b/src/data/things/additional-file/MiscellaneousAdditionalFile.js
new file mode 100644
index 00000000..0110f830
--- /dev/null
+++ b/src/data/things/additional-file/MiscellaneousAdditionalFile.js
@@ -0,0 +1,28 @@
+import {input, V} from '#composite';
+import Thing from '#thing';
+
+import {exposeConstant} from '#composite/control-flow';
+import {contributionList, soupyReverse} from '#composite/wiki-properties';
+
+import {AdditionalFile} from './AdditionalFile.js';
+
+export class MiscellaneousAdditionalFile extends AdditionalFile {
+  static [Thing.wikiData] = 'miscellaneousAdditionalFileData';
+
+  static [Thing.getPropertyDescriptors] = () => ({
+    // Update & expose
+
+    artistContribs: contributionList({
+      artistProperty: input.value('miscellaneousAdditionalFileArtistContributions'),
+    }),
+
+    // Expose only
+
+    isMiscellaneousAdditionalFile: exposeConstant(V(true)),
+  });
+
+  static [Thing.reverseSpecs] = {
+    miscellaneousAdditionalFileArtistContributionsBy:
+      soupyReverse.contributionsBy('miscellaneousAdditionalFileData', 'artistContribs'),
+  };
+}
diff --git a/src/data/things/additional-file/SheetMusicFile.js b/src/data/things/additional-file/SheetMusicFile.js
new file mode 100644
index 00000000..c06cde7f
--- /dev/null
+++ b/src/data/things/additional-file/SheetMusicFile.js
@@ -0,0 +1,28 @@
+import {input, V} from '#composite';
+import Thing from '#thing';
+
+import {exposeConstant} from '#composite/control-flow';
+import {contributionList, soupyReverse} from '#composite/wiki-properties';
+
+import {AdditionalFile} from './AdditionalFile.js';
+
+export class SheetMusicFile extends AdditionalFile {
+  static [Thing.wikiData] = 'sheetMusicFileData';
+
+  static [Thing.getPropertyDescriptors] = () => ({
+    // Update & expose
+
+    artistContribs: contributionList({
+      artistProperty: input.value('sheetMusicFileArtistContributions'),
+    }),
+
+    // Expose only
+
+    isSheetMusicFile: exposeConstant(V(true)),
+  });
+
+  static [Thing.reverseSpecs] = {
+    sheetMusicFileArtistContributionsBy:
+      soupyReverse.contributionsBy('sheetMusicFileData', 'artistContribs'),
+  };
+}
diff --git a/src/data/things/additional-file/index.js b/src/data/things/additional-file/index.js
new file mode 100644
index 00000000..d8de7455
--- /dev/null
+++ b/src/data/things/additional-file/index.js
@@ -0,0 +1,5 @@
+export * from './AdditionalFile.js';
+
+export * from './MidiProjectFile.js';
+export * from './MiscellaneousAdditionalFile.js';
+export * from './SheetMusicFile.js'