diff options
author | (quasar) nebula <qznebula@protonmail.com> | 2024-05-19 21:44:18 -0300 |
---|---|---|
committer | (quasar) nebula <qznebula@protonmail.com> | 2024-05-19 21:47:31 -0300 |
commit | 048e79a1ea83a942579ce89f797795e34cc4199e (patch) | |
tree | c810109a93bc5fe1dbae611bb6efb212846df00f /src | |
parent | 471de6e5ac73bd6c769a58392e3e49aff6d8f2cb (diff) |
data: TrackSection thing objects
Sorry this commit is kind of monolithic! It's difficult to separate out any of the changes since they're all related to track sections' basic functionality.
Diffstat (limited to 'src')
-rw-r--r-- | src/data/composite/things/album/index.js | 1 | ||||
-rw-r--r-- | src/data/composite/things/album/withTrackSections.js | 127 | ||||
-rw-r--r-- | src/data/composite/things/album/withTracks.js | 40 | ||||
-rw-r--r-- | src/data/composite/things/track-section/index.js | 1 | ||||
-rw-r--r-- | src/data/composite/things/track-section/withAlbum.js | 22 | ||||
-rw-r--r-- | src/data/things/album.js | 187 |
6 files changed, 172 insertions, 206 deletions
diff --git a/src/data/composite/things/album/index.js b/src/data/composite/things/album/index.js index 8139f10e..8b5098f0 100644 --- a/src/data/composite/things/album/index.js +++ b/src/data/composite/things/album/index.js @@ -1,2 +1 @@ export {default as withTracks} from './withTracks.js'; -export {default as withTrackSections} from './withTrackSections.js'; diff --git a/src/data/composite/things/album/withTrackSections.js b/src/data/composite/things/album/withTrackSections.js deleted file mode 100644 index 0a1ebebc..00000000 --- a/src/data/composite/things/album/withTrackSections.js +++ /dev/null @@ -1,127 +0,0 @@ -import {input, templateCompositeFrom} from '#composite'; -import find from '#find'; -import {empty, filterMultipleArrays, stitchArrays} from '#sugar'; -import {isTrackSectionList} from '#validators'; - -import {exitWithoutDependency, exitWithoutUpdateValue} - from '#composite/control-flow'; -import {withResolvedReferenceList} from '#composite/wiki-data'; - -import { - fillMissingListItems, - withFlattenedList, - withPropertiesFromList, - withUnflattenedList, -} from '#composite/data'; - -export default templateCompositeFrom({ - annotation: `withTrackSections`, - - outputs: ['#trackSections'], - - steps: () => [ - exitWithoutDependency({ - dependency: 'ownTrackData', - value: input.value([]), - }), - - exitWithoutUpdateValue({ - mode: input.value('empty'), - value: input.value([]), - }), - - // TODO: input.updateValue description down here is a kludge. - withPropertiesFromList({ - list: input.updateValue({ - validate: isTrackSectionList, - }), - prefix: input.value('#sections'), - properties: input.value([ - 'tracks', - 'dateOriginallyReleased', - 'isDefaultTrackSection', - 'name', - 'color', - ]), - }), - - fillMissingListItems({ - list: '#sections.tracks', - fill: input.value([]), - }), - - fillMissingListItems({ - list: '#sections.isDefaultTrackSection', - fill: input.value(false), - }), - - fillMissingListItems({ - list: '#sections.name', - fill: input.value('Unnamed Track Section'), - }), - - fillMissingListItems({ - list: '#sections.color', - fill: input.dependency('color'), - }), - - withFlattenedList({ - list: '#sections.tracks', - }).outputs({ - ['#flattenedList']: '#trackRefs', - ['#flattenedIndices']: '#sections.startIndex', - }), - - withResolvedReferenceList({ - list: '#trackRefs', - data: 'ownTrackData', - notFoundMode: input.value('null'), - find: input.value(find.track), - }).outputs({ - ['#resolvedReferenceList']: '#tracks', - }), - - withUnflattenedList({ - list: '#tracks', - indices: '#sections.startIndex', - }).outputs({ - ['#unflattenedList']: '#sections.tracks', - }), - - { - dependencies: [ - '#sections.tracks', - '#sections.name', - '#sections.color', - '#sections.dateOriginallyReleased', - '#sections.isDefaultTrackSection', - '#sections.startIndex', - ], - - compute: (continuation, { - '#sections.tracks': tracks, - '#sections.name': name, - '#sections.color': color, - '#sections.dateOriginallyReleased': dateOriginallyReleased, - '#sections.isDefaultTrackSection': isDefaultTrackSection, - '#sections.startIndex': startIndex, - }) => { - filterMultipleArrays( - tracks, name, color, dateOriginallyReleased, isDefaultTrackSection, startIndex, - tracks => !empty(tracks)); - - return continuation({ - ['#trackSections']: - stitchArrays({ - tracks, - name, - color, - dateOriginallyReleased, - isDefaultTrackSection, - startIndex, - }), - }); - }, - }, - ], -}); diff --git a/src/data/composite/things/album/withTracks.js b/src/data/composite/things/album/withTracks.js index fff3d5ae..05f5b24d 100644 --- a/src/data/composite/things/album/withTracks.js +++ b/src/data/composite/things/album/withTracks.js @@ -1,9 +1,8 @@ import {input, templateCompositeFrom} from '#composite'; -import find from '#find'; import {exitWithoutDependency, raiseOutputWithoutDependency} from '#composite/control-flow'; -import {withResolvedReferenceList} from '#composite/wiki-data'; +import {withFlattenedList, withPropertyFromList} from '#composite/data'; export default templateCompositeFrom({ annotation: `withTracks`, @@ -11,41 +10,22 @@ export default templateCompositeFrom({ outputs: ['#tracks'], steps: () => [ - exitWithoutDependency({ - dependency: 'ownTrackData', - value: input.value([]), - }), - raiseOutputWithoutDependency({ dependency: 'trackSections', - mode: input.value('empty'), output: input.value({ - ['#tracks']: [], + '#tracks': [], }), }), - { - dependencies: ['trackSections'], - compute: (continuation, {trackSections}) => - continuation({ - '#trackRefs': trackSections - .flatMap(section => section.tracks ?? []), - }), - }, - - withResolvedReferenceList({ - list: '#trackRefs', - data: 'ownTrackData', - find: input.value(find.track), + withPropertyFromList({ + list: 'trackSections', + property: input.value('tracks'), }), - { - dependencies: ['#resolvedReferenceList'], - compute: (continuation, { - ['#resolvedReferenceList']: resolvedReferenceList, - }) => continuation({ - ['#tracks']: resolvedReferenceList, - }) - }, + withFlattenedList({ + list: '#trackSections.tracks', + }).outputs({ + ['#flattenedList']: '#tracks', + }), ], }); diff --git a/src/data/composite/things/track-section/index.js b/src/data/composite/things/track-section/index.js new file mode 100644 index 00000000..3202ed49 --- /dev/null +++ b/src/data/composite/things/track-section/index.js @@ -0,0 +1 @@ +export {default as withAlbum} from './withAlbum.js'; diff --git a/src/data/composite/things/track-section/withAlbum.js b/src/data/composite/things/track-section/withAlbum.js new file mode 100644 index 00000000..608cc0cd --- /dev/null +++ b/src/data/composite/things/track-section/withAlbum.js @@ -0,0 +1,22 @@ +// Gets the track section's album. This will early exit if ownAlbumData is +// missing. If there's no album whose list of track sections includes this one, +// the output dependency will be null. + +import {input, templateCompositeFrom} from '#composite'; + +import {withUniqueReferencingThing} from '#composite/wiki-data'; + +export default templateCompositeFrom({ + annotation: `withAlbum`, + + outputs: ['#album'], + + steps: () => [ + withUniqueReferencingThing({ + data: 'ownAlbumData', + list: input.value('trackSections'), + }).outputs({ + ['#uniqueReferencingThing']: '#album', + }), + ], +}); diff --git a/src/data/things/album.js b/src/data/things/album.js index f8354962..78ecb294 100644 --- a/src/data/things/album.js +++ b/src/data/things/album.js @@ -6,15 +6,17 @@ import {input} from '#composite'; import find from '#find'; import {traverse} from '#node-utils'; import {sortAlbumsTracksChronologically, sortChronologically} from '#sort'; -import {empty} from '#sugar'; +import {accumulateSum, empty} from '#sugar'; import Thing from '#thing'; -import {isDate} from '#validators'; +import {isColor, isDate, validateWikiData} from '#validators'; import {parseAdditionalFiles, parseContributors, parseDate, parseDimensions} from '#yaml'; -import {exposeDependency, exposeUpdateValueOrContinue} +import {exitWithoutDependency, exposeDependency, exposeUpdateValueOrContinue} from '#composite/control-flow'; -import {exitWithoutContribs} from '#composite/wiki-data'; +import {withPropertyFromObject} from '#composite/data'; +import {exitWithoutContribs, withDirectory, withResolvedReference} + from '#composite/wiki-data'; import { additionalFiles, @@ -31,16 +33,24 @@ import { referenceList, simpleDate, simpleString, + singleReference, urls, wikiData, } from '#composite/wiki-properties'; -import {withTracks, withTrackSections} from '#composite/things/album'; +import {withTracks} from '#composite/things/album'; +import {withAlbum} from '#composite/things/track-section'; export class Album extends Thing { static [Thing.referenceType] = 'album'; - static [Thing.getPropertyDescriptors] = ({ArtTag, Artist, Group, Track}) => ({ + static [Thing.getPropertyDescriptors] = ({ + ArtTag, + Artist, + Group, + Track, + TrackSection, + }) => ({ // Update & expose name: name('Unnamed Album'), @@ -111,10 +121,17 @@ export class Album extends Thing { commentary: commentary(), additionalFiles: additionalFiles(), - trackSections: [ - withTrackSections(), - exposeDependency({dependency: '#trackSections'}), - ], + trackSections: { + flags: {update: true, expose: true}, + + update: { + validate: + validateWikiData({ + referenceType: + TrackSection[Thing.referenceType], + }), + }, + }, artistContribs: contributionList(), coverArtistContribs: contributionList(), @@ -155,13 +172,6 @@ export class Album extends Thing { class: input.value(Group), }), - // Only the tracks which belong to this album. - // Necessary for computing the track list, so provide this statically - // or keep it updated. - ownTrackData: wikiData({ - class: input.value(Track), - }), - // Expose only commentatorArtists: commentatorArtists(), @@ -345,7 +355,7 @@ export class Album extends Thing { headerDocumentThing: Album, entryDocumentThing: document => ('Section' in document - ? TrackSectionHelper + ? TrackSection : Track), save(results) { @@ -353,49 +363,49 @@ export class Album extends Thing { const trackData = []; for (const {header: album, entries} of results) { - // We can't mutate an array once it's set as a property value, - // so prepare the track sections that will show up in a track list - // all the way before actually applying them. (It's okay to mutate - // an individual section before applying it, since those are just - // generic objects; they aren't Things in and of themselves.) const trackSections = []; - const ownTrackData = []; - let currentTrackSection = { + let currentTrackSection = new TrackSection(); + let currentTrackSectionTracks = []; + + Object.assign(currentTrackSection, { name: `Default Track Section`, isDefaultTrackSection: true, - tracks: [], - }; + }); const albumRef = Thing.getReference(album); const closeCurrentTrackSection = () => { - if (!empty(currentTrackSection.tracks)) { - trackSections.push(currentTrackSection); + if (empty(currentTrackSectionTracks)) { + return; } + + currentTrackSection.tracks = + currentTrackSectionTracks + .map(track => Thing.getReference(track)); + + currentTrackSection.ownTrackData = + currentTrackSectionTracks; + + currentTrackSection.ownAlbumData = + [album]; + + trackSections.push(currentTrackSection); }; for (const entry of entries) { - if (entry instanceof TrackSectionHelper) { + if (entry instanceof TrackSection) { closeCurrentTrackSection(); - - currentTrackSection = { - name: entry.name, - color: entry.color, - dateOriginallyReleased: entry.dateOriginallyReleased, - isDefaultTrackSection: false, - tracks: [], - }; - + currentTrackSection = entry; + currentTrackSectionTracks = []; continue; } + currentTrackSectionTracks.push(entry); + trackData.push(entry); entry.dataSourceAlbum = albumRef; - - ownTrackData.push(entry); - currentTrackSection.tracks.push(Thing.getReference(entry)); } closeCurrentTrackSection(); @@ -403,7 +413,6 @@ export class Album extends Thing { albumData.push(album); album.trackSections = trackSections; - album.ownTrackData = ownTrackData; } return {albumData, trackData}; @@ -416,15 +425,97 @@ export class Album extends Thing { }); } -export class TrackSectionHelper extends Thing { +export class TrackSection extends Thing { static [Thing.friendlyName] = `Track Section`; + static [Thing.referenceType] = `track-section`; + + static [Thing.getPropertyDescriptors] = ({Album, Track}) => ({ + // Update & expose - static [Thing.getPropertyDescriptors] = () => ({ name: name('Unnamed Track Section'), - color: color(), + + unqualifiedDirectory: directory(), + + color: [ + exposeUpdateValueOrContinue({ + validate: input.value(isColor), + }), + + withAlbum(), + + withPropertyFromObject({ + object: '#album', + property: input.value('color'), + }), + + exposeDependency({dependency: '#album.color'}), + ], + dateOriginallyReleased: simpleDate(), - isDefaultTrackGroup: flag(false), - }) + + isDefaultTrackSection: flag(false), + + album: [ + withAlbum(), + exposeDependency({dependency: '#album'}), + ], + + tracks: referenceList({ + class: input.value(Track), + data: 'ownTrackData', + find: input.value(find.track), + }), + + // Update only + + ownAlbumData: wikiData({ + class: input.value(Album), + }), + + ownTrackData: wikiData({ + class: input.value(Track), + }), + + // Expose only + + startIndex: [ + withAlbum(), + + withPropertyFromObject({ + object: '#album', + property: input.value('trackSections'), + }), + + { + dependencies: ['#album.trackSections', input.myself()], + compute: (continuation, { + ['#album.trackSections']: trackSections, + [input.myself()]: myself, + }) => continuation({ + ['#index']: + trackSections.indexOf(myself), + }), + }, + + exitWithoutDependency({ + dependency: '#index', + mode: input.value('index'), + value: input.value(0), + }), + + { + dependencies: ['#album.trackSections', '#index'], + compute: ({ + ['#album.trackSections']: trackSections, + ['#index']: index, + }) => + accumulateSum( + trackSections + .slice(0, index) + .map(section => section.tracks.length)), + }, + ], + }); static [Thing.yamlDocumentSpec] = { fields: { |