diff options
Diffstat (limited to 'src/data/things/group/Group.js')
| -rw-r--r-- | src/data/things/group/Group.js | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/src/data/things/group/Group.js b/src/data/things/group/Group.js new file mode 100644 index 00000000..b065f9a3 --- /dev/null +++ b/src/data/things/group/Group.js @@ -0,0 +1,232 @@ +const GROUP_DATA_FILE = 'groups.yaml'; + +import {input, V} from '#composite'; +import Thing from '#thing'; +import {isBoolean} from '#validators'; +import {parseAnnotatedReferences, parseSerieses} from '#yaml'; + +import {withPropertyFromObject} from '#composite/data'; +import {withUniqueReferencingThing} from '#composite/wiki-data'; + +import { + exposeConstant, + exposeDependencyOrContinue, + exposeUpdateValueOrContinue, +} from '#composite/control-flow'; + +import { + annotatedReferenceList, + contentString, + directory, + flag, + name, + referenceList, + soupyFind, + soupyReverse, + thingList, + urls, +} from '#composite/wiki-properties'; + +export class Group extends Thing { + static [Thing.referenceType] = 'group'; + static [Thing.wikiData] = 'groupData'; + + static [Thing.getPropertyDescriptors] = ({Album, Artist, Series}) => ({ + // Update & expose + + name: name(V('Unnamed Group')), + directory: directory(), + + excludeFromGalleryTabs: [ + exposeUpdateValueOrContinue({ + validate: input.value(isBoolean), + }), + + withUniqueReferencingThing({ + reverse: soupyReverse.input('groupCategoriesWhichInclude'), + }).outputs({ + '#uniqueReferencingThing': '#category', + }), + + withPropertyFromObject('#category', V('excludeGroupsFromGalleryTabs')), + exposeDependencyOrContinue('#category.excludeGroupsFromGalleryTabs'), + + exposeConstant(V(false)), + ], + + divideAlbumsByStyle: flag(V(false)), + + description: contentString(), + + urls: urls(), + + closelyLinkedArtists: annotatedReferenceList({ + class: input.value(Artist), + find: soupyFind.input('artist'), + + reference: input.value('artist'), + thing: input.value('artist'), + }), + + featuredAlbums: referenceList({ + class: input.value(Album), + find: soupyFind.input('album'), + }), + + serieses: thingList(V(Series)), + + // Update only + + find: soupyFind(), + reverse: soupyReverse(), + + // Expose only + + isGroup: exposeConstant(V(true)), + + descriptionShort: { + flags: {expose: true}, + + expose: { + dependencies: ['description'], + compute: ({description}) => + (description + ? description.split('<hr class="split">')[0] + : null), + }, + }, + + albums: { + flags: {expose: true}, + + expose: { + dependencies: ['this', '_reverse'], + compute: ({this: group, _reverse: reverse}) => + reverse.albumsWhoseGroupsInclude(group), + }, + }, + + color: { + flags: {expose: true}, + + expose: { + dependencies: ['this', '_reverse'], + compute: ({this: group, _reverse: reverse}) => + reverse.groupCategoriesWhichInclude(group, {unique: true}) + ?.color, + }, + }, + + category: { + flags: {expose: true}, + + expose: { + dependencies: ['this', '_reverse'], + compute: ({this: group, _reverse: reverse}) => + reverse.groupCategoriesWhichInclude(group, {unique: true}) ?? + null, + }, + }, + }); + + static [Thing.findSpecs] = { + group: { + referenceTypes: ['group', 'group-gallery'], + bindTo: 'groupData', + }, + }; + + static [Thing.reverseSpecs] = { + groupsCloselyLinkedTo: { + bindTo: 'groupData', + + referencing: group => + group.closelyLinkedArtists + .map(({artist, ...referenceDetails}) => ({ + group, + artist, + referenceDetails, + })), + + referenced: ({artist}) => [artist], + + tidy: ({group, referenceDetails}) => + ({group, ...referenceDetails}), + }, + }; + + static [Thing.yamlDocumentSpec] = { + fields: { + 'Group': {property: 'name'}, + 'Directory': {property: 'directory'}, + + 'Exclude From Gallery Tabs': {property: 'excludeFromGalleryTabs'}, + 'Divide Albums By Style': {property: 'divideAlbumsByStyle'}, + + 'Description': {property: 'description'}, + 'URLs': {property: 'urls'}, + + 'Closely Linked Artists': { + property: 'closelyLinkedArtists', + transform: value => + parseAnnotatedReferences(value, { + referenceField: 'Artist', + referenceProperty: 'artist', + }), + }, + + 'Featured Albums': {property: 'featuredAlbums'}, + + 'Series': { + property: 'serieses', + transform: parseSerieses, + }, + + 'Review Points': {ignore: true}, + }, + }; + + static [Thing.getYamlLoadingSpec] = ({ + documentModes: {allInOne}, + thingConstructors: {Group, GroupCategory}, + }) => ({ + title: `Process groups file`, + file: GROUP_DATA_FILE, + + documentMode: allInOne, + documentThing: document => + ('Category' in document + ? GroupCategory + : Group), + + connect(results) { + let groupCategory; + let groupRefs = []; + + if (results[0] && !(results[0] instanceof GroupCategory)) { + throw new Error(`Expected a category at top of group data file`); + } + + for (const thing of results) { + if (thing instanceof GroupCategory) { + if (groupCategory) { + Object.assign(groupCategory, {groups: groupRefs}); + } + + groupCategory = thing; + groupRefs = []; + } else { + groupRefs.push(Thing.getReference(thing)); + } + } + + if (groupCategory) { + Object.assign(groupCategory, {groups: groupRefs}); + } + }, + + // Groups aren't sorted at all, always preserving the order in the data + // file as-is. + sort: null, + }); +} |