diff options
Diffstat (limited to 'src/data/composite/things')
15 files changed, 229 insertions, 410 deletions
diff --git a/src/data/composite/things/album/index.js b/src/data/composite/things/album/index.js index 8139f10..0ef91b8 100644 --- a/src/data/composite/things/album/index.js +++ b/src/data/composite/things/album/index.js @@ -1,2 +1,2 @@ -export {default as withTracks} from './withTracks.js'; export {default as withTrackSections} from './withTrackSections.js'; +export {default as withTracks} from './withTracks.js'; diff --git a/src/data/composite/things/album/withTrackSections.js b/src/data/composite/things/album/withTrackSections.js index 0a1ebeb..a56bda3 100644 --- a/src/data/composite/things/album/withTrackSections.js +++ b/src/data/composite/things/album/withTrackSections.js @@ -1,127 +1,21 @@ 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), + list: 'trackSections', + data: 'ownTrackSectionData', + find: input.value(find.unqualifiedTrackSection), }).outputs({ - ['#resolvedReferenceList']: '#tracks', + ['#resolvedReferenceList']: '#trackSections', }), - - 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 fff3d5a..c8d27c4 100644 --- a/src/data/composite/things/album/withTracks.js +++ b/src/data/composite/things/album/withTracks.js @@ -1,51 +1,27 @@ import {input, templateCompositeFrom} from '#composite'; -import find from '#find'; -import {exitWithoutDependency, raiseOutputWithoutDependency} - from '#composite/control-flow'; +import {withFlattenedList, withPropertyFromList} from '#composite/data'; import {withResolvedReferenceList} from '#composite/wiki-data'; +import withTrackSections from './withTrackSections.js'; + export default templateCompositeFrom({ annotation: `withTracks`, outputs: ['#tracks'], steps: () => [ - exitWithoutDependency({ - dependency: 'ownTrackData', - value: input.value([]), - }), + withTrackSections(), - raiseOutputWithoutDependency({ - dependency: 'trackSections', - mode: input.value('empty'), - output: input.value({ - ['#tracks']: [], - }), + withPropertyFromList({ + list: '#trackSections', + property: input.value('tracks'), }), - { - dependencies: ['trackSections'], - compute: (continuation, {trackSections}) => - continuation({ - '#trackRefs': trackSections - .flatMap(section => section.tracks ?? []), - }), - }, - - withResolvedReferenceList({ - list: '#trackRefs', - data: 'ownTrackData', - find: input.value(find.track), + withFlattenedList({ + list: '#trackSections.tracks', + }).outputs({ + ['#flattenedList']: '#tracks', }), - - { - dependencies: ['#resolvedReferenceList'], - compute: (continuation, { - ['#resolvedReferenceList']: resolvedReferenceList, - }) => continuation({ - ['#tracks']: resolvedReferenceList, - }) - }, ], }); diff --git a/src/data/composite/things/flash-act/index.js b/src/data/composite/things/flash-act/index.js new file mode 100644 index 0000000..40fecd2 --- /dev/null +++ b/src/data/composite/things/flash-act/index.js @@ -0,0 +1 @@ +export {default as withFlashSide} from './withFlashSide.js'; diff --git a/src/data/composite/things/flash-act/withFlashSide.js b/src/data/composite/things/flash-act/withFlashSide.js new file mode 100644 index 0000000..64daa1f --- /dev/null +++ b/src/data/composite/things/flash-act/withFlashSide.js @@ -0,0 +1,22 @@ +// Gets the flash act's side. This will early exit if flashSideData is missing. +// If there's no side whose list of flash acts includes this act, the output +// dependency will be null. + +import {input, templateCompositeFrom} from '#composite'; + +import {withUniqueReferencingThing} from '#composite/wiki-data'; + +export default templateCompositeFrom({ + annotation: `withFlashSide`, + + outputs: ['#flashSide'], + + steps: () => [ + withUniqueReferencingThing({ + data: 'flashSideData', + list: input.value('acts'), + }).outputs({ + ['#uniqueReferencingThing']: '#flashSide', + }), + ], +}); diff --git a/src/data/composite/things/flash/withFlashAct.js b/src/data/composite/things/flash/withFlashAct.js index ada2dcf..652b8bf 100644 --- a/src/data/composite/things/flash/withFlashAct.js +++ b/src/data/composite/things/flash/withFlashAct.js @@ -1,108 +1,22 @@ // Gets the flash's act. This will early exit if flashActData is missing. -// By default, if there's no flash whose list of flashes includes this flash, -// the output dependency will be null; set {notFoundMode: 'exit'} to early -// exit instead. -// -// This step models with Flash.withAlbum. +// If there's no flash whose list of flashes includes this flash, the output +// dependency will be null. import {input, templateCompositeFrom} from '#composite'; -import {is} from '#validators'; -import {exitWithoutDependency, withResultOfAvailabilityCheck} - from '#composite/control-flow'; -import {withPropertyFromList} from '#composite/data'; +import {withUniqueReferencingThing} from '#composite/wiki-data'; export default templateCompositeFrom({ annotation: `withFlashAct`, - inputs: { - notFoundMode: input({ - validate: is('exit', 'null'), - defaultValue: 'null', - }), - }, - outputs: ['#flashAct'], steps: () => [ - // null flashActData is always an early exit. - - exitWithoutDependency({ - dependency: 'flashActData', - mode: input.value('null'), - }), - - // empty flashActData conditionally exits early or outputs null. - - withResultOfAvailabilityCheck({ - from: 'flashActData', - mode: input.value('empty'), - }).outputs({ - '#availability': '#flashActDataAvailability', - }), - - { - dependencies: [input('notFoundMode'), '#flashActDataAvailability'], - compute(continuation, { - [input('notFoundMode')]: notFoundMode, - ['#flashActDataAvailability']: flashActDataIsAvailable, - }) { - if (flashActDataIsAvailable) return continuation(); - switch (notFoundMode) { - case 'exit': return continuation.exit(null); - case 'null': return continuation.raiseOutput({'#flashAct': null}); - } - }, - }, - - withPropertyFromList({ - list: 'flashActData', - property: input.value('flashes'), - }), - - { - dependencies: [input.myself(), '#flashActData.flashes'], - compute: (continuation, { - [input.myself()]: track, - ['#flashActData.flashes']: flashLists, - }) => continuation({ - ['#flashActIndex']: - flashLists.findIndex(flashes => flashes.includes(track)), - }), - }, - - // album not found conditionally exits or outputs null. - - withResultOfAvailabilityCheck({ - from: '#flashActIndex', - mode: input.value('index'), + withUniqueReferencingThing({ + data: 'flashActData', + list: input.value('flashes'), }).outputs({ - '#availability': '#flashActAvailability', + ['#uniqueReferencingThing']: '#flashAct', }), - - { - dependencies: [input('notFoundMode'), '#flashActAvailability'], - compute(continuation, { - [input('notFoundMode')]: notFoundMode, - ['#flashActAvailability']: flashActIsAvailable, - }) { - if (flashActIsAvailable) return continuation(); - switch (notFoundMode) { - case 'exit': return continuation.exit(null); - case 'null': return continuation.raiseOutput({'#flashAct': null}); - } - }, - }, - - { - dependencies: ['flashActData', '#flashActIndex'], - compute: (continuation, { - ['flashActData']: flashActData, - ['#flashActIndex']: flashActIndex, - }) => continuation.raiseOutput({ - ['#flashAct']: - flashActData[flashActIndex], - }), - }, ], }); 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 0000000..3202ed4 --- /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 0000000..608cc0c --- /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/composite/things/track/index.js b/src/data/composite/things/track/index.js index cc723a2..8959de9 100644 --- a/src/data/composite/things/track/index.js +++ b/src/data/composite/things/track/index.js @@ -9,3 +9,4 @@ export {default as withContainingTrackSection} from './withContainingTrackSectio export {default as withHasUniqueCoverArt} from './withHasUniqueCoverArt.js'; export {default as withOtherReleases} from './withOtherReleases.js'; export {default as withPropertyFromAlbum} from './withPropertyFromAlbum.js'; +export {default as withPropertyFromOriginalRelease} from './withPropertyFromOriginalRelease.js'; diff --git a/src/data/composite/things/track/inheritFromOriginalRelease.js b/src/data/composite/things/track/inheritFromOriginalRelease.js index 27ed138..38ab06b 100644 --- a/src/data/composite/things/track/inheritFromOriginalRelease.js +++ b/src/data/composite/things/track/inheritFromOriginalRelease.js @@ -1,8 +1,6 @@ -// Early exits with a value inherited from the original release, if -// this track is a rerelease, and otherwise continues with no further -// dependencies provided. If allowOverride is true, then the continuation -// will also be called if the original release exposed the requested -// property as null. +// Early exits with the value for the same property as specified on the +// original release, if this track is a rerelease, and otherwise continues +// without providing any further dependencies. // // Like withOriginalRelease, this will early exit (with notFoundValue) if the // original release is specified by reference and that reference doesn't @@ -10,41 +8,34 @@ import {input, templateCompositeFrom} from '#composite'; -import withOriginalRelease from './withOriginalRelease.js'; +import {exposeDependency, raiseOutputWithoutDependency} + from '#composite/control-flow'; + +import withPropertyFromOriginalRelease + from './withPropertyFromOriginalRelease.js'; export default templateCompositeFrom({ annotation: `inheritFromOriginalRelease`, inputs: { - property: input({type: 'string'}), - allowOverride: input({type: 'boolean', defaultValue: false}), - notFoundValue: input({defaultValue: null}), + notFoundValue: input({ + defaultValue: null, + }), }, steps: () => [ - withOriginalRelease({ + withPropertyFromOriginalRelease({ + property: input.thisProperty(), notFoundValue: input('notFoundValue'), }), - { - dependencies: [ - '#originalRelease', - input('property'), - input('allowOverride'), - ], - - compute: (continuation, { - ['#originalRelease']: originalRelease, - [input('property')]: originalProperty, - [input('allowOverride')]: allowOverride, - }) => { - if (!originalRelease) return continuation(); - - const value = originalRelease[originalProperty]; - if (allowOverride && value === null) return continuation(); - - return continuation.exit(value); - }, - }, + raiseOutputWithoutDependency({ + dependency: '#isRerelease', + mode: input.value('falsy'), + }), + + exposeDependency({ + dependency: '#originalValue', + }), ], }); diff --git a/src/data/composite/things/track/withAlbum.js b/src/data/composite/things/track/withAlbum.js index cbd16dc..03b840d 100644 --- a/src/data/composite/things/track/withAlbum.js +++ b/src/data/composite/things/track/withAlbum.js @@ -1,108 +1,22 @@ // Gets the track's album. This will early exit if albumData is missing. -// By default, if there's no album whose list of tracks includes this track, -// the output dependency will be null; set {notFoundMode: 'exit'} to early -// exit instead. -// -// This step models with Flash.withFlashAct. +// If there's no album whose list of tracks includes this track, the output +// dependency will be null. import {input, templateCompositeFrom} from '#composite'; -import {is} from '#validators'; -import {exitWithoutDependency, withResultOfAvailabilityCheck} - from '#composite/control-flow'; -import {withPropertyFromList} from '#composite/data'; +import {withUniqueReferencingThing} from '#composite/wiki-data'; export default templateCompositeFrom({ annotation: `withAlbum`, - inputs: { - notFoundMode: input({ - validate: is('exit', 'null'), - defaultValue: 'null', - }), - }, - outputs: ['#album'], steps: () => [ - // null albumData is always an early exit. - - exitWithoutDependency({ - dependency: 'albumData', - mode: input.value('null'), - }), - - // empty albumData conditionally exits early or outputs null. - - withResultOfAvailabilityCheck({ - from: 'albumData', - mode: input.value('empty'), - }).outputs({ - '#availability': '#albumDataAvailability', - }), - - { - dependencies: [input('notFoundMode'), '#albumDataAvailability'], - compute(continuation, { - [input('notFoundMode')]: notFoundMode, - ['#albumDataAvailability']: albumDataIsAvailable, - }) { - if (albumDataIsAvailable) return continuation(); - switch (notFoundMode) { - case 'exit': return continuation.exit(null); - case 'null': return continuation.raiseOutput({'#album': null}); - } - }, - }, - - withPropertyFromList({ - list: 'albumData', - property: input.value('tracks'), - }), - - { - dependencies: [input.myself(), '#albumData.tracks'], - compute: (continuation, { - [input.myself()]: track, - ['#albumData.tracks']: trackLists, - }) => continuation({ - ['#albumIndex']: - trackLists.findIndex(tracks => tracks.includes(track)), - }), - }, - - // album not found conditionally exits or outputs null. - - withResultOfAvailabilityCheck({ - from: '#albumIndex', - mode: input.value('index'), + withUniqueReferencingThing({ + data: 'albumData', + list: input.value('tracks'), }).outputs({ - '#availability': '#albumAvailability', + ['#uniqueReferencingThing']: '#album', }), - - { - dependencies: [input('notFoundMode'), '#albumAvailability'], - compute(continuation, { - [input('notFoundMode')]: notFoundMode, - ['#albumAvailability']: albumIsAvailable, - }) { - if (albumIsAvailable) return continuation(); - switch (notFoundMode) { - case 'exit': return continuation.exit(null); - case 'null': return continuation.raiseOutput({'#album': null}); - } - }, - }, - - { - dependencies: ['albumData', '#albumIndex'], - compute: (continuation, { - ['albumData']: albumData, - ['#albumIndex']: albumIndex, - }) => continuation.raiseOutput({ - ['#album']: - albumData[albumIndex], - }), - }, ], }); diff --git a/src/data/composite/things/track/withAlwaysReferenceByDirectory.js b/src/data/composite/things/track/withAlwaysReferenceByDirectory.js index fac8e21..e01720b 100644 --- a/src/data/composite/things/track/withAlwaysReferenceByDirectory.js +++ b/src/data/composite/things/track/withAlwaysReferenceByDirectory.js @@ -7,11 +7,15 @@ import {input, templateCompositeFrom} from '#composite'; import find from '#find'; import {isBoolean} from '#validators'; -import {exitWithoutDependency, exposeUpdateValueOrContinue} - from '#composite/control-flow'; import {withPropertyFromObject} from '#composite/data'; import {withResolvedReference} from '#composite/wiki-data'; +import { + exitWithoutDependency, + exposeDependencyOrContinue, + exposeUpdateValueOrContinue, +} from '#composite/control-flow'; + export default templateCompositeFrom({ annotation: `withAlwaysReferenceByDirectory`, @@ -22,6 +26,29 @@ export default templateCompositeFrom({ validate: input.value(isBoolean), }), + // withAlwaysReferenceByDirectory is sort of a fragile area - we can't + // find the track's album the normal way because albums' track lists + // recurse back into alwaysReferenceByDirectory! + withResolvedReference({ + ref: 'dataSourceAlbum', + data: 'albumData', + find: input.value(find.album), + }).outputs({ + '#resolvedReference': '#album', + }), + + withPropertyFromObject({ + object: '#album', + property: input.value('alwaysReferenceTracksByDirectory'), + }), + + // Falsy mode means this exposes true if the album's property is true, + // but continues if the property is false (which is also the default). + exposeDependencyOrContinue({ + dependency: '#album.alwaysReferenceTracksByDirectory', + mode: input.value('falsy'), + }), + // Remaining code is for defaulting to true if this track is a rerelease of // another with the same name, so everything further depends on access to // trackData as well as originalReleaseTrack. diff --git a/src/data/composite/things/track/withContainingTrackSection.js b/src/data/composite/things/track/withContainingTrackSection.js index b2e5f2b..eaac14d 100644 --- a/src/data/composite/things/track/withContainingTrackSection.js +++ b/src/data/composite/things/track/withContainingTrackSection.js @@ -1,63 +1,42 @@ // Gets the track section containing this track from its album's track list. -// If notFoundMode is set to 'exit', this will early exit if the album can't be -// found or if none of its trackSections includes the track for some reason. import {input, templateCompositeFrom} from '#composite'; import {is} from '#validators'; +import {raiseOutputWithoutDependency} from '#composite/control-flow'; + import withPropertyFromAlbum from './withPropertyFromAlbum.js'; export default templateCompositeFrom({ annotation: `withContainingTrackSection`, - inputs: { - notFoundMode: input({ - validate: is('exit', 'null'), - defaultValue: 'null', - }), - }, - outputs: ['#trackSection'], steps: () => [ withPropertyFromAlbum({ property: input.value('trackSections'), - notFoundMode: input('notFoundMode'), + }), + + raiseOutputWithoutDependency({ + dependency: '#album.trackSections', + output: input.value({'#trackSection': null}), }), { dependencies: [ input.myself(), - input('notFoundMode'), '#album.trackSections', ], - compute(continuation, { + compute: (continuation, { [input.myself()]: track, [input('notFoundMode')]: notFoundMode, ['#album.trackSections']: trackSections, - }) { - if (!trackSections) { - return continuation.raiseOutput({ - ['#trackSection']: null, - }); - } - - const trackSection = - trackSections.find(({tracks}) => tracks.includes(track)); - - if (trackSection) { - return continuation.raiseOutput({ - ['#trackSection']: trackSection, - }); - } else if (notFoundMode === 'exit') { - return continuation.exit(null); - } else { - return continuation.raiseOutput({ - ['#trackSection']: null, - }); - } - }, + }) => continuation({ + ['#trackSection']: + trackSections.find(({tracks}) => tracks.includes(track)) + ?? null, + }), }, ], }); diff --git a/src/data/composite/things/track/withPropertyFromAlbum.js b/src/data/composite/things/track/withPropertyFromAlbum.js index b236a6e..d41390f 100644 --- a/src/data/composite/things/track/withPropertyFromAlbum.js +++ b/src/data/composite/things/track/withPropertyFromAlbum.js @@ -1,7 +1,5 @@ // Gets a single property from this track's album, providing it as the same -// property name prefixed with '#album.' (by default). If the track's album -// isn't available, then by default, the property will be provided as null; -// set {notFoundMode: 'exit'} to early exit instead. +// property name prefixed with '#album.' (by default). import {input, templateCompositeFrom} from '#composite'; import {is} from '#validators'; @@ -15,11 +13,6 @@ export default templateCompositeFrom({ inputs: { property: input.staticValue({type: 'string'}), - - notFoundMode: input({ - validate: is('exit', 'null'), - defaultValue: 'null', - }), }, outputs: ({ @@ -27,9 +20,7 @@ export default templateCompositeFrom({ }) => ['#album.' + property], steps: () => [ - withAlbum({ - notFoundMode: input('notFoundMode'), - }), + withAlbum(), withPropertyFromObject({ object: '#album', diff --git a/src/data/composite/things/track/withPropertyFromOriginalRelease.js b/src/data/composite/things/track/withPropertyFromOriginalRelease.js new file mode 100644 index 0000000..fd37f6d --- /dev/null +++ b/src/data/composite/things/track/withPropertyFromOriginalRelease.js @@ -0,0 +1,86 @@ +// Provides a value inherited from the original release, if applicable, and a +// flag indicating if this track is a rerelase or not. +// +// Like withOriginalRelease, this will early exit (with notFoundValue) if the +// original release is specified by reference and that reference doesn't +// resolve to anything. + +import {input, templateCompositeFrom} from '#composite'; + +import {withResultOfAvailabilityCheck} from '#composite/control-flow'; +import {withPropertyFromObject} from '#composite/data'; + +import withOriginalRelease from './withOriginalRelease.js'; + +export default templateCompositeFrom({ + annotation: `inheritFromOriginalRelease`, + + inputs: { + property: input({type: 'string'}), + + notFoundValue: input({ + defaultValue: null, + }), + }, + + outputs: ({ + [input.staticValue('property')]: property, + }) => + ['#isRerelease'].concat( + (property + ? ['#original.' + property] + : ['#originalValue'])), + + steps: () => [ + withOriginalRelease({ + notFoundValue: input('notFoundValue'), + }), + + withResultOfAvailabilityCheck({ + from: '#originalRelease', + }), + + { + dependencies: [ + '#availability', + input.staticValue('property'), + ], + + compute: (continuation, { + ['#availability']: availability, + [input.staticValue('property')]: property, + }) => + (availability + ? continuation() + : continuation.raiseOutput( + Object.assign( + {'#isRerelease': false}, + (property + ? {['#original.' + property]: null} + : {'#originalValue': null})))), + }, + + withPropertyFromObject({ + object: '#originalRelease', + property: input('property'), + }), + + { + dependencies: [ + '#value', + input.staticValue('property'), + ], + + compute: (continuation, { + ['#value']: value, + [input.staticValue('property')]: property, + }) => + continuation.raiseOutput( + Object.assign( + {'#isRerelease': true}, + (property + ? {['#original.' + property]: value} + : {'#originalValue': value}))), + }, + ], +}); |