From 8ac83829b4f1add4c57504210d08758e63540853 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Wed, 10 Jun 2026 10:32:21 -0300 Subject: data: Track: 'Name Detail: section' --- .../things/track/withDirectorySuffixes.js | 113 ++++++++++++++++----- src/data/things/Track.js | 39 +++++-- src/data/things/album/TrackSection.js | 46 +++++++-- 3 files changed, 157 insertions(+), 41 deletions(-) diff --git a/src/data/composite/things/track/withDirectorySuffixes.js b/src/data/composite/things/track/withDirectorySuffixes.js index efc66f13..be66b5c9 100644 --- a/src/data/composite/things/track/withDirectorySuffixes.js +++ b/src/data/composite/things/track/withDirectorySuffixes.js @@ -22,13 +22,23 @@ export default templateCompositeFrom({ properties: input.value([ 'suffixTrackDirectoriesByDefault', 'directorySuffixForTracks', + 'nameDetailForTracks', + ]), + }), + + withPropertiesFromObject({ + object: 'album', + properties: input.value([ + 'suffixTrackDirectoriesByDefault', + 'directorySuffixForTracks', + 'nameDetailForTracks', ]), }), { dependencies: [ input('from'), - '#trackSection.suffixTrackDirectoriesByDefault', + '#album.directorySuffixForTracks', '#trackSection.directorySuffixForTracks', ], @@ -36,25 +46,34 @@ export default templateCompositeFrom({ [input('from')]: suffixDirectory, - ['#trackSection.suffixTrackDirectoriesByDefault']: - suffixTrackDirectoriesByDefault, + ['#album.directorySuffixForTracks']: + albumDirectorySuffixForTracks, ['#trackSection.directorySuffixForTracks']: - directorySuffixForTracks, + trackSectionDirectorySuffixForTracks, }) { // 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.) + // the actual update value - that is, everything EXCEPT null, + // which passes through to conditional "defaults". + // Note that 'Suffix Directory: true' is literally equivalent to + // suffixDirectory = 'album', via yaml transformation. if (suffixDirectory === 'album') { return continuation.raiseOutput({ - ['#directorySuffix']: directorySuffixForTracks, + ['#directorySuffix']: albumDirectorySuffixForTracks, ['#directorySuffixWithinAlbum']: null, }); } + if (suffixDirectory === 'section') { + // Bear in mind the directory is suffixed within the album. + // This is repeated in following steps, too. + return continuation.raiseOutput({ + ['#directorySuffix']: trackSectionDirectorySuffixForTracks, + ['#directorySuffixWithinAlbum']: trackSectionDirectorySuffixForTracks, + }); + } + if (typeof suffixDirectory === 'string') { return continuation.raiseOutput({ ['#directorySuffix']: suffixDirectory, @@ -74,7 +93,9 @@ export default templateCompositeFrom({ suffixDirectory .map(item => (item === 'album' - ? directorySuffixForTracks + ? albumDirectorySuffixForTracks + : item === 'section' + ? trackSectionDirectorySuffixForTracks : item)); const parts2 = @@ -82,6 +103,8 @@ export default templateCompositeFrom({ .map(item => (item === 'album' ? null + : item === 'section' + ? trackSectionDirectorySuffixForTracks : item)) .filter(Boolean); @@ -91,27 +114,53 @@ export default templateCompositeFrom({ }); } - // It's true or null - just continue. + // It's null - just continue. return continuation(); }, }, { + // Neither of the track section fields inherit from the album. + // Importantly, trackSection.suffixTrackDirectoriesByDefault can be null + // OR false at the same time as album.suffixTrackDirectoriesByDefault + // is true, and those carry different meanings. dependencies: [ '#trackSection.suffixTrackDirectoriesByDefault', '#trackSection.directorySuffixForTracks', + '#album.suffixTrackDirectoriesByDefault', + '#album.directorySuffixForTracks', ], compute(continuation, { ['#trackSection.suffixTrackDirectoriesByDefault']: - suffixTrackDirectoriesByDefault, + trackSectionSuffixTrackDirectoriesByDefault, ['#trackSection.directorySuffixForTracks']: - directorySuffixForTracks, + trackSectionDirectorySuffixForTracks, + + ['#album.suffixTrackDirectoriesByDefault']: + albumSuffixTrackDirectoriesByDefault, + + ['#album.directorySuffixForTracks']: + albumDirectorySuffixForTracks, }) { - if (suffixTrackDirectoriesByDefault === true) { + if (trackSectionSuffixTrackDirectoriesByDefault === true) { + return continuation.raiseOutput({ + ['#directorySuffix']: trackSectionDirectorySuffixForTracks, + ['#directorySuffixWithinAlbum']: trackSectionDirectorySuffixForTracks, + }); + } + + if (trackSectionSuffixTrackDirectoriesByDefault === false) { + // Just proceed. Other logic may independently provide a suffix, + // but this false ensures that track ignores whether the *album* + // provides Suffix Track Directories: true. + return continuation(); + } + + if (albumSuffixTrackDirectoriesByDefault === true) { return continuation.raiseOutput({ - ['#directorySuffix']: directorySuffixForTracks, + ['#directorySuffix']: albumDirectorySuffixForTracks, ['#directorySuffixWithinAlbum']: null, }); } @@ -141,29 +190,47 @@ export default templateCompositeFrom({ }, { + // The logic path in this section is ONLY decided based on the track's + // actually-set Name Detail, and inheritence is not a factor at all. dependencies: [ '_nameDetail', - 'nameDetailAcrossWiki', - + '#album.nameDetailForTracks', + '#album.directorySuffixForTracks', + '#trackSection.nameDetailForTracks', '#trackSection.directorySuffixForTracks', ], compute(continuation, { ['_nameDetail']: nameDetail, - [ 'nameDetailAcrossWiki']: nameDetailAcrossWiki, + + ['#album.nameDetailForTracks']: + albumNameDetailForTracks, + + ['#album.directorySuffixForTracks']: + albumDirectorySuffixForTracks, + + ['#trackSection.nameDetailForTracks']: + trackSectionNameDetailForTracks, ['#trackSection.directorySuffixForTracks']: - directorySuffixForTracks, + trackSectionDirectorySuffixForTracks, }) { + if (nameDetail === 'section') { + return continuation.raiseOutput({ + ['#directorySuffix']: trackSectionDirectorySuffixForTracks, + ['#directorySuffixWithinAlbum']: trackSectionDirectorySuffixForTracks, + }) + } + if (nameDetail === 'album') { return continuation.raiseOutput({ - ['#directorySuffix']: directorySuffixForTracks, - ['#directorySuffixWithinAlbum']: directorySuffixForTracks, + ['#directorySuffix']: albumDirectorySuffixForTracks, + ['#directorySuffixWithinAlbum']: null, }); } - if (nameDetailAcrossWiki) { - const kebab = getKebabCase(nameDetailAcrossWiki); + if (nameDetail) { + const kebab = getKebabCase(nameDetail); return continuation.raiseOutput({ ['#directorySuffix']: kebab, diff --git a/src/data/things/Track.js b/src/data/things/Track.js index 1f7375be..f6b3346c 100644 --- a/src/data/things/Track.js +++ b/src/data/things/Track.js @@ -169,12 +169,12 @@ export class Track extends Thing { input.updateValue({ validate: anyOf( - isBoolean, - is('album'), + is(false), + is('album', 'section'), isDirectory, strictArrayOf( anyOf( - is('album'), + is('album', 'section'), isDirectory))), }), }), @@ -781,21 +781,37 @@ export class Track extends Thing { }) => (nameDetail === 'album' ? null + : nameDetail === 'section' + ? null : nameDetail), }, ], nameDetailAcrossWiki: [ withPropertyFromObject('album', V('nameDetailForTracks')), + withPropertyFromObject('trackSection', V('nameDetailForTracks')), { - dependencies: ['_nameDetail', '#album.nameDetailForTracks'], + dependencies: [ + '_nameDetail', + '#album.nameDetailForTracks', + '#trackSection.nameDetailForTracks', + ], + compute: ({ - ['_nameDetail']: nameDetail, - ['#album.nameDetailForTracks']: nameDetailFromAlbum, + ['_nameDetail']: + nameDetail, + + ['#album.nameDetailForTracks']: + albumNameDetailForTracks, + + ['#trackSection.nameDetailForTracks']: + trackSectionNameDetailForTracks, }) => (nameDetail === 'album' - ? nameDetailFromAlbum + ? albumNameDetailForTracks + : nameDetail === 'section' + ? trackSectionNameDetailForTracks : nameDetail), }, ], @@ -1062,7 +1078,14 @@ export class Track extends Thing { 'Name Detail': {property: 'nameDetail'}, 'Directory': {property: 'directory'}, - 'Suffix Directory': {property: 'suffixDirectory'}, + + 'Suffix Directory': { + property: 'suffixDirectory', + transform: value => + (value === true + ? 'album' + : value), + }, 'Reference By Directory': {property: 'referenceByDirectory'}, diff --git a/src/data/things/album/TrackSection.js b/src/data/things/album/TrackSection.js index 00963d1b..0e6adb6d 100644 --- a/src/data/things/album/TrackSection.js +++ b/src/data/things/album/TrackSection.js @@ -13,6 +13,7 @@ import { isDirectory, isExcludingURLsReason, isNumber, + isString, } from '#validators'; import {withLengthOfList, withNearbyItemFromList, withPropertyFromObject} @@ -48,6 +49,22 @@ export class TrackSection extends Thing { name: name(V('Unnamed Track Section')), + // Track sections don't have a Name Detail themselves, but they do provide + // a value which tracks can reference via 'Name Detail: section'. + nameDetailForTracks: { + flags: {update: true, expose: true}, + + update: {validate: isString}, + + expose: { + dependencies: ['name'], + transform: (value, {name}) => + (value + ? value + : name), + }, + }, + unqualifiedDirectory: directory(), directorySuffixForTracks: [ @@ -55,18 +72,25 @@ export class TrackSection extends Thing { validate: input.value(isDirectory), }), - withPropertyFromObject('album', V('directorySuffixForTracks')), - exposeDependency('#album.directorySuffixForTracks'), + { + dependencies: ['unqualifiedDirectory', 'name', 'nameDetailForTracks'], + compute: ({unqualifiedDirectory, name, nameDetailForTracks}) => + (nameDetailForTracks === name + ? unqualifiedDirectory + : getKebabCase(nameDetailForTracks)), + }, ], - suffixTrackDirectoriesByDefault: [ - exposeUpdateValueOrContinue({ - validate: input.value(isBoolean), - }), - - withPropertyFromObject('album', V('suffixTrackDirectoriesByDefault')), - exposeDependency('#album.suffixTrackDirectoriesByDefault'), - ], + // Not quite a flag, because it supports (and defaults to) null. + // The value false means to explicitly ignore that the album is + // providing Suffix Track Directories: true. The value true means + // to use the TRACK SECTION's own directory suffix. The value null + // defers to the album's suffixTrackDirectoriesByDefault, which is + // simply true or false. + suffixTrackDirectoriesByDefault: { + flags: {expose: true, update: true}, + update: {validate: isBoolean}, + }, color: [ exposeUpdateValueOrContinue({ @@ -204,6 +228,8 @@ export class TrackSection extends Thing { static [Thing.yamlDocumentSpec] = { fields: { 'Section': {property: 'name'}, + 'Name Detail For Tracks': {property: 'nameDetailForTracks'}, + 'Directory Suffix': {property: 'directorySuffixForTracks'}, 'Suffix Track Directories': {property: 'suffixTrackDirectoriesByDefault'}, -- cgit 1.3.0-6-gf8a5