From ab7591e45e7e31b4e2c0e2f81e224672145993fa Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Sun, 1 Oct 2023 17:01:21 -0300 Subject: data, test: refactor utilities into own file Primarily for more precies test coverage mapping, but also to make navigation a bit easier and consolidate complex functions with lots of imports out of the same space as other, more simple or otherwise specialized files. --- src/data/composite/things/track/withAlbum.js | 57 ++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 src/data/composite/things/track/withAlbum.js (limited to 'src/data/composite/things/track/withAlbum.js') diff --git a/src/data/composite/things/track/withAlbum.js b/src/data/composite/things/track/withAlbum.js new file mode 100644 index 00000000..34845ab0 --- /dev/null +++ b/src/data/composite/things/track/withAlbum.js @@ -0,0 +1,57 @@ +// 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. + +import {input, templateCompositeFrom} from '#composite'; +import {is} from '#validators'; + +import {raiseOutputWithoutDependency} from '#composite/control-flow'; + +export default templateCompositeFrom({ + annotation: `withAlbum`, + + inputs: { + notFoundMode: input({ + validate: is('exit', 'null'), + defaultValue: 'null', + }), + }, + + outputs: ['#album'], + + steps: () => [ + raiseOutputWithoutDependency({ + dependency: 'albumData', + mode: input.value('empty'), + output: input.value({ + ['#album']: null, + }), + }), + + { + dependencies: [input.myself(), 'albumData'], + compute: (continuation, { + [input.myself()]: track, + ['albumData']: albumData, + }) => + continuation({ + ['#album']: + albumData.find(album => album.tracks.includes(track)), + }), + }, + + raiseOutputWithoutDependency({ + dependency: '#album', + output: input.value({ + ['#album']: null, + }), + }), + + { + dependencies: ['#album'], + compute: (continuation, {'#album': album}) => + continuation.raiseOutput({'#album': album}), + }, + ], +}); -- cgit 1.3.0-6-gf8a5 From c7e21005beb8807216aac6ed3ae54029575007a1 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 26 Oct 2023 18:03:24 -0300 Subject: data: Track.withAlbum: bulkily match documented early exit behavior --- src/data/composite/things/track/withAlbum.js | 45 +++++++++++++++------------- 1 file changed, 25 insertions(+), 20 deletions(-) (limited to 'src/data/composite/things/track/withAlbum.js') diff --git a/src/data/composite/things/track/withAlbum.js b/src/data/composite/things/track/withAlbum.js index 34845ab0..0e85cee9 100644 --- a/src/data/composite/things/track/withAlbum.js +++ b/src/data/composite/things/track/withAlbum.js @@ -4,10 +4,9 @@ // exit instead. import {input, templateCompositeFrom} from '#composite'; +import {empty} from '#sugar'; import {is} from '#validators'; -import {raiseOutputWithoutDependency} from '#composite/control-flow'; - export default templateCompositeFrom({ annotation: `withAlbum`, @@ -21,13 +20,20 @@ export default templateCompositeFrom({ outputs: ['#album'], steps: () => [ - raiseOutputWithoutDependency({ - dependency: 'albumData', - mode: input.value('empty'), - output: input.value({ - ['#album']: null, - }), - }), + { + dependencies: [input('notFoundMode'), 'albumData'], + compute: (continuation, { + [input('notFoundMode')]: notFoundMode, + ['albumData']: albumData, + }) => + (albumData === null + ? continuation.exit(null) + : empty(albumData) + ? (notFoundMode === 'exit' + ? continuation.exit(null) + : continuation.raiseOutput({'#album': null})) + : continuation()), + }, { dependencies: [input.myself(), 'albumData'], @@ -37,21 +43,20 @@ export default templateCompositeFrom({ }) => continuation({ ['#album']: - albumData.find(album => album.tracks.includes(track)), + albumData.find(album => album.tracks.includes(track)) + ?? null, }), }, - raiseOutputWithoutDependency({ - dependency: '#album', - output: input.value({ - ['#album']: null, - }), - }), - { - dependencies: ['#album'], - compute: (continuation, {'#album': album}) => - continuation.raiseOutput({'#album': album}), + dependencies: [input('notFoundMode'), '#album'], + compute: (continuation, { + [input('notFoundMode')]: notFoundMode, + ['#album']: album, + }) => + ((album === null && notFoundMode === 'exit') + ? continuation.exit(null) + : continuation.raiseOutput({'#album': album})), }, ], }); -- cgit 1.3.0-6-gf8a5 From bb646f28853399a43d52a056c86d04f6a4343932 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 26 Oct 2023 19:09:22 -0300 Subject: data: Track.withAlbum: refactor for clarity Utilizes availability checks instead of manual null comparisons and empty() calls, extracts track lists using withPropertyFromList, operates on index instead of unique album object where possible (including found / not found check). --- src/data/composite/things/track/withAlbum.js | 98 ++++++++++++++++++++-------- 1 file changed, 71 insertions(+), 27 deletions(-) (limited to 'src/data/composite/things/track/withAlbum.js') diff --git a/src/data/composite/things/track/withAlbum.js b/src/data/composite/things/track/withAlbum.js index 0e85cee9..9c974cd1 100644 --- a/src/data/composite/things/track/withAlbum.js +++ b/src/data/composite/things/track/withAlbum.js @@ -4,9 +4,12 @@ // exit instead. import {input, templateCompositeFrom} from '#composite'; -import {empty} from '#sugar'; import {is} from '#validators'; +import {exitWithoutDependency, withResultOfAvailabilityCheck} + from '#composite/control-flow'; +import {withPropertyFromList} from '#composite/data'; + export default templateCompositeFrom({ annotation: `withAlbum`, @@ -20,43 +23,84 @@ export default templateCompositeFrom({ 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'), 'albumData'], - compute: (continuation, { + dependencies: [input('notFoundMode'), '#albumDataAvailability'], + compute(continuation, { [input('notFoundMode')]: notFoundMode, - ['albumData']: albumData, - }) => - (albumData === null - ? continuation.exit(null) - : empty(albumData) - ? (notFoundMode === 'exit' - ? continuation.exit(null) - : continuation.raiseOutput({'#album': null})) - : continuation()), + ['#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'], + dependencies: [input.myself(), '#albumData.tracks'], compute: (continuation, { [input.myself()]: track, - ['albumData']: albumData, - }) => - continuation({ - ['#album']: - albumData.find(album => album.tracks.includes(track)) - ?? null, - }), + ['#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'), + }).outputs({ + '#availability': '#albumAvailability', + }), + { - dependencies: [input('notFoundMode'), '#album'], - compute: (continuation, { + dependencies: [input('notFoundMode'), '#albumAvailability'], + compute(continuation, { [input('notFoundMode')]: notFoundMode, - ['#album']: album, - }) => - ((album === null && notFoundMode === 'exit') - ? continuation.exit(null) - : continuation.raiseOutput({'#album': album})), + ['#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], + }), }, ], }); -- cgit 1.3.0-6-gf8a5 From 855dcdbc17831809cfb3c800d378c62186702740 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 26 Oct 2023 19:30:40 -0300 Subject: data: Flash.withFlashAct --- src/data/composite/things/track/withAlbum.js | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/data/composite/things/track/withAlbum.js') diff --git a/src/data/composite/things/track/withAlbum.js b/src/data/composite/things/track/withAlbum.js index 9c974cd1..cbd16dcd 100644 --- a/src/data/composite/things/track/withAlbum.js +++ b/src/data/composite/things/track/withAlbum.js @@ -2,6 +2,8 @@ // 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. import {input, templateCompositeFrom} from '#composite'; import {is} from '#validators'; -- cgit 1.3.0-6-gf8a5