« get me outta code hell

data: Track.directoryWithinAlbum - hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
author(quasar) nebula <qznebula@protonmail.com>2026-05-28 13:24:20 -0300
committer(quasar) nebula <qznebula@protonmail.com>2026-05-28 13:24:20 -0300
commit75e68aa1c8886e69d63a0e0b365fd6a7c309412c (patch)
treef90f1cb666634b774b3e9183a2d5729140418d0a /src
parent9dc7c08e2fa7a0303fda3b9a687b55425c594aef (diff)
data: Track.directoryWithinAlbum
Diffstat (limited to 'src')
-rw-r--r--src/data/composite/things/track/index.js1
-rw-r--r--src/data/composite/things/track/withDirectorySuffixes.js184
-rw-r--r--src/data/things/Track.js115
-rw-r--r--src/data/things/album/Album.js11
-rw-r--r--src/data/things/album/TrackSection.js16
5 files changed, 235 insertions, 92 deletions
diff --git a/src/data/composite/things/track/index.js b/src/data/composite/things/track/index.js
index c200df19..db982ea7 100644
--- a/src/data/composite/things/track/index.js
+++ b/src/data/composite/things/track/index.js
@@ -1,2 +1,3 @@
 export {default as inheritContributionListFromMainRelease} from './inheritContributionListFromMainRelease.js';
 export {default as inheritFromMainRelease} from './inheritFromMainRelease.js';
