From 06cf8a27117cf1b77104b75e1e34375f064134ed Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Mon, 4 Mar 2024 13:34:56 -0400 Subject: data: transparent basic Contribution objects --- package.json | 1 + src/data/composite/things/contribution/index.js | 1 + .../things/contribution/withContributionArtist.js | 31 +++++++ .../composite/wiki-data/withResolvedContribs.js | 57 ++++++++----- src/data/things/contribution.js | 97 ++++++++++++++++++++++ src/data/things/index.js | 2 + test/unit/data/things/track.js | 12 +-- 7 files changed, 176 insertions(+), 25 deletions(-) create mode 100644 src/data/composite/things/contribution/index.js create mode 100644 src/data/composite/things/contribution/withContributionArtist.js create mode 100644 src/data/things/contribution.js diff --git a/package.json b/package.json index 5ae6772f..ace852ad 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "#composite/wiki-data": "./src/data/composite/wiki-data/index.js", "#composite/wiki-properties": "./src/data/composite/wiki-properties/index.js", "#composite/things/album": "./src/data/composite/things/album/index.js", + "#composite/things/contribution": "./src/data/composite/things/contribution/index.js", "#composite/things/flash": "./src/data/composite/things/flash/index.js", "#composite/things/flash-act": "./src/data/composite/things/flash-act/index.js", "#composite/things/track": "./src/data/composite/things/track/index.js", diff --git a/src/data/composite/things/contribution/index.js b/src/data/composite/things/contribution/index.js new file mode 100644 index 00000000..c0506a2b --- /dev/null +++ b/src/data/composite/things/contribution/index.js @@ -0,0 +1 @@ +export {default as withContributionArtist} from './withContributionArtist.js'; diff --git a/src/data/composite/things/contribution/withContributionArtist.js b/src/data/composite/things/contribution/withContributionArtist.js new file mode 100644 index 00000000..9e588936 --- /dev/null +++ b/src/data/composite/things/contribution/withContributionArtist.js @@ -0,0 +1,31 @@ +import {input, templateCompositeFrom} from '#composite'; +import find from '#find'; + +import {withPropertyFromObject} from '#composite/data'; +import {withResolvedReference} from '#composite/wiki-data'; + +export default templateCompositeFrom({ + annotation: `withOwnContributionArtist`, + + inputs: { + ref: input({type: 'string'}), + }, + + outputs: ['#artist'], + + steps: () => [ + withPropertyFromObject({ + object: 'thing', + property: input.value('artistData'), + internal: input.value(true), + }), + + withResolvedReference({ + ref: input('ref'), + data: '#thing.artistData', + find: input.value(find.artist), + }).outputs({ + '#resolvedReference': '#artist', + }), + ], +}); diff --git a/src/data/composite/wiki-data/withResolvedContribs.js b/src/data/composite/wiki-data/withResolvedContribs.js index 95266382..7ff7b1bc 100644 --- a/src/data/composite/wiki-data/withResolvedContribs.js +++ b/src/data/composite/wiki-data/withResolvedContribs.js @@ -7,17 +7,11 @@ import {input, templateCompositeFrom} from '#composite'; import find from '#find'; import {filterMultipleArrays, stitchArrays} from '#sugar'; +import thingConstructors from '#things'; import {is, isContributionList} from '#validators'; -import { - raiseOutputWithoutDependency, -} from '#composite/control-flow'; - -import { - withPropertiesFromList, -} from '#composite/data'; - -import withResolvedReferenceList from './withResolvedReferenceList.js'; +import {raiseOutputWithoutDependency} from '#composite/control-flow'; +import {withPropertiesFromList} from '#composite/data'; export default templateCompositeFrom({ annotation: `withResolvedContribs`, @@ -51,15 +45,6 @@ export default templateCompositeFrom({ prefix: input.value('#contribs'), }), - withResolvedReferenceList({ - list: '#contribs.artist', - data: 'artistData', - find: input.value(find.artist), - notFoundMode: input('notFoundMode'), - }).outputs({ - ['#resolvedReferenceList']: '#contribs.artist', - }), - { dependencies: ['#contribs.artist', '#contribs.annotation'], @@ -68,11 +53,45 @@ export default templateCompositeFrom({ ['#contribs.annotation']: annotation, }) { filterMultipleArrays(artist, annotation, (artist, _annotation) => artist); + return continuation({ - ['#resolvedContribs']: + ['#details']: stitchArrays({artist, annotation}), }); }, }, + + { + dependencies: ['#details', input.myself()], + + compute: (continuation, { + ['#details']: details, + [input.myself()]: myself, + }) => continuation({ + ['#contributions']: + details.map(details => { + const contrib = new thingConstructors.Contribution(); + + Object.assign(contrib, { + ...details, + thing: myself, + }); + + return contrib; + }), + }), + }, + + { + dependencies: ['#contributions'], + + compute: (continuation, { + ['#contributions']: contributions, + }) => continuation({ + ['#resolvedContribs']: + contributions + .filter(contrib => contrib.artist), + }), + }, ], }); diff --git a/src/data/things/contribution.js b/src/data/things/contribution.js new file mode 100644 index 00000000..dc7f2157 --- /dev/null +++ b/src/data/things/contribution.js @@ -0,0 +1,97 @@ +import {inspect} from 'node:util'; + +import CacheableObject from '#cacheable-object'; +import {colors} from '#cli'; +import {input} from '#composite'; +import {empty} from '#sugar'; +import Thing from '#thing'; +import {isStringNonEmpty, isThing, validateReference} from '#validators'; + +import {exposeDependency} from '#composite/control-flow'; +import {withResolvedReference} from '#composite/wiki-data'; + +import {withContributionArtist} from '#composite/things/contribution'; + +export class Contribution extends Thing { + static [Thing.getPropertyDescriptors] = () => ({ + // Update & expose + + thing: { + flags: {update: true, expose: true}, + update: {validate: isThing}, + }, + + artist: [ + withContributionArtist({ + ref: input.updateValue({ + validate: validateReference('artist'), + }), + }), + + exposeDependency({ + dependency: '#artist', + }), + ], + + annotation: { + flags: {update: true, expose: true}, + update: {validate: isStringNonEmpty}, + }, + }); + + [inspect.custom](depth, options, inspect) { + const parts = []; + const accentParts = []; + + parts.push(Thing.prototype[inspect.custom].apply(this)); + + if (this.annotation) { + accentParts.push(colors.green(`"${this.annotation}"`)); + } + + let artistRef; + if (depth >= 0) { + let artist; + try { + artist = this.artist; + } catch (_error) { + // Computing artist might crash for any reason - don't distract from + // other errors as a result of inspecting this contribution. + } + + if (artist) { + artistRef = + colors.blue(Thing.getReference(artist)); + } + } else { + artistRef = + colors.green(CacheableObject.getUpdateValue(this, 'artist')); + } + + if (artistRef) { + accentParts.push(`by ${artistRef}`); + } + + if (this.thing) { + if (depth >= 0) { + const newOptions = { + ...options, + depth: + (options.depth === null + ? null + : options.depth - 1), + }; + + accentParts.push(`to ${inspect(this.thing, newOptions)}`); + } else { + accentParts.push(`to ${colors.blue(Thing.getReference(this.thing))}`); + } + } + + if (!empty(accentParts)) { + parts.push(` (${accentParts.join(', ')})`); + } + + return parts.join(''); + } +} diff --git a/src/data/things/index.js b/src/data/things/index.js index 4f87f492..f18e283a 100644 --- a/src/data/things/index.js +++ b/src/data/things/index.js @@ -11,6 +11,7 @@ import Thing from '#thing'; import * as albumClasses from './album.js'; import * as artTagClasses from './art-tag.js'; import * as artistClasses from './artist.js'; +import * as contributionClasses from './contribution.js'; import * as flashClasses from './flash.js'; import * as groupClasses from './group.js'; import * as homepageLayoutClasses from './homepage-layout.js'; @@ -24,6 +25,7 @@ const allClassLists = { 'album.js': albumClasses, 'art-tag.js': artTagClasses, 'artist.js': artistClasses, + 'contribution.js': contributionClasses, 'flash.js': flashClasses, 'group.js': groupClasses, 'homepage-layout.js': homepageLayoutClasses, diff --git a/test/unit/data/things/track.js b/test/unit/data/things/track.js index c6695b6f..74231e20 100644 --- a/test/unit/data/things/track.js +++ b/test/unit/data/things/track.js @@ -280,7 +280,7 @@ t.test(`Track.artistContribs`, t => { XXX_decacheWikiData(); - t.same(track.artistContribs, + t.match(track.artistContribs, [{artist: artist1, annotation: `composition`}, {artist: artist2, annotation: null}], `artistContribs #2: inherits album artistContribs`); @@ -288,7 +288,7 @@ t.test(`Track.artistContribs`, t => { {artist: `Artist 1`, annotation: `arrangement`}, ]; - t.same(track.artistContribs, [{artist: artist1, annotation: `arrangement`}], + t.match(track.artistContribs, [{artist: artist1, annotation: `arrangement`}], `artistContribs #3: resolves from own value`); track.artistContribs = [ @@ -297,7 +297,7 @@ t.test(`Track.artistContribs`, t => { {artist: `Artist 2`, annotation: `usual`}, ]; - t.same(track.artistContribs, + t.match(track.artistContribs, [{artist: artist1, annotation: `snooping`}, {artist: artist2, annotation: `usual`}], `artistContribs #4: filters out names without matches`); }); @@ -457,7 +457,7 @@ t.test(`Track.coverArtistContribs`, t => { XXX_decacheWikiData(); - t.same(track.coverArtistContribs, + t.match(track.coverArtistContribs, [{artist: artist1, annotation: `lines`}, {artist: artist2, annotation: null}], `coverArtistContribs #2: inherits album trackCoverArtistContribs`); @@ -465,7 +465,7 @@ t.test(`Track.coverArtistContribs`, t => { {artist: `Artist 1`, annotation: `collage`}, ]; - t.same(track.coverArtistContribs, [{artist: artist1, annotation: `collage`}], + t.match(track.coverArtistContribs, [{artist: artist1, annotation: `collage`}], `coverArtistContribs #3: resolves from own value`); track.coverArtistContribs = [ @@ -474,7 +474,7 @@ t.test(`Track.coverArtistContribs`, t => { {artist: `Artist 2`, annotation: `usual`}, ]; - t.same(track.coverArtistContribs, + t.match(track.coverArtistContribs, [{artist: artist1, annotation: `snooping`}, {artist: artist2, annotation: `usual`}], `coverArtistContribs #4: filters out names without matches`); -- cgit 1.3.0-6-gf8a5