diff options
Diffstat (limited to 'src/data/composite/wiki-properties')
21 files changed, 529 insertions, 162 deletions
diff --git a/src/data/composite/wiki-properties/additionalFiles.js b/src/data/composite/wiki-properties/additionalFiles.js deleted file mode 100644 index 6760527a..00000000 --- a/src/data/composite/wiki-properties/additionalFiles.js +++ /dev/null @@ -1,30 +0,0 @@ -// This is a somewhat more involved data structure - it's for additional -// or "bonus" files associated with albums or tracks (or anything else). -// It's got this form: -// -// [ -// {title: 'Booklet', files: ['Booklet.pdf']}, -// { -// title: 'Wallpaper', -// description: 'Cool Wallpaper!', -// files: ['1440x900.png', '1920x1080.png'] -// }, -// {title: 'Alternate Covers', description: null, files: [...]}, -// ... -// ] -// - -import {isAdditionalFileList} from '#validators'; - -// TODO: Not templateCompositeFrom. - -export default function() { - return { - flags: {update: true, expose: true}, - update: {validate: isAdditionalFileList}, - expose: { - transform: (additionalFiles) => - additionalFiles ?? [], - }, - }; -} diff --git a/src/data/composite/wiki-properties/additionalNameList.js b/src/data/composite/wiki-properties/additionalNameList.js deleted file mode 100644 index c5971d4a..00000000 --- a/src/data/composite/wiki-properties/additionalNameList.js +++ /dev/null @@ -1,14 +0,0 @@ -// A list of additional names! These can be used for a variety of purposes, -// e.g. providing extra searchable titles, localizations, romanizations or -// original titles, and so on. Each item has a name and, optionally, a -// descriptive annotation. - -import {isAdditionalNameList} from '#validators'; - -export default function() { - return { - flags: {update: true, expose: true}, - update: {validate: isAdditionalNameList}, - expose: {transform: value => value ?? []}, - }; -} diff --git a/src/data/composite/wiki-properties/annotatedReferenceList.js b/src/data/composite/wiki-properties/annotatedReferenceList.js new file mode 100644 index 00000000..8e6c96a1 --- /dev/null +++ b/src/data/composite/wiki-properties/annotatedReferenceList.js @@ -0,0 +1,64 @@ +import {input, templateCompositeFrom} from '#composite'; + +import { + isContentString, + optional, + validateArrayItems, + validateProperties, + validateReference, +} from '#validators'; + +import {exposeDependency} from '#composite/control-flow'; +import {inputSoupyFind, inputWikiData, withResolvedAnnotatedReferenceList} + from '#composite/wiki-data'; + +import {referenceListInputDescriptions, referenceListUpdateDescription} + from './helpers/reference-list-helpers.js'; + +export default templateCompositeFrom({ + annotation: `annotatedReferenceList`, + + compose: false, + + inputs: { + ...referenceListInputDescriptions(), + + data: inputWikiData({allowMixedTypes: true}), + find: inputSoupyFind(), + + reference: input.staticValue({type: 'string', defaultValue: 'reference'}), + annotation: input.staticValue({type: 'string', defaultValue: 'annotation'}), + thing: input.staticValue({type: 'string', defaultValue: 'thing'}), + }, + + update(staticInputs) { + const { + [input.staticValue('reference')]: referenceProperty, + [input.staticValue('annotation')]: annotationProperty, + } = staticInputs; + + return referenceListUpdateDescription({ + validateReferenceList: type => + validateArrayItems( + validateProperties({ + [referenceProperty]: validateReference(type), + [annotationProperty]: optional(isContentString), + })), + })(staticInputs); + }, + + steps: () => [ + withResolvedAnnotatedReferenceList({ + list: input.updateValue(), + + reference: input('reference'), + annotation: input('annotation'), + thing: input('thing'), + + data: input('data'), + find: input('find'), + }), + + exposeDependency({dependency: '#resolvedAnnotatedReferenceList'}), + ], +}); diff --git a/src/data/composite/wiki-properties/commentary.js b/src/data/composite/wiki-properties/commentary.js deleted file mode 100644 index cd6b7ac4..00000000 --- a/src/data/composite/wiki-properties/commentary.js +++ /dev/null @@ -1,30 +0,0 @@ -// Artist commentary! Generally present on tracks and albums. - -import {input, templateCompositeFrom} from '#composite'; -import {isCommentary} from '#validators'; - -import {exitWithoutDependency, exposeDependency} - from '#composite/control-flow'; -import {withParsedCommentaryEntries} from '#composite/wiki-data'; - -export default templateCompositeFrom({ - annotation: `commentary`, - - compose: false, - - steps: () => [ - exitWithoutDependency({ - dependency: input.updateValue({validate: isCommentary}), - mode: input.value('falsy'), - value: input.value(null), - }), - - withParsedCommentaryEntries({ - from: input.updateValue(), - }), - - exposeDependency({ - dependency: '#parsedCommentaryEntries', - }), - ], -}); diff --git a/src/data/composite/wiki-properties/commentatorArtists.js b/src/data/composite/wiki-properties/commentatorArtists.js index c5c14769..54d3e1a5 100644 --- a/src/data/composite/wiki-properties/commentatorArtists.js +++ b/src/data/composite/wiki-properties/commentatorArtists.js @@ -7,7 +7,6 @@ import {exitWithoutDependency, exposeDependency} from '#composite/control-flow'; import {withFlattenedList, withPropertyFromList, withUniqueItemsOnly} from '#composite/data'; -import {withParsedCommentaryEntries} from '#composite/wiki-data'; export default templateCompositeFrom({ annotation: `commentatorArtists`, @@ -21,19 +20,13 @@ export default templateCompositeFrom({ value: input.value([]), }), - withParsedCommentaryEntries({ - from: 'commentary', - }), - withPropertyFromList({ - list: '#parsedCommentaryEntries', + list: 'commentary', property: input.value('artists'), - }).outputs({ - '#parsedCommentaryEntries.artists': '#artistLists', }), withFlattenedList({ - list: '#artistLists', + list: '#commentary.artists', }).outputs({ '#flattenedList': '#artists', }), diff --git a/src/data/composite/wiki-properties/constitutibleArtwork.js b/src/data/composite/wiki-properties/constitutibleArtwork.js new file mode 100644 index 00000000..48f4211a --- /dev/null +++ b/src/data/composite/wiki-properties/constitutibleArtwork.js @@ -0,0 +1,70 @@ +// This composition does not actually inspect the values of any properties +// specified, so it's not responsible for determining whether a constituted +// artwork should exist at all. + +import {input, templateCompositeFrom} from '#composite'; +import {withEntries} from '#sugar'; +import Thing from '#thing'; +import {validateThing} from '#validators'; + +import {exposeDependency, exposeUpdateValueOrContinue} + from '#composite/control-flow'; +import {withConstitutedArtwork} from '#composite/wiki-data'; + +const template = templateCompositeFrom({ + annotation: `constitutibleArtwork`, + + compose: false, + + inputs: { + thingProperty: input({type: 'string', acceptsNull: true}), + dimensionsFromThingProperty: input({type: 'string', acceptsNull: true}), + fileExtensionFromThingProperty: input({type: 'string', acceptsNull: true}), + dateFromThingProperty: input({type: 'string', acceptsNull: true}), + artistContribsFromThingProperty: input({type: 'string', acceptsNull: true}), + artistContribsArtistProperty: input({type: 'string', acceptsNull: true}), + artTagsFromThingProperty: input({type: 'string', acceptsNull: true}), + referencedArtworksFromThingProperty: input({type: 'string', acceptsNull: true}), + }, + + steps: () => [ + exposeUpdateValueOrContinue({ + validate: input.value( + validateThing({ + referenceType: 'artwork', + })), + }), + + withConstitutedArtwork({ + thingProperty: input('thingProperty'), + dimensionsFromThingProperty: input('dimensionsFromThingProperty'), + fileExtensionFromThingProperty: input('fileExtensionFromThingProperty'), + dateFromThingProperty: input('dateFromThingProperty'), + artistContribsFromThingProperty: input('artistContribsFromThingProperty'), + artistContribsArtistProperty: input('artistContribsArtistProperty'), + artTagsFromThingProperty: input('artTagsFromThingProperty'), + referencedArtworksFromThingProperty: input('referencedArtworksFromThingProperty'), + }), + + exposeDependency({ + dependency: '#constitutedArtwork', + }), + ], +}); + +template.fromYAMLFieldSpec = function(field) { + const {[Thing.yamlDocumentSpec]: documentSpec} = this; + + const {provide} = documentSpec.fields[field].transform; + + const inputs = + withEntries(provide, entries => + entries.map(([property, value]) => [ + property, + input.value(value), + ])); + + return template(inputs); +}; + +export default template; diff --git a/src/data/composite/wiki-properties/constitutibleArtworkList.js b/src/data/composite/wiki-properties/constitutibleArtworkList.js new file mode 100644 index 00000000..dad3a957 --- /dev/null +++ b/src/data/composite/wiki-properties/constitutibleArtworkList.js @@ -0,0 +1,72 @@ +// This composition does not actually inspect the values of any properties +// specified, so it's not responsible for determining whether a constituted +// artwork should exist at all. + +import {input, templateCompositeFrom} from '#composite'; +import {withEntries} from '#sugar'; +import Thing from '#thing'; +import {validateWikiData} from '#validators'; + +import {exposeUpdateValueOrContinue} from '#composite/control-flow'; +import {withConstitutedArtwork} from '#composite/wiki-data'; + +const template = templateCompositeFrom({ + annotation: `constitutibleArtworkList`, + + compose: false, + + inputs: { + thingProperty: input({type: 'string', acceptsNull: true}), + dimensionsFromThingProperty: input({type: 'string', acceptsNull: true}), + fileExtensionFromThingProperty: input({type: 'string', acceptsNull: true}), + dateFromThingProperty: input({type: 'string', acceptsNull: true}), + artistContribsFromThingProperty: input({type: 'string', acceptsNull: true}), + artistContribsArtistProperty: input({type: 'string', acceptsNull: true}), + artTagsFromThingProperty: input({type: 'string', acceptsNull: true}), + referencedArtworksFromThingProperty: input({type: 'string', acceptsNull: true}), + }, + + steps: () => [ + exposeUpdateValueOrContinue({ + validate: input.value( + validateWikiData({ + referenceType: 'artwork', + })), + }), + + withConstitutedArtwork({ + thingProperty: input('thingProperty'), + dimensionsFromThingProperty: input('dimensionsFromThingProperty'), + fileExtensionFromThingProperty: input('fileExtensionFromThingProperty'), + dateFromThingProperty: input('dateFromThingProperty'), + artistContribsFromThingProperty: input('artistContribsFromThingProperty'), + artistContribsArtistProperty: input('artistContribsArtistProperty'), + artTagsFromThingProperty: input('artTagsFromThingProperty'), + referencedArtworksFromThingProperty: input('referencedArtworksFromThingProperty'), + }), + + { + dependencies: ['#constitutedArtwork'], + compute: ({ + ['#constitutedArtwork']: constitutedArtwork, + }) => [constitutedArtwork], + }, + ], +}); + +template.fromYAMLFieldSpec = function(field) { + const {[Thing.yamlDocumentSpec]: documentSpec} = this; + + const {provide} = documentSpec.fields[field].transform; + + const inputs = + withEntries(provide, entries => + entries.map(([property, value]) => [ + property, + input.value(value), + ])); + + return template(inputs); +}; + +export default template; diff --git a/src/data/composite/wiki-properties/contributionList.js b/src/data/composite/wiki-properties/contributionList.js index 8fde2caa..d9a6b417 100644 --- a/src/data/composite/wiki-properties/contributionList.js +++ b/src/data/composite/wiki-properties/contributionList.js @@ -3,19 +3,19 @@ // into one property. Update value will look something like this: // // [ -// {who: 'Artist Name', what: 'Viola'}, -// {who: 'artist:john-cena', what: null}, +// {artist: 'Artist Name', annotation: 'Viola'}, +// {artist: 'artist:john-cena', annotation: null}, // ... // ] // // ...typically as processed from YAML, spreadsheet, or elsewhere. -// Exposes as the same, but with the "who" replaced with matches found in -// artistData - which means this always depends on an `artistData` property -// also existing on this object! +// Exposes as the same, but with the artist property replaced with matches +// found in artistData - which means this always depends on an `artistData` +// property also existing on this object! // import {input, templateCompositeFrom} from '#composite'; -import {isContributionList} from '#validators'; +import {isContributionList, isDate, isStringNonEmpty} from '#validators'; import {exposeConstant, exposeDependencyOrContinue} from '#composite/control-flow'; import {withResolvedContribs} from '#composite/wiki-data'; @@ -25,11 +25,34 @@ export default templateCompositeFrom({ compose: false, + inputs: { + date: input({ + validate: isDate, + acceptsNull: true, + }), + + artistProperty: input({ + validate: isStringNonEmpty, + defaultValue: null, + }), + }, + update: {validate: isContributionList}, steps: () => [ - withResolvedContribs({from: input.updateValue()}), - exposeDependencyOrContinue({dependency: '#resolvedContribs'}), - exposeConstant({value: input.value([])}), + withResolvedContribs({ + from: input.updateValue(), + thingProperty: input.thisProperty(), + artistProperty: input('artistProperty'), + date: input('date'), + }), + + exposeDependencyOrContinue({ + dependency: '#resolvedContribs', + }), + + exposeConstant({ + value: input.value([]), + }), ], }); diff --git a/src/data/composite/wiki-properties/directory.js b/src/data/composite/wiki-properties/directory.js index 0b2181c9..1756a8e5 100644 --- a/src/data/composite/wiki-properties/directory.js +++ b/src/data/composite/wiki-properties/directory.js @@ -2,22 +2,40 @@ // almost any data object. Also corresponds to a part of the URL which pages of // such objects are visited at. -import {isDirectory} from '#validators'; -import {getKebabCase} from '#wiki-data'; - -// TODO: Not templateCompositeFrom. - -export default function() { - return { - flags: {update: true, expose: true}, - update: {validate: isDirectory}, - expose: { - dependencies: ['name'], - transform(directory, {name}) { - if (directory === null && name === null) return null; - else if (directory === null) return getKebabCase(name); - else return directory; - }, - }, - }; -} +import {input, templateCompositeFrom} from '#composite'; + +import {isDirectory, isName} from '#validators'; + +import {exposeDependency} from '#composite/control-flow'; +import {withDirectory} from '#composite/wiki-data'; + +export default templateCompositeFrom({ + annotation: `directory`, + + compose: false, + + inputs: { + name: input({ + validate: isName, + defaultDependency: 'name', + acceptsNull: true, + }), + + suffix: input({ + validate: isDirectory, + defaultValue: null, + }), + }, + + steps: () => [ + withDirectory({ + directory: input.updateValue({validate: isDirectory}), + name: input('name'), + suffix: input('suffix'), + }), + + exposeDependency({ + dependency: '#directory', + }), + ], +}); diff --git a/src/data/composite/wiki-properties/helpers/reference-list-helpers.js b/src/data/composite/wiki-properties/helpers/reference-list-helpers.js new file mode 100644 index 00000000..dfdc6b41 --- /dev/null +++ b/src/data/composite/wiki-properties/helpers/reference-list-helpers.js @@ -0,0 +1,44 @@ +import {input} from '#composite'; +import {anyOf, isString, isThingClass, validateArrayItems} from '#validators'; + +export function referenceListInputDescriptions() { + return { + class: input.staticValue({ + validate: + anyOf( + isThingClass, + validateArrayItems(isThingClass)), + + acceptsNull: true, + defaultValue: null, + }), + + referenceType: input.staticValue({ + validate: + anyOf( + isString, + validateArrayItems(isString)), + + acceptsNull: true, + defaultValue: null, + }), + }; +} + +export function referenceListUpdateDescription({ + validateReferenceList, +}) { + return ({ + [input.staticValue('class')]: thingClass, + [input.staticValue('referenceType')]: referenceType, + }) => ({ + validate: + validateReferenceList( + (Array.isArray(thingClass) + ? thingClass.map(thingClass => + thingClass[Symbol.for('Thing.referenceType')]) + : thingClass + ? thingClass[Symbol.for('Thing.referenceType')] + : referenceType)), + }); +} diff --git a/src/data/composite/wiki-properties/index.js b/src/data/composite/wiki-properties/index.js index 89cb6838..e8f109d3 100644 --- a/src/data/composite/wiki-properties/index.js +++ b/src/data/composite/wiki-properties/index.js @@ -3,11 +3,11 @@ // Entries here may depend on entries in #composite/control-flow, // #composite/data, and #composite/wiki-data. -export {default as additionalFiles} from './additionalFiles.js'; -export {default as additionalNameList} from './additionalNameList.js'; +export {default as annotatedReferenceList} from './annotatedReferenceList.js'; export {default as color} from './color.js'; -export {default as commentary} from './commentary.js'; export {default as commentatorArtists} from './commentatorArtists.js'; +export {default as constitutibleArtwork} from './constitutibleArtwork.js'; +export {default as constitutibleArtworkList} from './constitutibleArtworkList.js'; export {default as contentString} from './contentString.js'; export {default as contribsPresent} from './contribsPresent.js'; export {default as contributionList} from './contributionList.js'; @@ -19,10 +19,15 @@ export {default as fileExtension} from './fileExtension.js'; export {default as flag} from './flag.js'; export {default as name} from './name.js'; export {default as referenceList} from './referenceList.js'; -export {default as reverseContributionList} from './reverseContributionList.js'; +export {default as referencedArtworkList} from './referencedArtworkList.js'; export {default as reverseReferenceList} from './reverseReferenceList.js'; export {default as simpleDate} from './simpleDate.js'; export {default as simpleString} from './simpleString.js'; export {default as singleReference} from './singleReference.js'; +export {default as soupyFind} from './soupyFind.js'; +export {default as soupyReverse} from './soupyReverse.js'; +export {default as thing} from './thing.js'; +export {default as thingList} from './thingList.js'; export {default as urls} from './urls.js'; +export {default as wallpaperParts} from './wallpaperParts.js'; export {default as wikiData} from './wikiData.js'; diff --git a/src/data/composite/wiki-properties/referenceList.js b/src/data/composite/wiki-properties/referenceList.js index af634a68..4f8207b5 100644 --- a/src/data/composite/wiki-properties/referenceList.js +++ b/src/data/composite/wiki-properties/referenceList.js @@ -1,5 +1,6 @@ // Stores and exposes a list of references to other data objects; all items -// must be references to the same type, which is specified on the class input. +// must be references to the same type, which is either implied from the class +// input, or explicitly set on the referenceType input. // // See also: // - singleReference @@ -7,10 +8,14 @@ // import {input, templateCompositeFrom} from '#composite'; -import {isThingClass, validateReferenceList} from '#validators'; +import {validateReferenceList} from '#validators'; import {exposeDependency} from '#composite/control-flow'; -import {inputWikiData, withResolvedReferenceList} from '#composite/wiki-data'; +import {inputSoupyFind, inputWikiData, withResolvedReferenceList} + from '#composite/wiki-data'; + +import {referenceListInputDescriptions, referenceListUpdateDescription} + from './helpers/reference-list-helpers.js'; export default templateCompositeFrom({ annotation: `referenceList`, @@ -18,20 +23,16 @@ export default templateCompositeFrom({ compose: false, inputs: { - class: input.staticValue({validate: isThingClass}), - - data: inputWikiData({allowMixedTypes: false}), + ...referenceListInputDescriptions(), - find: input({type: 'function'}), + data: inputWikiData({allowMixedTypes: true}), + find: inputSoupyFind(), }, - update: ({ - [input.staticValue('class')]: thingClass, - }) => ({ - validate: - validateReferenceList( - thingClass[Symbol.for('Thing.referenceType')]), - }), + update: + referenceListUpdateDescription({ + validateReferenceList: validateReferenceList, + }), steps: () => [ withResolvedReferenceList({ diff --git a/src/data/composite/wiki-properties/referencedArtworkList.js b/src/data/composite/wiki-properties/referencedArtworkList.js new file mode 100644 index 00000000..4f243493 --- /dev/null +++ b/src/data/composite/wiki-properties/referencedArtworkList.js @@ -0,0 +1,31 @@ +import {input, templateCompositeFrom} from '#composite'; +import find from '#find'; + +import annotatedReferenceList from './annotatedReferenceList.js'; + +export default templateCompositeFrom({ + annotation: `referencedArtworkList`, + + compose: false, + + steps: () => [ + { + compute: (continuation) => continuation({ + ['#find']: + find.mixed({ + track: find.trackPrimaryArtwork, + album: find.albumPrimaryArtwork, + }), + }), + }, + + annotatedReferenceList({ + referenceType: input.value(['album', 'track']), + + data: 'artworkData', + find: '#find', + + thing: input.value('artwork'), + }), + ], +}); diff --git a/src/data/composite/wiki-properties/reverseContributionList.js b/src/data/composite/wiki-properties/reverseContributionList.js deleted file mode 100644 index 7f3f9c81..00000000 --- a/src/data/composite/wiki-properties/reverseContributionList.js +++ /dev/null @@ -1,24 +0,0 @@ -import {input, templateCompositeFrom} from '#composite'; - -import {exposeDependency} from '#composite/control-flow'; -import {inputWikiData, withReverseContributionList} from '#composite/wiki-data'; - -export default templateCompositeFrom({ - annotation: `reverseContributionList`, - - compose: false, - - inputs: { - data: inputWikiData({allowMixedTypes: false}), - list: input({type: 'string'}), - }, - - steps: () => [ - withReverseContributionList({ - data: input('data'), - list: input('list'), - }), - - exposeDependency({dependency: '#reverseContributionList'}), - ], -}); diff --git a/src/data/composite/wiki-properties/reverseReferenceList.js b/src/data/composite/wiki-properties/reverseReferenceList.js index 84ba67df..6d590a67 100644 --- a/src/data/composite/wiki-properties/reverseReferenceList.js +++ b/src/data/composite/wiki-properties/reverseReferenceList.js @@ -1,13 +1,13 @@ // Neat little shortcut for "reversing" the reference lists stored on other // things - for example, tracks specify a "referenced tracks" property, and // you would use this to compute a corresponding "referenced *by* tracks" -// property. Naturally, the passed ref list property is of the things in the -// wiki data provided, not the requesting Thing itself. +// property. import {input, templateCompositeFrom} from '#composite'; import {exposeDependency} from '#composite/control-flow'; -import {inputWikiData, withReverseReferenceList} from '#composite/wiki-data'; +import {inputSoupyReverse, inputWikiData, withReverseReferenceList} + from '#composite/wiki-data'; export default templateCompositeFrom({ annotation: `reverseReferenceList`, @@ -15,14 +15,14 @@ export default templateCompositeFrom({ compose: false, inputs: { - data: inputWikiData({allowMixedTypes: false}), - list: input({type: 'string'}), + data: inputWikiData({allowMixedTypes: true}), + reverse: inputSoupyReverse(), }, steps: () => [ withReverseReferenceList({ data: input('data'), - list: input('list'), + reverse: input('reverse'), }), exposeDependency({dependency: '#reverseReferenceList'}), diff --git a/src/data/composite/wiki-properties/singleReference.js b/src/data/composite/wiki-properties/singleReference.js index db4fc9f9..f532ebbe 100644 --- a/src/data/composite/wiki-properties/singleReference.js +++ b/src/data/composite/wiki-properties/singleReference.js @@ -11,7 +11,8 @@ import {input, templateCompositeFrom} from '#composite'; import {isThingClass, validateReference} from '#validators'; import {exposeDependency} from '#composite/control-flow'; -import {inputWikiData, withResolvedReference} from '#composite/wiki-data'; +import {inputSoupyFind, inputWikiData, withResolvedReference} + from '#composite/wiki-data'; export default templateCompositeFrom({ annotation: `singleReference`, @@ -21,8 +22,7 @@ export default templateCompositeFrom({ inputs: { class: input.staticValue({validate: isThingClass}), - find: input({type: 'function'}), - + find: inputSoupyFind(), data: inputWikiData({allowMixedTypes: false}), }, diff --git a/src/data/composite/wiki-properties/soupyFind.js b/src/data/composite/wiki-properties/soupyFind.js new file mode 100644 index 00000000..0f9a17e3 --- /dev/null +++ b/src/data/composite/wiki-properties/soupyFind.js @@ -0,0 +1,14 @@ +import {isObject} from '#validators'; + +import {inputSoupyFind} from '#composite/wiki-data'; + +function soupyFind() { + return { + flags: {update: true}, + update: {validate: isObject}, + }; +} + +soupyFind.input = inputSoupyFind.input; + +export default soupyFind; diff --git a/src/data/composite/wiki-properties/soupyReverse.js b/src/data/composite/wiki-properties/soupyReverse.js new file mode 100644 index 00000000..784a66b4 --- /dev/null +++ b/src/data/composite/wiki-properties/soupyReverse.js @@ -0,0 +1,37 @@ +import {isObject} from '#validators'; + +import {inputSoupyReverse} from '#composite/wiki-data'; + +function soupyReverse() { + return { + flags: {update: true}, + update: {validate: isObject}, + }; +} + +soupyReverse.input = inputSoupyReverse.input; + +soupyReverse.contributionsBy = + (bindTo, contributionsProperty) => ({ + bindTo, + + referencing: thing => thing[contributionsProperty], + referenced: contrib => [contrib.artist], + }); + +soupyReverse.artworkContributionsBy = + (bindTo, artworkProperty, {single = false} = {}) => ({ + bindTo, + + referencing: thing => + (single + ? (thing[artworkProperty] + ? thing[artworkProperty].artistContribs + : []) + : thing[artworkProperty] + .flatMap(artwork => artwork.artistContribs)), + + referenced: contrib => [contrib.artist], + }); + +export default soupyReverse; diff --git a/src/data/composite/wiki-properties/thing.js b/src/data/composite/wiki-properties/thing.js new file mode 100644 index 00000000..1f97a362 --- /dev/null +++ b/src/data/composite/wiki-properties/thing.js @@ -0,0 +1,40 @@ +// An individual Thing, provided directly rather than by reference. + +import {input, templateCompositeFrom} from '#composite'; +import {isThingClass, validateThing} from '#validators'; + +import {exposeConstant, exposeUpdateValueOrContinue} + from '#composite/control-flow'; + +export default templateCompositeFrom({ + annotation: `wikiData`, + + compose: false, + + inputs: { + class: input.staticValue({ + validate: isThingClass, + defaultValue: null, + }), + }, + + update: ({ + [input.staticValue('class')]: thingClass, + }) => ({ + validate: + validateThing({ + referenceType: + (thingClass + ? thingClass[Symbol.for('Thing.referenceType')] + : ''), + }), + }), + + steps: () => [ + exposeUpdateValueOrContinue(), + + exposeConstant({ + value: input.value(null), + }), + ], +}); diff --git a/src/data/composite/wiki-properties/thingList.js b/src/data/composite/wiki-properties/thingList.js new file mode 100644 index 00000000..f4c00e06 --- /dev/null +++ b/src/data/composite/wiki-properties/thingList.js @@ -0,0 +1,44 @@ +// A list of Things, provided directly rather than by reference. +// +// Essentially the same as wikiData, but exposes the list of things, +// instead of keeping it private. + +import {input, templateCompositeFrom} from '#composite'; +import {isThingClass, validateWikiData} from '#validators'; + +import {exposeConstant, exposeUpdateValueOrContinue} + from '#composite/control-flow'; + +export default templateCompositeFrom({ + annotation: `wikiData`, + + compose: false, + + inputs: { + class: input.staticValue({ + validate: isThingClass, + defaultValue: null, + }), + }, + + update: ({ + [input.staticValue('class')]: thingClass, + }) => ({ + validate: + validateWikiData({ + referenceType: + (thingClass + ? thingClass[Symbol.for('Thing.referenceType')] + : ''), + }), + }), + + steps: () => [ + exposeUpdateValueOrContinue(), + + exposeConstant({ + value: input.value([]), + }), + ], +}); + diff --git a/src/data/composite/wiki-properties/wallpaperParts.js b/src/data/composite/wiki-properties/wallpaperParts.js new file mode 100644 index 00000000..23049397 --- /dev/null +++ b/src/data/composite/wiki-properties/wallpaperParts.js @@ -0,0 +1,9 @@ +import {isWallpaperPartList} from '#validators'; + +export default function() { + return { + flags: {update: true, expose: true}, + update: {validate: isWallpaperPartList}, + expose: {transform: value => value ?? []}, + }; +} |