+export {default as withDirectorySuffixes} from './withDirectorySuffixes.js';
diff --git a/src/data/composite/things/track/withDirectorySuffixes.js b/src/data/composite/things/track/withDirectorySuffixes.js
new file mode 100644
index 00000000..87a737db
--- /dev/null
+++ b/src/data/composite/things/track/withDirectorySuffixes.js
@@ -0,0 +1,184 @@
+import {input, templateCompositeFrom} from '#composite';
+import {getKebabCase} from '#wiki-data';
+
+import {withPropertiesFromObject} from '#composite/data';
+
+export default templateCompositeFrom({
+  annotation: `withDirectorySuffixes`,
+
+  inputs: {
+    from: input({
+      defaultDependency: '_suffixDirectory',
+      acceptsNull: true,
+    }),
+  },
+
+  // sorry these are in noun form (dies)
+  outputs: ['#directorySuffix', '#directorySuffixWithinAlbum'],
+
+  steps: () =>  [
+    withPropertiesFromObject({
+      object: 'trackSection',
+      properties: input.value([
+        'suffixTrackDirectoriesByDefault',
+        'directorySuffixForTracks',
+      ]),
+    }),
+
+    {
+      dependencies: [
+        input('from'),
+        '#trackSection.suffixTrackDirectoriesByDefault',
+        '#trackSection.directorySuffixForTracks',
+      ],
+
+      compute(continuation, {
+        [input('from')]:
+          suffixDirectory,
+
+        ['#trackSection.suffixTrackDirectoriesByDefault']:
+          suffixTrackDirectoriesByDefault,
+
+        ['#trackSection.directorySuffixForTracks']:
+          directorySuffixForTracks,
+      }) {
+        // All conditions in this chunk process explicitly set values for
+        // the actual update value - that is, everything EXCEPT true or null,
+        // which both pass through to conditional "defaults".
+        // (True and null aren't quite equal, but the difference only matters
+        //  at the very end.)
+
+        if (suffixDirectory === 'album') {
+          return continuation.raiseOutput({
+            ['#directorySuffix']: directorySuffixForTracks,
+            ['#directorySuffixWithinAlbum']: null,
+          });
+        }
+
+        if (typeof suffixDirectory === 'string') {
+          return continuation.raiseOutput({
+            ['#directorySuffix']: suffixDirectory,
+            ['#directorySuffixWithinAlbum']: suffixDirectory,
+          });
+        }
+
+        if (suffixDirectory === false) {
+          return continuation.raiseOutput({
+            ['#directorySuffix']: null,
+            ['#directorySuffixWithinAlbum']: null,
+          });
+        }
+
+        if (Array.isArray(suffixDirectory)) {
+          const parts1 =
+            suffixDirectory
+              .map(item =>
+                (item === 'album'
+                  ? directorySuffixForTracks
+                  : item));
+
+          const parts2 =
+            suffixDirectory
+              .map(item =>
+                (item === 'album'
+                  ? null
+                  : item))
+              .filter(Boolean);
+
+          return continuation.raiseOutput({
+            ['#directorySuffix']: parts1.join('-'),
+            ['#directorySuffixWithinAlbum']: parts2.join('-'),
+          });
+        }
+
+        // It's true or null - just continue.
+        return continuation();
+      },
+    },
+
+    {
+      dependencies: [
+        '#trackSection.suffixTrackDirectoriesByDefault',
+        '#trackSection.directorySuffixForTracks',
+      ],
+
+      compute(continuation, {
+        ['#trackSection.suffixTrackDirectoriesByDefault']:
+          suffixTrackDirectoriesByDefault,
+
+        ['#trackSection.directorySuffixForTracks']:
+          directorySuffixForTracks,
+      }) {
+        if (suffixTrackDirectoriesByDefault === true) {
+          return continuation.raiseOutput({
+            ['#directorySuffix']: directorySuffixForTracks,
+            ['#directorySuffixWithinAlbum']: null,
+          });
+        }
+
+        return continuation();
+      },
+    },
+
+    {
+      dependencies: [
+        '_nameDetail',
+         'nameDetailAcrossWiki',
+
+        '#trackSection.directorySuffixForTracks',
+      ],
+
+      compute(continuation, {
+        ['_nameDetail']: nameDetail,
+        [ 'nameDetailAcrossWiki']: nameDetailAcrossWiki,
+
+        ['#trackSection.directorySuffixForTracks']:
+          directorySuffixForTracks,
+      }) {
+        if (nameDetail === 'album') {
+          return continuation.raiseOutput({
+            ['#directorySuffix']: directorySuffixForTracks,
+            ['#directorySuffixWithinAlbum']: directorySuffixForTracks,
+          });
+        }
+
+        if (nameDetailAcrossWiki) {
+          const kebab = getKebabCase(nameDetailAcrossWiki);
+
+          return continuation.raiseOutput({
+            ['#directorySuffix']: kebab,
+            ['#directorySuffixWithinAlbum']: kebab,
+          });
+        }
+
+        return continuation();
+      },
+    },
+
+    // Ultimately, if no conditions above exposed a more particular value,
+    // now we can FINALLY differentiate between true and null.
+    {
+      dependencies: [
+        input('from'),
+        '#trackSection.directorySuffixForTracks',
+      ],
+
+      compute: (continuation, {
+        [input('from')]:
+          suffixDirectory,
+
+        ['#trackSection.directorySuffixForTracks']:
+          directorySuffixForTracks,
+      }) =>
+        (suffixDirectory === true
+          ? continuation({
+              ['#directorySuffix']: directorySuffixForTracks,
+              ['#directorySuffixWithinAlbum']: null,
+            })
+          : continuation({
+              ['#directorySuffix']: null,
+              ['#directorySuffixWithinAlbum']: null,
+            })),
+    },
+  ],
+});
diff --git a/src/data/things/Track.js b/src/data/things/Track.js
index a615af4a..7ce55e51 100644
--- a/src/data/things/Track.js
+++ b/src/data/things/Track.js
@@ -7,7 +7,7 @@ import find, {keyRefRegex} from '#find';
 import {empty, onlyItem} from '#sugar';
 import {sortByDate, sortFlashesChronologically} from '#sort';
 import Thing from '#thing';
