« get me outta code hell

hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/data
diff options
context:
space:
mode:
Diffstat (limited to 'src/data')
-rw-r--r--src/data/checks.js3
-rw-r--r--src/data/thing.js8
-rw-r--r--src/data/things/artist.js61
-rw-r--r--src/data/things/language.js10
-rw-r--r--src/data/things/track.js23
-rw-r--r--src/data/yaml.js24
6 files changed, 81 insertions, 48 deletions
diff --git a/src/data/checks.js b/src/data/checks.js
index e68b2ed0..fd2c4931 100644
--- a/src/data/checks.js
+++ b/src/data/checks.js
@@ -60,7 +60,7 @@ export function reportDirectoryErrors(wikiData, {
           : [thing.directory]);
 
       for (const directory of directories) {
-        if (directory === null || directory === undefined) {
+        if (directory === '' || directory === null || directory === undefined) {
           missingDirectoryThings.add(thing);
           continue;
         }
@@ -297,6 +297,7 @@ export function filterReferenceErrors(wikiData, {
       artistContribs: '_contrib',
       contributorContribs: '_contrib',
       coverArtistContribs: '_contrib',
+      previousProductionTracks: '_trackMainReleasesOnly',
       referencedTracks: '_trackMainReleasesOnly',
       sampledTracks: '_trackMainReleasesOnly',
       artTags: '_artTag',
diff --git a/src/data/thing.js b/src/data/thing.js
index f719224d..4fbad5f5 100644
--- a/src/data/thing.js
+++ b/src/data/thing.js
@@ -84,7 +84,13 @@ export default class Thing extends CacheableObject {
     }
 
     if (!thing.directory) {
-      throw TypeError(`Passed ${thing.constructor.name} is missing its directory`);
+      if (thing.name) {
+        throw TypeError(
+          `Passed ${thing.constructor.name} (named ${inspect(thing.name)}) ` +
+          `is missing its directory`);
+      } else {
+        throw TypeError(`Passed ${thing.constructor.name} is missing its directory`);
+      }
     }
 
     return `${thing.constructor[Thing.referenceType]}:${thing.directory}`;
diff --git a/src/data/things/artist.js b/src/data/things/artist.js
index 2905d893..24c99698 100644
--- a/src/data/things/artist.js
+++ b/src/data/things/artist.js
@@ -7,9 +7,9 @@ import {colors} from '#cli';
 import {input} from '#composite';
 import {stitchArrays} from '#sugar';
 import Thing from '#thing';
-import {isName, validateArrayItems} from '#validators';
+import {validateArrayItems} from '#validators';
 import {getKebabCase} from '#wiki-data';
-import {parseArtwork} from '#yaml';
+import {parseArtistAliases, parseArtwork} from '#yaml';
 
 import {
   sortAlbumsTracksChronologically,
@@ -32,6 +32,8 @@ import {
   singleReference,
   soupyFind,
   soupyReverse,
+  thing,
+  thingList,
   urls,
 } from '#composite/wiki-properties';
 
@@ -63,17 +65,14 @@ export class Artist extends Thing {
         .call(this, 'Avatar Artwork'),
     ],
 
-    aliasNames: {
-      flags: {update: true, expose: true},
-      update: {validate: validateArrayItems(isName)},
-      expose: {transform: (names) => names ?? []},
-    },
-
     isAlias: flag(),
 
-    aliasedArtist: singleReference({
+    artistAliases: thingList({
+      class: input.value(Artist),
+    }),
+
+    aliasedArtist: thing({
       class: input.value(Artist),
-      find: soupyFind.input('artist'),
     }),
 
     // Update only
@@ -251,8 +250,6 @@ export class Artist extends Thing {
     hasAvatar: S.id,
     avatarFileExtension: S.id,
 
-    aliasNames: S.id,
-
     tracksAsCommentator: S.toRefs,
     albumsAsCommentator: S.toRefs,
   });
@@ -283,17 +280,9 @@ export class Artist extends Thing {
         // in the original's alias list. This is honestly a bit awkward, but it
         // avoids artist aliases conflicting with each other when checking for
         // duplicate directories.
-        for (const aliasName of originalArtist.aliasNames) {
-          // These are trouble. We should be accessing aliases' directories
-          // directly, but artists currently don't expose a reverse reference
-          // list for aliases. (This is pending a cleanup of "reverse reference"
-          // behavior in general.) It doesn't actually cause problems *here*
-          // because alias directories are computed from their names 100% of the
-          // time, but that *is* an assumption this code makes.
-          if (aliasName === artist.name) continue;
-          if (artist.directory === getKebabCase(aliasName)) {
-            return [];
-          }
+        for (const alias of originalArtist.artistAliases) {
+          if (alias === artist) break;
+          if (alias.directory === artist.directory) return [];
         }
 
         // And, aliases never return just a blank string. This part is pretty
@@ -333,7 +322,10 @@ export class Artist extends Thing {
       'Has Avatar': {property: 'hasAvatar'},
       'Avatar File Extension': {property: 'avatarFileExtension'},
 
-      'Aliases': {property: 'aliasNames'},
+      'Aliases': {
+        property: 'artistAliases',
+        transform: parseArtistAliases,
+      },
 
       'Dead URLs': {ignore: true},
 
@@ -353,26 +345,7 @@ export class Artist extends Thing {
 
     save(results) {
       const artists = results;
-
-      const artistRefs =
-        artists.map(artist => Thing.getReference(artist));
-
-      const artistAliasNames =
-        artists.map(artist => artist.aliasNames);
-
-      const artistAliases =
-        stitchArrays({
-          originalArtistRef: artistRefs,
-          aliasNames: artistAliasNames,
-        }).flatMap(({originalArtistRef, aliasNames}) =>
-            aliasNames.map(name => {
-              const alias = new Artist();
-              alias.name = name;
-              alias.isAlias = true;
-              alias.aliasedArtist = originalArtistRef;
-              return alias;
-            }));
-
+      const artistAliases = artists.flatMap(artist => artist.artistAliases);
       const artistData = [...artists, ...artistAliases];
 
       const artworkData =
diff --git a/src/data/things/language.js b/src/data/things/language.js
index 91774761..43f69f3d 100644
--- a/src/data/things/language.js
+++ b/src/data/things/language.js
@@ -354,13 +354,19 @@ export class Language extends Thing {
 
       partInProgress += template.slice(lastIndex, match.index);
 
-      for (const insertionItem of html.smush(insertion).content) {
+      const insertionItems = html.smush(insertion).content;
+      if (insertionItems.length === 1 && typeof insertionItems[0] !== 'string') {
+        // Push the insertion exactly as it is, rather than manipulating.
+        if (partInProgress) outputParts.push(partInProgress);
+        outputParts.push(insertion);
+        partInProgress = '';
+      } else for (const insertionItem of insertionItems) {
         if (typeof insertionItem === 'string') {
           // Join consecutive strings together.
           partInProgress += insertionItem;
         } else {
           // Push the string part in progress, then the insertion as-is.
-          outputParts.push(partInProgress);
+          if (partInProgress) outputParts.push(partInProgress);
           outputParts.push(insertionItem);
           partInProgress = '';
         }
diff --git a/src/data/things/track.js b/src/data/things/track.js
index 93193b6a..64790a61 100644
--- a/src/data/things/track.js
+++ b/src/data/things/track.js
@@ -393,6 +393,17 @@ export class Track extends Thing {
 
     // > Update & expose - Referenced tracks
 
+    previousProductionTracks: [
+      inheritFromMainRelease({
+        notFoundValue: input.value([]),
+      }),
+
+      referenceList({
+        class: input.value(Track),
+        find: soupyFind.input('trackMainReleasesOnly'),
+      }),
+    ],
+
     referencedTracks: [
       inheritFromMainRelease({
         notFoundValue: input.value([]),
@@ -563,6 +574,10 @@ export class Track extends Thing {
       }),
     ],
 
+    followingProductionTracks: reverseReferenceList({
+      reverse: soupyReverse.input('tracksWhichAreFollowingProductionsOf'),
+    }),
+
     referencedByTracks: reverseReferenceList({
       reverse: soupyReverse.input('tracksWhichReference'),
     }),
@@ -701,6 +716,7 @@ export class Track extends Thing {
 
       // Referenced tracks
 
+      'Previous Productions': {property: 'previousProductionTracks'},
       'Referenced Tracks': {property: 'referencedTracks'},
       'Sampled Tracks': {property: 'sampledTracks'},
 
@@ -912,6 +928,13 @@ export class Track extends Thing {
       referencing: track => track.isSecondaryRelease ? [track] : [],
       referenced: track => [track.mainReleaseTrack],
     },
+
+    tracksWhichAreFollowingProductionsOf: {
+      bindTo: 'trackData',
+
+      referencing: track => track,
+      referenced: track => track.previousProductionTracks,
+    },
   };
 
   // Track YAML loading is handled in album.js.
diff --git a/src/data/yaml.js b/src/data/yaml.js
index 46cb4eda..13dfd24d 100644
--- a/src/data/yaml.js
+++ b/src/data/yaml.js
@@ -982,6 +982,30 @@ export function parseLyrics(value, {subdoc, LyricsEntry}) {
   return parseContentEntries(LyricsEntry, value, {subdoc});
 }
 
+export function parseArtistAliases(value, {subdoc, Artist}) {
+  return parseArrayEntries(value, item => {
+    const config = {
+      bindInto: 'aliasedArtist',
+      provide: {isAlias: true},
+    };
+
+    if (typeof item === 'string') {
+      return subdoc(Artist, {'Artist': item}, config);
+    } else if (typeof item === 'object' && !Array.isArray(item)) {
+      if (item['Name']) {
+        const clone = {...item};
+        clone['Artist'] = item['Name'];
+        delete clone['Name'];
+        return subdoc(Artist, clone, config);
+      } else {
+        return subdoc(Artist, item, config);
+      }
+    } else {
+      return item;
+    }
+  });
+}
+
 // documentModes: Symbols indicating sets of behavior for loading and processing
 // data files.
 export const documentModes = {