« get me outta code hell

data: break up content.js, flash.js, sorting-rule.js - hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/data/things/flash
diff options
context:
space:
mode:
author(quasar) nebula <qznebula@protonmail.com>2026-01-26 14:07:13 -0400
committer(quasar) nebula <qznebula@protonmail.com>2026-01-26 14:07:13 -0400
commit1f37e5d6b0c6fccc9c46aabd7bd402375131d452 (patch)
treee441757a73dd2b2cb346ce33b90bf185c614fe7c /src/data/things/flash
parentaa3cb2dd34780fd97873340c3faf7388993fa8d8 (diff)
data: break up content.js, flash.js, sorting-rule.js
Diffstat (limited to 'src/data/things/flash')
-rw-r--r--src/data/things/flash/Flash.js246
-rw-r--r--src/data/things/flash/FlashAct.js74
-rw-r--r--src/data/things/flash/FlashSide.js136
-rw-r--r--src/data/things/flash/index.js3
4 files changed, 459 insertions, 0 deletions
diff --git a/src/data/things/flash/Flash.js b/src/data/things/flash/Flash.js
new file mode 100644
index 00000000..1f290b3f
--- /dev/null
+++ b/src/data/things/flash/Flash.js
@@ -0,0 +1,246 @@
+import {input, V} from '#composite';
+import Thing from '#thing';
+import {anyOf, isColor, isDirectory, isNumber, isString}
+  from '#validators';
+
+import {
+  parseArtwork,
+  parseAdditionalNames,
+  parseCommentary,
+  parseContributors,
+  parseCreditingSources,
+  parseDate,
+  parseDimensions,
+} from '#yaml';
+
+import {withPropertyFromObject} from '#composite/data';
+
+import {
+  exposeConstant,
+  exposeDependency,
+  exposeUpdateValueOrContinue,
+} from '#composite/control-flow';
+
+import {
+  commentatorArtists,
+  constitutibleArtwork,
+  contributionList,
+  dimensions,
+  fileExtension,
+  name,
+  referenceList,
+  simpleDate,
+  soupyFind,
+  soupyReverse,
+  thing,
+  thingList,
+  urls,
+} from '#composite/wiki-properties';
+
+export class Flash extends Thing {
+  static [Thing.referenceType] = 'flash';
+  static [Thing.wikiData] = 'flashData';
+
+  static [Thing.constitutibleProperties] = [
+    'coverArtwork', // from inline fields
+  ];
+
+  static [Thing.getPropertyDescriptors] = ({
+    AdditionalName,
+    CommentaryEntry,
+    CreditingSourcesEntry,
+    FlashAct,
+    Track,
+    WikiInfo,
+  }) => ({
+    // Update & expose
+
+    act: thing(V(FlashAct)),
+
+    name: name(V('Unnamed Flash')),
+
+    directory: {
+      flags: {update: true, expose: true},
+      update: {validate: isDirectory},
+
+      // Flashes expose directory differently from other Things! Their
+      // default directory is dependent on the page number (or ID), not
+      // the name.
+      expose: {
+        dependencies: ['page'],
+        transform(directory, {page}) {
+          if (directory === null && page === null) return null;
+          else if (directory === null) return page;
+          else return directory;
+        },
+      },
+    },
+
+    page: {
+      flags: {update: true, expose: true},
+      update: {validate: anyOf(isString, isNumber)},
+
+      expose: {
+        transform: (value) => (value === null ? null : value.toString()),
+      },
+    },
+
+    color: [
+      exposeUpdateValueOrContinue({
+        validate: input.value(isColor),
+      }),
+
+      withPropertyFromObject('act', V('color')),
+      exposeDependency('#act.color'),
+    ],
+
+    date: simpleDate(),
+
+    coverArtFileExtension: fileExtension(V('jpg')),
+
+    coverArtDimensions: dimensions(),
+
+    coverArtwork:
+      constitutibleArtwork.fromYAMLFieldSpec
+        .call(this, 'Cover Artwork'),
+
+    contributorContribs: contributionList({
+      artistProperty: input.value('flashContributorContributions'),
+    }),
+
+    featuredTracks: referenceList({
+      class: input.value(Track),
+      find: soupyFind.input('track'),
+    }),
+
+    urls: urls(),
+
+    additionalNames: thingList(V(AdditionalName)),
+
+    commentary: thingList(V(CommentaryEntry)),
+    creditingSources: thingList(V(CreditingSourcesEntry)),
+
+    // Update only
+
+    find: soupyFind(),
+    reverse: soupyReverse(),
+
+    // used for withMatchingContributionPresets (indirectly by Contribution)
+    wikiInfo: thing(V(WikiInfo)),
+
+    // Expose only
+
+    isFlash: exposeConstant(V(true)),
+
+    commentatorArtists: commentatorArtists(),
+
+    side: [
+      withPropertyFromObject('act', V('side')),
+      exposeDependency('#act.side'),
+    ],
+  });
+
+  static [Thing.getSerializeDescriptors] = ({
+    serialize: S,
+  }) => ({
+    name: S.id,
+    page: S.id,
+    directory: S.id,
+    date: S.id,
+    contributors: S.toContribRefs,
+    tracks: S.toRefs,
+    urls: S.id,
+    color: S.id,
+  });
+
+  static [Thing.findSpecs] = {
+    flash: {
+      referenceTypes: ['flash'],
+      bindTo: 'flashData',
+    },
+  };
+
+  static [Thing.reverseSpecs] = {
+    flashesWhichFeature: {
+      bindTo: 'flashData',
+
+      referencing: flash => [flash],
+      referenced: flash => flash.featuredTracks,
+    },
+
+    flashContributorContributionsBy:
+      soupyReverse.contributionsBy('flashData', 'contributorContribs'),
+
+    flashesWithCommentaryBy: {
+      bindTo: 'flashData',
+
+      referencing: flash => [flash],
+      referenced: flash => flash.commentatorArtists,
+    },
+  };
+
+  static [Thing.yamlDocumentSpec] = {
+    fields: {
+      'Flash': {property: 'name'},
+      'Directory': {property: 'directory'},
+      'Page': {property: 'page'},
+      'Color': {property: 'color'},
+      'URLs': {property: 'urls'},
+
+      'Date': {
+        property: 'date',
+        transform: parseDate,
+      },
+
+      'Additional Names': {
+        property: 'additionalNames',
+        transform: parseAdditionalNames,
+      },
+
+      'Cover Artwork': {
+        property: 'coverArtwork',
+        transform:
+          parseArtwork({
+            single: true,
+            thingProperty: 'coverArtwork',
+            fileExtensionFromThingProperty: 'coverArtFileExtension',
+            dimensionsFromThingProperty: 'coverArtDimensions',
+          }),
+      },
+
+      'Cover Art File Extension': {property: 'coverArtFileExtension'},
+
+      'Cover Art Dimensions': {
+        property: 'coverArtDimensions',
+        transform: parseDimensions,
+      },
+
+      'Featured Tracks': {property: 'featuredTracks'},
+
+      'Contributors': {
+        property: 'contributorContribs',
+        transform: parseContributors,
+      },
+
+      'Commentary': {
+        property: 'commentary',
+        transform: parseCommentary,
+      },
+
+      'Crediting Sources': {
+        property: 'creditingSources',
+        transform: parseCreditingSources,
+      },
+
+      'Review Points': {ignore: true},
+    },
+  };
+
+  getOwnArtworkPath(artwork) {
+    return [
+      'media.flashArt',
+      this.directory,
+      artwork.fileExtension,
+    ];
+  }
+}
diff --git a/src/data/things/flash/FlashAct.js b/src/data/things/flash/FlashAct.js
new file mode 100644
index 00000000..66d4ee1b
--- /dev/null
+++ b/src/data/things/flash/FlashAct.js
@@ -0,0 +1,74 @@
+
+import {input, V} from '#composite';
+import Thing from '#thing';
+import {isContentString} from '#validators';
+
+import {withPropertyFromObject} from '#composite/data';
+import {exposeConstant, exposeDependency, exposeUpdateValueOrContinue}
+  from '#composite/control-flow';
+import {color, directory, name, soupyFind, soupyReverse, thing, thingList}
+  from '#composite/wiki-properties';
+
+export class FlashAct extends Thing {
+  static [Thing.referenceType] = 'flash-act';
+  static [Thing.friendlyName] = `Flash Act`;
+  static [Thing.wikiData] = 'flashActData';
+
+  static [Thing.getPropertyDescriptors] = ({Flash, FlashSide}) => ({
+    // Update & expose
+
+    side: thing(V(FlashSide)),
+
+    name: name(V('Unnamed Flash Act')),
+    directory: directory(),
+    color: color(),
+
+    listTerminology: [
+      exposeUpdateValueOrContinue({
+        validate: input.value(isContentString),
+      }),
+
+      withPropertyFromObject('side', V('listTerminology')),
+      exposeDependency('#side.listTerminology'),
+    ],
+
+    flashes: thingList(V(Flash)),
+
+    // Update only
+
+    find: soupyFind(),
+    reverse: soupyReverse(),
+
+    // Expose only
+
+    isFlashAct: exposeConstant(V(true)),
+  });
+
+  static [Thing.findSpecs] = {
+    flashAct: {
+      referenceTypes: ['flash-act'],
+      bindTo: 'flashActData',
+    },
+  };
+
+  static [Thing.reverseSpecs] = {
+    flashActsWhoseFlashesInclude: {
+      bindTo: 'flashActData',
+
+      referencing: flashAct => [flashAct],
+      referenced: flashAct => flashAct.flashes,
+    },
+  };
+
+  static [Thing.yamlDocumentSpec] = {
+    fields: {
+      'Act': {property: 'name'},
+      'Directory': {property: 'directory'},
+
+      'Color': {property: 'color'},
+      'List Terminology': {property: 'listTerminology'},
+
+      'Review Points': {ignore: true},
+    },
+  };
+}
diff --git a/src/data/things/flash/FlashSide.js b/src/data/things/flash/FlashSide.js
new file mode 100644
index 00000000..72782bdd
--- /dev/null
+++ b/src/data/things/flash/FlashSide.js
@@ -0,0 +1,136 @@
+const FLASH_DATA_FILE = 'flashes.yaml';
+
+import {V} from '#composite';
+import {sortFlashesChronologically} from '#sort';
+import Thing from '#thing';
+
+import {exposeConstant} from '#composite/control-flow';
+import {color, contentString, directory, name, soupyFind, thingList}
+  from '#composite/wiki-properties';
+
+export class FlashSide extends Thing {
+  static [Thing.referenceType] = 'flash-side';
+  static [Thing.friendlyName] = `Flash Side`;
+  static [Thing.wikiData] = 'flashSideData';
+
+  static [Thing.getPropertyDescriptors] = ({FlashAct}) => ({
+    // Update & expose
+
+    name: name(V('Unnamed Flash Side')),
+    directory: directory(),
+    color: color(),
+    listTerminology: contentString(),
+
+    acts: thingList(V(FlashAct)),
+
+    // Update only
+
+    find: soupyFind(),
+
+    // Expose only
+
+    isFlashSide: exposeConstant(V(true)),
+  });
+
+  static [Thing.yamlDocumentSpec] = {
+    fields: {
+      'Side': {property: 'name'},
+      'Directory': {property: 'directory'},
+      'Color': {property: 'color'},
+      'List Terminology': {property: 'listTerminology'},
+    },
+  };
+
+  static [Thing.findSpecs] = {
+    flashSide: {
+      referenceTypes: ['flash-side'],
+      bindTo: 'flashSideData',
+    },
+  };
+
+  static [Thing.reverseSpecs] = {
+    flashSidesWhoseActsInclude: {
+      bindTo: 'flashSideData',
+
+      referencing: flashSide => [flashSide],
+      referenced: flashSide => flashSide.acts,
+    },
+  };
+
+  static [Thing.getYamlLoadingSpec] = ({
+    documentModes: {allInOne},
+    thingConstructors: {Flash, FlashAct},
+  }) => ({
+    title: `Process flashes file`,
+    file: FLASH_DATA_FILE,
+
+    documentMode: allInOne,
+    documentThing: document =>
+      ('Side' in document
+        ? FlashSide
+     : 'Act' in document
+        ? FlashAct
+        : Flash),
+
+    connect(results) {
+      let thing, i;
+
+      for (i = 0; thing = results[i]; i++) {
+        if (thing.isFlashSide) {
+          const side = thing;
+          const acts = [];
+
+          for (i++; thing = results[i]; i++) {
+            if (thing.isFlashAct) {
+              const act = thing;
+              const flashes = [];
+
+              for (i++; thing = results[i]; i++) {
+                if (thing.isFlash) {
+                  const flash = thing;
+
+                  flash.act = act;
+                  flashes.push(flash);
+
+                  continue;
+                }
+
+                i--;
+                break;
+              }
+
+              act.side = side;
+              act.flashes = flashes;
+              acts.push(act);
+
+              continue;
+            }
+
+            if (thing.isFlash) {
+              throw new Error(`Flashes must be under an act`);
+            }
+
+            i--;
+            break;
+          }
+
+          side.acts = acts;
+
+          continue;
+        }
+
+        if (thing.isFlashAct) {
+          throw new Error(`Acts must be under a side`);
+        }
+
+        if (thing.isFlash) {
+          throw new Error(`Flashes must be under a side and act`);
+        }
+      }
+    },
+
+    sort({flashData}) {
+      sortFlashesChronologically(flashData);
+    },
+  });
+}
diff --git a/src/data/things/flash/index.js b/src/data/things/flash/index.js
new file mode 100644
index 00000000..19b8cc34
--- /dev/null
+++ b/src/data/things/flash/index.js
@@ -0,0 +1,3 @@
+export * from './Flash.js';
+export * from './FlashAct.js';
+export * from './FlashSide.js';