-import {compareKebabCase, getKebabCase} from '#wiki-data';
+import {compareKebabCase} from '#wiki-data';
 
 import {
   anyOf,
@@ -17,9 +17,11 @@ import {
   isContentString,
   isContributionList,
   isDate,
+  isDirectory,
   isExcludingURLsReason,
   isFileExtension,
   isString,
+  strictArrayOf,
   validateReference,
 } from '#validators';
 
@@ -69,6 +71,7 @@ import {
 } from '#composite/data';
 
 import {
+  withDirectory,
   withRecontextualizedContributionList,
   withRedatedContributionList,
   withResolvedContribs,
@@ -100,6 +103,7 @@ import {
 import {
   inheritContributionListFromMainRelease,
   inheritFromMainRelease,
+  withDirectorySuffixes,
 } from '#composite/things/track';
 
 export class Track extends Thing {
@@ -155,16 +159,26 @@ export class Track extends Thing {
     ],
 
     directory: directory({
-      suffix: 'directorySuffix',
+      suffix: 'suffixDirectory',
     }),
 
     suffixDirectory: [
-      exposeUpdateValueOrContinue({
-        validate: input.value(isBoolean),
+      withDirectorySuffixes({
+        from:
+          input.updateValue({
+            validate:
+              anyOf(
+                isBoolean,
+                is('album'),
+                isDirectory,
+                strictArrayOf(
+                  anyOf(
+                    is('album'),
+                    isDirectory))),
+          }),
       }),
 
-      withPropertyFromObject('trackSection', V('suffixTrackDirectories')),
-      exposeDependency('#trackSection.suffixTrackDirectories'),
+      exposeDependency('#directorySuffix'),
     ],
 
     referenceByDirectory: [
@@ -674,80 +688,25 @@ export class Track extends Thing {
       exposeDependency('name'),
     ],
 
-    commentatorArtists: commentatorArtists(),
-
-    directorySuffix: [
-      withPropertyFromObject('trackSection', V('directorySuffix')),
-
-      {
-        dependencies: [
-          '_suffixDirectory',
-           'suffixDirectory',
-          '#trackSection.directorySuffix',
-        ],
-
-        compute(continuation, {
-          ['_suffixDirectory']: suffixDirectoryUpdateValue,
-          [ 'suffixDirectory']: suffixDirectoryComputedValue,
-          ['#trackSection.directorySuffix']: directorySuffixFromAlbum,
-        }) {
-          // If directly set to true or inheriting true...
-          if (suffixDirectoryComputedValue === true) {
-            return directorySuffixFromAlbum;
-          }
-
-          // If directly set to false...
-          if (suffixDirectoryUpdateValue === false) {
-            return null;
-          }
-
-          // If inheriting false or defaulting to false...
-          return continuation();
-        },
-      },
+    directoryWithinAlbum: [
+      withDirectorySuffixes(),
 
-      // Don't follow any "automatic" directory suffix logic if the track's
-      // entire directory is set outright.
-      {
-        dependencies: ['_directory'],
-        compute(continuation, {
-          ['_directory']: directoryUpdateValue,
-        }) {
-          if (directoryUpdateValue) {
-            return null;
-          }
-
-          return continuation();
-        },
-      },
-
-      {
-        dependencies: [
-          '_nameDetail',
-           'nameDetailAcrossWiki',
-          '#trackSection.directorySuffix',
-        ],
-
-        compute(continuation, {
-          ['_nameDetail']: nameDetail,
-          [ 'nameDetailAcrossWiki']: nameDetailAcrossWiki,
-          ['#trackSection.directorySuffix']: directorySuffixFromAlbum,
-        }) {
-          if (nameDetail === 'album') {
-            return directorySuffixFromAlbum;
-          }
-
-          if (nameDetailAcrossWiki) {
-            return getKebabCase(nameDetailAcrossWiki);
-          }
+      withDirectory({
+        directory: '_directory',
+        name: 'name',
+        suffix: '#directorySuffixWithinAlbum',
+      }),
 
-          return continuation();
-        },
-      },
+      exposeDependency('#directory'),
+    ],
 
-      exposeConstant(V(null)),
+    suffixDirectoryWithinAlbum: [
+      withDirectorySuffixes(),
+      exposeDependency('#directorySuffixWithinAlbum'),
     ],
 
+    commentatorArtists: commentatorArtists(),
+
     date: [
       {
         dependencies: ['disableDate'],
@@ -1467,8 +1426,8 @@ export class Track extends Thing {
     const ext = artwork.fileExtension;
     const basename =
       (artwork.unqualifiedDirectory
-        ? this.directory + '-' + artwork.unqualifiedDirectory
-        : this.directory);
+        ? this.directoryWithinAlbum + '-' + artwork.unqualifiedDirectory
+        : this.directoryWithinAlbum);
 
     return this.album.getAlbumArtPath(`${basename}.${ext}`);
   }
@@ -1484,7 +1443,7 @@ export class Track extends Thing {
     const trackPrefix =
       (isSingleFirstTrack
         ? ''
-        : this.directory + '-');
+        : this.directoryWithinAlbum + '-');
 
     const filename =
       trackPrefix +
diff --git a/src/data/things/album/Album.js b/src/data/things/album/Album.js
index 7efc2d8c..369186f3 100644
--- a/src/data/things/album/Album.js
+++ b/src/data/things/album/Album.js
@@ -122,8 +122,7 @@ export class Album extends Thing {
 
     directory: directory(),
 
-    // note: this is currently strictly "directory suffix for tracks"
-    directorySuffix: [
+    directorySuffixForTracks: [
       exposeUpdateValueOrContinue({
         validate: input.value(isDirectory),
       }),
@@ -137,6 +136,8 @@ export class Album extends Thing {
       },
     ],
 
+    suffixTrackDirectoriesByDefault: flag(V(false)),
+
     alwaysReferenceByDirectory: flag(V(false)),
 
     referenceTracksByDirectory: [
@@ -153,8 +154,6 @@ export class Album extends Thing {
       exposeConstant(V('normally')),
     ],
 
-    suffixTrackDirectories: flag(V(false)),
-
     style: [
       exposeUpdateValueOrContinue({
         validate: input.value(is(...[
@@ -640,8 +639,8 @@ export class Album extends Thing {
       'Name Detail For Tracks': {property: 'nameDetailForTracks'},
 
       'Directory': {property: 'directory'},
-      'Directory Suffix': {property: 'directorySuffix'},
-      'Suffix Track Directories': {property: 'suffixTrackDirectories'},
+      'Directory Suffix': {property: 'directorySuffixForTracks'},
+      'Suffix Track Directories': {property: 'suffixTrackDirectoriesByDefault'},
 
       'Always Reference By Directory': {property: 'alwaysReferenceByDirectory'},
 
diff --git a/src/data/things/album/TrackSection.js b/src/data/things/album/TrackSection.js
index 451f8f7b..00963d1b 100644
--- a/src/data/things/album/TrackSection.js
+++ b/src/data/things/album/TrackSection.js
@@ -50,22 +50,22 @@ export class TrackSection extends Thing {
 
     unqualifiedDirectory: directory(),
 
-    directorySuffix: [
+    directorySuffixForTracks: [
       exposeUpdateValueOrContinue({
         validate: input.value(isDirectory),
       }),
 
-      withPropertyFromObject('album', V('directorySuffix')),
-      exposeDependency('#album.directorySuffix'),
+      withPropertyFromObject('album', V('directorySuffixForTracks')),
+      exposeDependency('#album.directorySuffixForTracks'),
     ],
 
-    suffixTrackDirectories: [
+    suffixTrackDirectoriesByDefault: [
       exposeUpdateValueOrContinue({
         validate: input.value(isBoolean),
       }),
 
-      withPropertyFromObject('album', V('suffixTrackDirectories')),
-      exposeDependency('#album.suffixTrackDirectories'),
+      withPropertyFromObject('album', V('suffixTrackDirectoriesByDefault')),
+      exposeDependency('#album.suffixTrackDirectoriesByDefault'),
     ],
 
     color: [
@@ -204,8 +204,8 @@ export class TrackSection extends Thing {
   static [Thing.yamlDocumentSpec] = {
     fields: {
       'Section': {property: 'name'},
-      'Directory Suffix': {property: 'directorySuffix'},
-      'Suffix Track Directories': {property: 'suffixTrackDirectories'},
+      'Directory Suffix': {property: 'directorySuffixForTracks'},
+      'Suffix Track Directories': {property: 'suffixTrackDirectoriesByDefault'},
 
       'Color': {property: 'color'},
       'Has Track Numbers': {property: 'hasTrackNumbers'},