« get me outta code hell

hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/data/composite/things
diff options
context:
space:
mode:
Diffstat (limited to 'src/data/composite/things')
-rw-r--r--src/data/composite/things/album/index.js1
-rw-r--r--src/data/composite/things/album/withTracks.js29
-rw-r--r--src/data/composite/things/artist/artistTotalDuration.js69
-rw-r--r--src/data/composite/things/artist/index.js1
-rw-r--r--src/data/composite/things/artwork/index.js1
-rw-r--r--src/data/composite/things/artwork/withContainingArtworkList.js46
-rw-r--r--src/data/composite/things/content/hasAnnotationPart.js25
-rw-r--r--src/data/composite/things/content/index.js4
-rw-r--r--src/data/composite/things/content/withAnnotationPartNodeLists.js28
-rw-r--r--src/data/composite/things/content/withExpressedOrImplicitArtistReferences.js61
-rw-r--r--src/data/composite/things/content/withWebArchiveDate.js41
-rw-r--r--src/data/composite/things/contribution/index.js4
-rw-r--r--src/data/composite/things/contribution/inheritFromContributionPresets.js17
-rw-r--r--src/data/composite/things/contribution/thingPropertyMatches.js33
-rw-r--r--src/data/composite/things/contribution/thingReferenceTypeMatches.js39
-rw-r--r--src/data/composite/things/contribution/withContainingReverseContributionList.js54
-rw-r--r--src/data/composite/things/contribution/withContributionArtist.js26
-rw-r--r--src/data/composite/things/contribution/withMatchingContributionPresets.js70
-rw-r--r--src/data/composite/things/flash-act/index.js1
-rw-r--r--src/data/composite/things/flash-act/withFlashSide.js22
-rw-r--r--src/data/composite/things/flash/index.js1
-rw-r--r--src/data/composite/things/flash/withFlashAct.js22
-rw-r--r--src/data/composite/things/track-section/index.js1
-rw-r--r--src/data/composite/things/track-section/withAlbum.js20
-rw-r--r--src/data/composite/things/track/exitWithoutUniqueCoverArt.js26
-rw-r--r--src/data/composite/things/track/index.js17
-rw-r--r--src/data/composite/things/track/inheritContributionListFromMainRelease.js (renamed from src/data/composite/things/track/inheritContributionListFromOriginalRelease.js)35
-rw-r--r--src/data/composite/things/track/inheritFromMainRelease.js29
-rw-r--r--src/data/composite/things/track/inheritFromOriginalRelease.js41
-rw-r--r--src/data/composite/things/track/trackAdditionalNameList.js38
-rw-r--r--src/data/composite/things/track/withAlbum.js22
-rw-r--r--src/data/composite/things/track/withAlwaysReferenceByDirectory.js105
-rw-r--r--src/data/composite/things/track/withContainingTrackSection.js20
-rw-r--r--src/data/composite/things/track/withDate.js34
-rw-r--r--src/data/composite/things/track/withDirectorySuffix.js36
-rw-r--r--src/data/composite/things/track/withHasUniqueCoverArt.js64
-rw-r--r--src/data/composite/things/track/withOriginalRelease.js70
-rw-r--r--src/data/composite/things/track/withOtherReleases.js41
-rw-r--r--src/data/composite/things/track/withPropertyFromAlbum.js39
-rw-r--r--src/data/composite/things/track/withPropertyFromOriginalRelease.js86
-rw-r--r--src/data/composite/things/track/withSuffixDirectoryFromAlbum.js53
-rw-r--r--src/data/composite/things/track/withTrackArtDate.js80
42 files changed, 301 insertions, 1151 deletions
diff --git a/src/data/composite/things/album/index.js b/src/data/composite/things/album/index.js
deleted file mode 100644
index 8b5098f0..00000000
--- a/src/data/composite/things/album/index.js
+++ /dev/null
@@ -1 +0,0 @@
-export {default as withTracks} from './withTracks.js';
diff --git a/src/data/composite/things/album/withTracks.js b/src/data/composite/things/album/withTracks.js
deleted file mode 100644
index 835ee570..00000000
--- a/src/data/composite/things/album/withTracks.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import {input, templateCompositeFrom} from '#composite';
-
-import {withFlattenedList, withPropertyFromList} from '#composite/data';
-
-import {raiseOutputWithoutDependency} from '#composite/control-flow';
-
-export default templateCompositeFrom({
-  annotation: `withTracks`,
-
-  outputs: ['#tracks'],
-
-  steps: () => [
-    raiseOutputWithoutDependency({
-      dependency: 'trackSections',
-      output: input.value({'#tracks': []}),
-    }),
-
-    withPropertyFromList({
-      list: 'trackSections',
-      property: input.value('tracks'),
-    }),
-
-    withFlattenedList({
-      list: '#trackSections.tracks',
-    }).outputs({
-      ['#flattenedList']: '#tracks',
-    }),
-  ],
-});
diff --git a/src/data/composite/things/artist/artistTotalDuration.js b/src/data/composite/things/artist/artistTotalDuration.js
deleted file mode 100644
index a4a33542..00000000
--- a/src/data/composite/things/artist/artistTotalDuration.js
+++ /dev/null
@@ -1,69 +0,0 @@
-import {input, templateCompositeFrom} from '#composite';
-
-import {exposeDependency} from '#composite/control-flow';
-import {withFilteredList, withPropertyFromList} from '#composite/data';
-import {withContributionListSums, withReverseReferenceList}
-  from '#composite/wiki-data';
-import {soupyReverse} from '#composite/wiki-properties';
-
-export default templateCompositeFrom({
-  annotation: `artistTotalDuration`,
-
-  compose: false,
-
-  steps: () => [
-    withReverseReferenceList({
-      reverse: soupyReverse.input('trackArtistContributionsBy'),
-    }).outputs({
-      '#reverseReferenceList': '#contributionsAsArtist',
-    }),
-
-    withReverseReferenceList({
-      reverse: soupyReverse.input('trackContributorContributionsBy'),
-    }).outputs({
-      '#reverseReferenceList': '#contributionsAsContributor',
-    }),
-
-    {
-      dependencies: [
-        '#contributionsAsArtist',
-        '#contributionsAsContributor',
-      ],
-
-      compute: (continuation, {
-        ['#contributionsAsArtist']: artistContribs,
-        ['#contributionsAsContributor']: contributorContribs,
-      }) => continuation({
-        ['#allContributions']: [
-          ...artistContribs,
-          ...contributorContribs,
-        ],
-      }),
-    },
-
-    withPropertyFromList({
-      list: '#allContributions',
-      property: input.value('thing'),
-    }),
-
-    withPropertyFromList({
-      list: '#allContributions.thing',
-      property: input.value('isOriginalRelease'),
-    }),
-
-    withFilteredList({
-      list: '#allContributions',
-      filter: '#allContributions.thing.isOriginalRelease',
-    }).outputs({
-      '#filteredList': '#originalContributions',
-    }),
-
-    withContributionListSums({
-      list: '#originalContributions',
-    }),
-
-    exposeDependency({
-      dependency: '#contributionListDuration',
-    }),
-  ],
-});
diff --git a/src/data/composite/things/artist/index.js b/src/data/composite/things/artist/index.js
deleted file mode 100644
index 55514c71..00000000
--- a/src/data/composite/things/artist/index.js
+++ /dev/null
@@ -1 +0,0 @@
-export {default as artistTotalDuration} from './artistTotalDuration.js';
diff --git a/src/data/composite/things/artwork/index.js b/src/data/composite/things/artwork/index.js
new file mode 100644
index 00000000..2cd3c388
--- /dev/null
+++ b/src/data/composite/things/artwork/index.js
@@ -0,0 +1 @@
+export {default as withContainingArtworkList} from './withContainingArtworkList.js';
diff --git a/src/data/composite/things/artwork/withContainingArtworkList.js b/src/data/composite/things/artwork/withContainingArtworkList.js
new file mode 100644
index 00000000..9c928ffd
--- /dev/null
+++ b/src/data/composite/things/artwork/withContainingArtworkList.js
@@ -0,0 +1,46 @@
+// Gets the list of artworks which contains this one, which is functionally
+// equivalent to `this.thing[this.thingProperty]`. If the exposed value is not
+// a list at all (i.e. the property holds a single artwork), this composition
+// outputs null.
+
+import {input, templateCompositeFrom} from '#composite';
+
+import {raiseOutputWithoutDependency} from '#composite/control-flow';
+import {withPropertyFromObject} from '#composite/data';
+
+export default templateCompositeFrom({
+  annotation: `withContainingArtworkList`,
+
+  outputs: ['#containingArtworkList'],
+
+  steps: () => [
+    raiseOutputWithoutDependency({
+      dependency: 'thing',
+      output: input.value({'#containingArtworkList': null}),
+    }),
+
+    raiseOutputWithoutDependency({
+      dependency: 'thingProperty',
+      output: input.value({'#containingArtworkList': null}),
+    }),
+
+    withPropertyFromObject({
+      object: 'thing',
+      property: 'thingProperty',
+    }).outputs({
+      '#value': '#containingValue',
+    }),
+
+    {
+      dependencies: ['#containingValue'],
+      compute: (continuation, {
+        ['#containingValue']: containingValue,
+      }) => continuation({
+        ['#containingArtworkList']:
+          (Array.isArray(containingValue)
+            ? containingValue
+            : null),
+      }),
+    },
+  ],
+});
diff --git a/src/data/composite/things/content/hasAnnotationPart.js b/src/data/composite/things/content/hasAnnotationPart.js
new file mode 100644
index 00000000..93aaf5e5
--- /dev/null
+++ b/src/data/composite/things/content/hasAnnotationPart.js
@@ -0,0 +1,25 @@
+import {input, templateCompositeFrom} from '#composite';
+
+export default templateCompositeFrom({
+  annotation: `hasAnnotationPart`,
+
+  compose: false,
+
+  inputs: {
+    part: input({type: 'string'}),
+  },
+
+  steps: () => [
+    {
+      dependencies: [input('part'), 'annotationParts'],
+
+      compute: ({
+        [input('part')]: search,
+        ['annotationParts']: parts,
+      }) =>
+          parts.some(part =>
+            part.toLowerCase() ===
+            search.toLowerCase()),
+    },
+  ],
+});
diff --git a/src/data/composite/things/content/index.js b/src/data/composite/things/content/index.js
new file mode 100644
index 00000000..27bf7c53
--- /dev/null
+++ b/src/data/composite/things/content/index.js
@@ -0,0 +1,4 @@
+export {default as hasAnnotationPart} from './hasAnnotationPart.js';
+export {default as withAnnotationPartNodeLists} from './withAnnotationPartNodeLists.js';
+export {default as withExpressedOrImplicitArtistReferences} from './withExpressedOrImplicitArtistReferences.js';
+export {default as withWebArchiveDate} from './withWebArchiveDate.js';
diff --git a/src/data/composite/things/content/withAnnotationPartNodeLists.js b/src/data/composite/things/content/withAnnotationPartNodeLists.js
new file mode 100644
index 00000000..fc304594
--- /dev/null
+++ b/src/data/composite/things/content/withAnnotationPartNodeLists.js
@@ -0,0 +1,28 @@
+import {input, templateCompositeFrom} from '#composite';
+
+import {raiseOutputWithoutDependency} from '#composite/control-flow';
+import {splitContentNodesAround, withContentNodes} from '#composite/wiki-data';
+
+export default templateCompositeFrom({
+  annotation: `withAnnotationPartNodeLists`,
+
+  outputs: ['#annotationPartNodeLists'],
+
+  steps: () => [
+    raiseOutputWithoutDependency({
+      dependency: 'annotation',
+      output: input.value({'#annotationPartNodeLists': []}),
+    }),
+
+    withContentNodes({
+      from: 'annotation',
+    }),
+
+    splitContentNodesAround({
+      nodes: '#contentNodes',
+      around: input.value(/, */g),
+    }).outputs({
+      '#contentNodeLists': '#annotationPartNodeLists',
+    }),
+  ],
+});
diff --git a/src/data/composite/things/content/withExpressedOrImplicitArtistReferences.js b/src/data/composite/things/content/withExpressedOrImplicitArtistReferences.js
new file mode 100644
index 00000000..69da8c75
--- /dev/null
+++ b/src/data/composite/things/content/withExpressedOrImplicitArtistReferences.js
@@ -0,0 +1,61 @@
+import {input, templateCompositeFrom} from '#composite';
+
+import {raiseOutputWithoutDependency} from '#composite/control-flow';
+import {withFilteredList, withMappedList} from '#composite/data';
+import {withContentNodes} from '#composite/wiki-data';
+
+export default templateCompositeFrom({
+  annotation: `withExpressedOrImplicitArtistReferences`,
+
+  inputs: {
+    from: input({type: 'array', acceptsNull: true}),
+  },
+
+  outputs: ['#artistReferences'],
+
+  steps: () => [
+    {
+      dependencies: [input('from')],
+      compute: (continuation, {
+        [input('from')]: expressedArtistReferences,
+      }) =>
+        (expressedArtistReferences
+          ? continuation.raiseOutput({'#artistReferences': expressedArtistReferences})
+          : continuation()),
+    },
+
+    raiseOutputWithoutDependency({
+      dependency: 'artistText',
+      output: input.value({'#artistReferences': null}),
+    }),
+
+    withContentNodes({
+      from: 'artistText',
+    }),
+
+    withMappedList({
+      list: '#contentNodes',
+      map: input.value(node =>
+        node.type === 'tag' &&
+        node.data.replacerKey?.data === 'artist'),
+    }).outputs({
+      '#mappedList': '#artistTagFilter',
+    }),
+
+    withFilteredList({
+      list: '#contentNodes',
+      filter: '#artistTagFilter',
+    }).outputs({
+      '#filteredList': '#artistTags',
+    }),
+
+    withMappedList({
+      list: '#artistTags',
+      map: input.value(node =>
+        'artist:' +
+        node.data.replacerValue[0].data),
+    }).outputs({
+      '#mappedList': '#artistReferences',
+    }),
+  ],
+});
diff --git a/src/data/composite/things/content/withWebArchiveDate.js b/src/data/composite/things/content/withWebArchiveDate.js
new file mode 100644
index 00000000..3aaa4f64
--- /dev/null
+++ b/src/data/composite/things/content/withWebArchiveDate.js
@@ -0,0 +1,41 @@
+import {input, templateCompositeFrom} from '#composite';
+
+import {raiseOutputWithoutDependency} from '#composite/control-flow';
+
+export default templateCompositeFrom({
+  annotation: `withWebArchiveDate`,
+
+  outputs: ['#webArchiveDate'],
+
+  steps: () => [
+    {
+      dependencies: ['annotation'],
+
+      compute: (continuation, {annotation}) =>
+        continuation({
+          ['#dateText']:
+            annotation
+              ?.match(/https?:\/\/web.archive.org\/web\/([0-9]{8,8})[0-9]*\//)
+              ?.[1] ??
+            null,
+        }),
+    },
+
+    raiseOutputWithoutDependency({
+      dependency: '#dateText',
+      output: input.value({['#webArchiveDate']: null}),
+    }),
+
+    {
+      dependencies: ['#dateText'],
+      compute: (continuation, {['#dateText']: dateText}) =>
+        continuation({
+          ['#webArchiveDate']:
+            new Date(
+              dateText.slice(0, 4) + '/' +
+              dateText.slice(4, 6) + '/' +
+              dateText.slice(6, 8)),
+        }),
+    },
+  ],
+});
diff --git a/src/data/composite/things/contribution/index.js b/src/data/composite/things/contribution/index.js
index 9b22be2e..2bbf994d 100644
--- a/src/data/composite/things/contribution/index.js
+++ b/src/data/composite/things/contribution/index.js
@@ -1,7 +1,3 @@
 export {default as inheritFromContributionPresets} from './inheritFromContributionPresets.js';
-export {default as thingPropertyMatches} from './thingPropertyMatches.js';
-export {default as thingReferenceTypeMatches} from './thingReferenceTypeMatches.js';
 export {default as withContainingReverseContributionList} from './withContainingReverseContributionList.js';
-export {default as withContributionArtist} from './withContributionArtist.js';
 export {default as withContributionContext} from './withContributionContext.js';
-export {default as withMatchingContributionPresets} from './withMatchingContributionPresets.js';
diff --git a/src/data/composite/things/contribution/inheritFromContributionPresets.js b/src/data/composite/things/contribution/inheritFromContributionPresets.js
index a74e6db3..b429b3ef 100644
--- a/src/data/composite/things/contribution/inheritFromContributionPresets.js
+++ b/src/data/composite/things/contribution/inheritFromContributionPresets.js
@@ -3,29 +3,18 @@ import {input, templateCompositeFrom} from '#composite';
 import {raiseOutputWithoutDependency} from '#composite/control-flow';
 import {withPropertyFromList} from '#composite/data';
 
-import withMatchingContributionPresets
-  from './withMatchingContributionPresets.js';
-
 export default templateCompositeFrom({
   annotation: `inheritFromContributionPresets`,
 
-  inputs: {
-    property: input({type: 'string'}),
-  },
-
   steps: () => [
-    withMatchingContributionPresets().outputs({
-      '#matchingContributionPresets': '#presets',
-    }),
-
     raiseOutputWithoutDependency({
-      dependency: '#presets',
+      dependency: 'matchingContributionPresets',
       mode: input.value('empty'),
     }),
 
     withPropertyFromList({
-      list: '#presets',
-      property: input('property'),
+      list: 'matchingContributionPresets',
+      property: input.thisProperty(),
     }),
 
     {
diff --git a/src/data/composite/things/contribution/thingPropertyMatches.js b/src/data/composite/things/contribution/thingPropertyMatches.js
deleted file mode 100644
index 4a37f2cf..00000000
--- a/src/data/composite/things/contribution/thingPropertyMatches.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import {input, templateCompositeFrom} from '#composite';
-
-import {exitWithoutDependency} from '#composite/control-flow';
-
-export default templateCompositeFrom({
-  annotation: `thingPropertyMatches`,
-
-  compose: false,
-
-  inputs: {
-    value: input({type: 'string'}),
-  },
-
-  steps: () => [
-    exitWithoutDependency({
-      dependency: 'thingProperty',
-      value: input.value(false),
-    }),
-
-    {
-      dependencies: [
-        'thingProperty',
-        input('value'),
-      ],
-
-      compute: ({
-        ['thingProperty']: thingProperty,
-        [input('value')]: value,
-      }) =>
-        thingProperty === value,
-    },
-  ],
-});
diff --git a/src/data/composite/things/contribution/thingReferenceTypeMatches.js b/src/data/composite/things/contribution/thingReferenceTypeMatches.js
deleted file mode 100644
index 2ee811af..00000000
--- a/src/data/composite/things/contribution/thingReferenceTypeMatches.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import {input, templateCompositeFrom} from '#composite';
-
-import {exitWithoutDependency} from '#composite/control-flow';
-import {withPropertyFromObject} from '#composite/data';
-
-export default templateCompositeFrom({
-  annotation: `thingReferenceTypeMatches`,
-
-  compose: false,
-
-  inputs: {
-    value: input({type: 'string'}),
-  },
-
-  steps: () => [
-    exitWithoutDependency({
-      dependency: 'thing',
-      value: input.value(false),
-    }),
-
-    withPropertyFromObject({
-      object: 'thing',
-      property: input.value('constructor'),
-    }),
-
-    {
-      dependencies: [
-        '#thing.constructor',
-        input('value'),
-      ],
-
-      compute: ({
-        ['#thing.constructor']: constructor,
-        [input('value')]: value,
-      }) =>
-        constructor[Symbol.for('Thing.referenceType')] === value,
-    },
-  ],
-});
diff --git a/src/data/composite/things/contribution/withContainingReverseContributionList.js b/src/data/composite/things/contribution/withContainingReverseContributionList.js
index 56704c8b..a9ba31c9 100644
--- a/src/data/composite/things/contribution/withContainingReverseContributionList.js
+++ b/src/data/composite/things/contribution/withContainingReverseContributionList.js
@@ -1,18 +1,20 @@
-// Get the artist's contribution list containing this property.
+// Get the artist's contribution list containing this property. Although that
+// list literally includes both dated and dateless contributions, here, if the
+// current contribution is dateless, the list is filtered to only include
+// dateless contributions from the same immediately nearby context.
 
 import {input, templateCompositeFrom} from '#composite';
 
-import {raiseOutputWithoutDependency} from '#composite/control-flow';
+import {raiseOutputWithoutDependency, withResultOfAvailabilityCheck}
+  from '#composite/control-flow';
 import {withPropertyFromObject} from '#composite/data';
 
-import withContributionArtist from './withContributionArtist.js';
-
 export default templateCompositeFrom({
   annotation: `withContainingReverseContributionList`,
 
   inputs: {
     artistProperty: input({
-      defaultDependency: 'artistProperty',
+      defaultDependency: '_artistProperty',
       acceptsNull: true,
     }),
   },
@@ -28,13 +30,47 @@ export default templateCompositeFrom({
       }),
     }),
 
-    withContributionArtist(),
-
     withPropertyFromObject({
-      object: '#artist',
+      object: 'artist',
       property: input('artistProperty'),
     }).outputs({
-      ['#value']: '#containingReverseContributionList',
+      ['#value']: '#list',
+    }),
+
+    withResultOfAvailabilityCheck({
+      from: 'date',
+    }).outputs({
+      ['#availability']: '#hasDate',
     }),
+
+    {
+      dependencies: ['#hasDate', '#list'],
+      compute: (continuation, {
+        ['#hasDate']: hasDate,
+        ['#list']: list,
+      }) =>
+        (hasDate
+          ? continuation.raiseOutput({
+              ['#containingReverseContributionList']:
+                list.filter(contrib => contrib.date),
+            })
+          : continuation({
+              ['#list']:
+                list.filter(contrib => !contrib.date),
+            })),
+    },
+
+    {
+      dependencies: ['#list', 'thing'],
+      compute: (continuation, {
+        ['#list']: list,
+        ['thing']: thing,
+      }) => continuation({
+        ['#containingReverseContributionList']:
+          (thing.album
+            ? list.filter(contrib => contrib.thing.album === thing.album)
+            : list),
+      }),
+    },
   ],
 });
diff --git a/src/data/composite/things/contribution/withContributionArtist.js b/src/data/composite/things/contribution/withContributionArtist.js
deleted file mode 100644
index 5f81c716..00000000
--- a/src/data/composite/things/contribution/withContributionArtist.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import {input, templateCompositeFrom} from '#composite';
-
-import {withResolvedReference} from '#composite/wiki-data';
-import {soupyFind} from '#composite/wiki-properties';
-
-export default templateCompositeFrom({
-  annotation: `withContributionArtist`,
-
-  inputs: {
-    ref: input({
-      type: 'string',
-      defaultDependency: 'artist',
-    }),
-  },
-
-  outputs: ['#artist'],
-
-  steps: () => [
-    withResolvedReference({
-      ref: input('ref'),
-      find: soupyFind.input('artist'),
-    }).outputs({
-      '#resolvedReference': '#artist',
-    }),
-  ],
-});
diff --git a/src/data/composite/things/contribution/withMatchingContributionPresets.js b/src/data/composite/things/contribution/withMatchingContributionPresets.js
deleted file mode 100644
index 09454164..00000000
--- a/src/data/composite/things/contribution/withMatchingContributionPresets.js
+++ /dev/null
@@ -1,70 +0,0 @@
-import {input, templateCompositeFrom} from '#composite';
-
-import {raiseOutputWithoutDependency} from '#composite/control-flow';
-import {withPropertyFromObject} from '#composite/data';
-
-import withContributionContext from './withContributionContext.js';
-
-export default templateCompositeFrom({
-  annotation: `withMatchingContributionPresets`,
-
-  outputs: ['#matchingContributionPresets'],
-
-  steps: () => [
-    withPropertyFromObject({
-      object: 'thing',
-      property: input.value('wikiInfo'),
-      internal: input.value(true),
-    }),
-
-    raiseOutputWithoutDependency({
-      dependency: '#thing.wikiInfo',
-      output: input.value({
-        '#matchingContributionPresets': null,
-      }),
-    }),
-
-    withPropertyFromObject({
-      object: '#thing.wikiInfo',
-      property: input.value('contributionPresets'),
-    }).outputs({
-      '#thing.wikiInfo.contributionPresets': '#contributionPresets',
-    }),
-
-    raiseOutputWithoutDependency({
-      dependency: '#contributionPresets',
-      mode: input.value('empty'),
-      output: input.value({
-        '#matchingContributionPresets': [],
-      }),
-    }),
-
-    withContributionContext(),
-
-    {
-      dependencies: [
-        '#contributionPresets',
-        '#contributionTarget',
-        '#contributionProperty',
-        'annotation',
-      ],
-
-      compute: (continuation, {
-        ['#contributionPresets']: presets,
-        ['#contributionTarget']: target,
-        ['#contributionProperty']: property,
-        ['annotation']: annotation,
-      }) => continuation({
-        ['#matchingContributionPresets']:
-          presets
-            .filter(preset =>
-              preset.context[0] === target &&
-              preset.context.slice(1).includes(property) &&
-              // For now, only match if the annotation is a complete match.
-              // Partial matches (e.g. because the contribution includes "two"
-              // annotations, separated by commas) don't count.
-              preset.annotation === annotation),
-      })
-    },
-  ],
-});
diff --git a/src/data/composite/things/flash-act/index.js b/src/data/composite/things/flash-act/index.js
deleted file mode 100644
index 40fecd2f..00000000
--- a/src/data/composite/things/flash-act/index.js
+++ /dev/null
@@ -1 +0,0 @@
-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
deleted file mode 100644
index e09f06e6..00000000
--- a/src/data/composite/things/flash-act/withFlashSide.js
+++ /dev/null
@@ -1,22 +0,0 @@
-// 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 {templateCompositeFrom} from '#composite';
-
-import {withUniqueReferencingThing} from '#composite/wiki-data';
-import {soupyReverse} from '#composite/wiki-properties';
-
-export default templateCompositeFrom({
-  annotation: `withFlashSide`,
-
-  outputs: ['#flashSide'],
-
-  steps: () => [
-    withUniqueReferencingThing({
-      reverse: soupyReverse.input('flashSidesWhoseActsInclude'),
-    }).outputs({
-      ['#uniqueReferencingThing']: '#flashSide',
-    }),
-  ],
-});
diff --git a/src/data/composite/things/flash/index.js b/src/data/composite/things/flash/index.js
deleted file mode 100644
index 63ac13da..00000000
--- a/src/data/composite/things/flash/index.js
+++ /dev/null
@@ -1 +0,0 @@
-export {default as withFlashAct} from './withFlashAct.js';
diff --git a/src/data/composite/things/flash/withFlashAct.js b/src/data/composite/things/flash/withFlashAct.js
deleted file mode 100644
index 87922aff..00000000
--- a/src/data/composite/things/flash/withFlashAct.js
+++ /dev/null
@@ -1,22 +0,0 @@
-// Gets the flash's act. This will early exit if flashActData is missing.
-// If there's no flash whose list of flashes includes this flash, the output
-// dependency will be null.
-
-import {templateCompositeFrom} from '#composite';
-
-import {withUniqueReferencingThing} from '#composite/wiki-data';
-import {soupyReverse} from '#composite/wiki-properties';
-
-export default templateCompositeFrom({
-  annotation: `withFlashAct`,
-
-  outputs: ['#flashAct'],
-
-  steps: () => [
-    withUniqueReferencingThing({
-      reverse: soupyReverse.input('flashActsWhoseFlashesInclude'),
-    }).outputs({
-      ['#uniqueReferencingThing']: '#flashAct',
-    }),
-  ],
-});
diff --git a/src/data/composite/things/track-section/index.js b/src/data/composite/things/track-section/index.js
deleted file mode 100644
index 3202ed49..00000000
--- a/src/data/composite/things/track-section/index.js
+++ /dev/null
@@ -1 +0,0 @@
-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
deleted file mode 100644
index e257062e..00000000
--- a/src/data/composite/things/track-section/withAlbum.js
+++ /dev/null
@@ -1,20 +0,0 @@
-// Gets the track section's album.
-
-import {templateCompositeFrom} from '#composite';
-
-import {withUniqueReferencingThing} from '#composite/wiki-data';
-import {soupyReverse} from '#composite/wiki-properties';
-
-export default templateCompositeFrom({
-  annotation: `withAlbum`,
-
-  outputs: ['#album'],
-
-  steps: () => [
-    withUniqueReferencingThing({
-      reverse: soupyReverse.input('albumsWhoseTrackSectionsInclude'),
-    }).outputs({
-      ['#uniqueReferencingThing']: '#album',
-    }),
-  ],
-});
diff --git a/src/data/composite/things/track/exitWithoutUniqueCoverArt.js b/src/data/composite/things/track/exitWithoutUniqueCoverArt.js
deleted file mode 100644
index f47086d9..00000000
--- a/src/data/composite/things/track/exitWithoutUniqueCoverArt.js
+++ /dev/null
@@ -1,26 +0,0 @@
-// Shorthand for checking if the track has unique cover art and exposing a
-// fallback value if it isn't.
-
-import {input, templateCompositeFrom} from '#composite';
-
-import {exitWithoutDependency} from '#composite/control-flow';
-
-import withHasUniqueCoverArt from './withHasUniqueCoverArt.js';
-
-export default templateCompositeFrom({
-  annotation: `exitWithoutUniqueCoverArt`,
-
-  inputs: {
-    value: input({defaultValue: null}),
-  },
-
-  steps: () => [
-    withHasUniqueCoverArt(),
-
-    exitWithoutDependency({
-      dependency: '#hasUniqueCoverArt',
-      mode: input.value('falsy'),
-      value: input('value'),
-    }),
-  ],
-});
diff --git a/src/data/composite/things/track/index.js b/src/data/composite/things/track/index.js
index 32c72f78..c200df19 100644
--- a/src/data/composite/things/track/index.js
+++ b/src/data/composite/things/track/index.js
@@ -1,15 +1,2 @@
-export {default as exitWithoutUniqueCoverArt} from './exitWithoutUniqueCoverArt.js';
-export {default as inheritContributionListFromOriginalRelease} from './inheritContributionListFromOriginalRelease.js';
-export {default as inheritFromOriginalRelease} from './inheritFromOriginalRelease.js';
-export {default as withAlbum} from './withAlbum.js';
-export {default as withAlwaysReferenceByDirectory} from './withAlwaysReferenceByDirectory.js';
-export {default as withContainingTrackSection} from './withContainingTrackSection.js';
-export {default as withDate} from './withDate.js';
-export {default as withDirectorySuffix} from './withDirectorySuffix.js';
-export {default as withHasUniqueCoverArt} from './withHasUniqueCoverArt.js';
-export {default as withOriginalRelease} from './withOriginalRelease.js';
-export {default as withOtherReleases} from './withOtherReleases.js';
-export {default as withPropertyFromAlbum} from './withPropertyFromAlbum.js';
-export {default as withPropertyFromOriginalRelease} from './withPropertyFromOriginalRelease.js';
-export {default as withSuffixDirectoryFromAlbum} from './withSuffixDirectoryFromAlbum.js';
-export {default as withTrackArtDate} from './withTrackArtDate.js';
+export {default as inheritContributionListFromMainRelease} from './inheritContributionListFromMainRelease.js';
+export {default as inheritFromMainRelease} from './inheritFromMainRelease.js';
diff --git a/src/data/composite/things/track/inheritContributionListFromOriginalRelease.js b/src/data/composite/things/track/inheritContributionListFromMainRelease.js
index f4ae3ddb..8db50060 100644
--- a/src/data/composite/things/track/inheritContributionListFromOriginalRelease.js
+++ b/src/data/composite/things/track/inheritContributionListFromMainRelease.js
@@ -1,44 +1,41 @@
-// Like inheritFromOriginalRelease, but tuned for contributions.
-// Recontextualized contributions for this track.
+// Like inheritFromMainRelease, but tuned for contributions.
+// Recontextualizes contributions for this track.
 
 import {input, templateCompositeFrom} from '#composite';
 
 import {exposeDependency, raiseOutputWithoutDependency}
   from '#composite/control-flow';
+import {withPropertyFromObject} from '#composite/data';
 import {withRecontextualizedContributionList, withRedatedContributionList}
   from '#composite/wiki-data';
 
-import withDate from './withDate.js';
-import withPropertyFromOriginalRelease
-  from './withPropertyFromOriginalRelease.js';
-
 export default templateCompositeFrom({
-  annotation: `inheritContributionListFromOriginalRelease`,
+  annotation: `inheritContributionListFromMainRelease`,
 
   steps: () => [
-    withPropertyFromOriginalRelease({
-      property: input.thisProperty(),
-      notFoundValue: input.value([]),
-    }),
-
     raiseOutputWithoutDependency({
-      dependency: '#isRerelease',
+      dependency: 'isSecondaryRelease',
       mode: input.value('falsy'),
     }),
 
-    withRecontextualizedContributionList({
-      list: '#originalValue',
+    withPropertyFromObject({
+      object: 'mainReleaseTrack',
+      property: input.thisProperty(),
+    }).outputs({
+      '#value': '#contributions',
     }),
 
-    withDate(),
+    withRecontextualizedContributionList({
+      list: '#contributions',
+    }),
 
     withRedatedContributionList({
-      list: '#originalValue',
-      date: '#date',
+      list: '#contributions',
+      date: 'date',
     }),
 
     exposeDependency({
-      dependency: '#originalValue',
+      dependency: '#contributions',
     }),
   ],
 });
diff --git a/src/data/composite/things/track/inheritFromMainRelease.js b/src/data/composite/things/track/inheritFromMainRelease.js
new file mode 100644
index 00000000..ca532bc7
--- /dev/null
+++ b/src/data/composite/things/track/inheritFromMainRelease.js
@@ -0,0 +1,29 @@
+// Early exits with the value for the same property as specified on the
+// main release, if this track is a secondary release, and otherwise continues
+// without providing any further dependencies.
+
+import {input, templateCompositeFrom} from '#composite';
+
+import {exposeDependency, raiseOutputWithoutDependency}
+  from '#composite/control-flow';
+import {withPropertyFromObject} from '#composite/data';
+
+export default templateCompositeFrom({
+  annotation: `inheritFromMainRelease`,
+
+  steps: () => [
+    raiseOutputWithoutDependency({
+      dependency: 'isSecondaryRelease',
+      mode: input.value('falsy'),
+    }),
+
+    withPropertyFromObject({
+      object: 'mainReleaseTrack',
+      property: input.thisProperty(),
+    }),
+
+    exposeDependency({
+      dependency: '#value',
+    }),
+  ],
+});
diff --git a/src/data/composite/things/track/inheritFromOriginalRelease.js b/src/data/composite/things/track/inheritFromOriginalRelease.js
deleted file mode 100644
index 38ab06be..00000000
--- a/src/data/composite/things/track/inheritFromOriginalRelease.js
+++ /dev/null
@@ -1,41 +0,0 @@
-// 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
-// resolve to anything.
-
-import {input, templateCompositeFrom} from '#composite';
-
-import {exposeDependency, raiseOutputWithoutDependency}
-  from '#composite/control-flow';
-
-import withPropertyFromOriginalRelease
-  from './withPropertyFromOriginalRelease.js';
-
-export default templateCompositeFrom({
-  annotation: `inheritFromOriginalRelease`,
-
-  inputs: {
-    notFoundValue: input({
-      defaultValue: null,
-    }),
-  },
-
-  steps: () => [
-    withPropertyFromOriginalRelease({
-      property: input.thisProperty(),
-      notFoundValue: input('notFoundValue'),
-    }),
-
-    raiseOutputWithoutDependency({
-      dependency: '#isRerelease',
-      mode: input.value('falsy'),
-    }),
-
-    exposeDependency({
-      dependency: '#originalValue',
-    }),
-  ],
-});
diff --git a/src/data/composite/things/track/trackAdditionalNameList.js b/src/data/composite/things/track/trackAdditionalNameList.js
deleted file mode 100644
index 65a2263d..00000000
--- a/src/data/composite/things/track/trackAdditionalNameList.js
+++ /dev/null
@@ -1,38 +0,0 @@
-// Compiles additional names from various sources.
-
-import {input, templateCompositeFrom} from '#composite';
-import {isAdditionalNameList} from '#validators';
-
-import withInferredAdditionalNames from './withInferredAdditionalNames.js';
-import withSharedAdditionalNames from './withSharedAdditionalNames.js';
-
-export default templateCompositeFrom({
-  annotation: `trackAdditionalNameList`,
-
-  compose: false,
-
-  update: {validate: isAdditionalNameList},
-
-  steps: () => [
-    withInferredAdditionalNames(),
-    withSharedAdditionalNames(),
-
-    {
-      dependencies: [
-        '#inferredAdditionalNames',
-        '#sharedAdditionalNames',
-        input.updateValue(),
-      ],
-
-      compute: ({
-        ['#inferredAdditionalNames']: inferredAdditionalNames,
-        ['#sharedAdditionalNames']: sharedAdditionalNames,
-        [input.updateValue()]: providedAdditionalNames,
-      }) => [
-        ...providedAdditionalNames ?? [],
-        ...sharedAdditionalNames,
-        ...inferredAdditionalNames,
-      ],
-    },
-  ],
-});
diff --git a/src/data/composite/things/track/withAlbum.js b/src/data/composite/things/track/withAlbum.js
deleted file mode 100644
index 4c55e1f4..00000000
--- a/src/data/composite/things/track/withAlbum.js
+++ /dev/null
@@ -1,22 +0,0 @@
-// Gets the track's album. This will early exit if albumData is missing.
-// If there's no album whose list of tracks includes this track, the output
-// dependency will be null.
-
-import {templateCompositeFrom} from '#composite';
-
-import {withUniqueReferencingThing} from '#composite/wiki-data';
-import {soupyReverse} from '#composite/wiki-properties';
-
-export default templateCompositeFrom({
-  annotation: `withAlbum`,
-
-  outputs: ['#album'],
-
-  steps: () => [
-    withUniqueReferencingThing({
-      reverse: soupyReverse.input('albumsWhoseTracksInclude'),
-    }).outputs({
-      ['#uniqueReferencingThing']: '#album',
-    }),
-  ],
-});
diff --git a/src/data/composite/things/track/withAlwaysReferenceByDirectory.js b/src/data/composite/things/track/withAlwaysReferenceByDirectory.js
deleted file mode 100644
index 26c5ba97..00000000
--- a/src/data/composite/things/track/withAlwaysReferenceByDirectory.js
+++ /dev/null
@@ -1,105 +0,0 @@
-// Controls how find.track works - it'll never be matched by a reference
-// just to the track's name, which means you don't have to always reference
-// some *other* (much more commonly referenced) track by directory instead
-// of more naturally by name.
-
-import {input, templateCompositeFrom} from '#composite';
-import find from '#find';
-import {isBoolean} from '#validators';
-
-import {withPropertyFromObject} from '#composite/data';
-import {withResolvedReference} from '#composite/wiki-data';
-import {soupyFind} from '#composite/wiki-properties';
-
-import {
-  exitWithoutDependency,
-  exposeDependencyOrContinue,
-  exposeUpdateValueOrContinue,
-} from '#composite/control-flow';
-
-export default templateCompositeFrom({
-  annotation: `withAlwaysReferenceByDirectory`,
-
-  outputs: ['#alwaysReferenceByDirectory'],
-
-  steps: () => [
-    exposeUpdateValueOrContinue({
-      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',
-      find: soupyFind.input('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.
-
-    exitWithoutDependency({
-      dependency: 'trackData',
-      mode: input.value('empty'),
-      value: input.value(false),
-    }),
-
-    exitWithoutDependency({
-      dependency: 'originalReleaseTrack',
-      value: input.value(false),
-    }),
-
-    // It's necessary to use the custom trackOriginalReleasesOnly find function
-    // here, so as to avoid recursion issues - the find.track() function depends
-    // on accessing each track's alwaysReferenceByDirectory, which means it'll
-    // hit *this track* - and thus this step - and end up recursing infinitely.
-    // By definition, find.trackOriginalReleasesOnly excludes tracks which have
-    // an originalReleaseTrack update value set, which means even though it does
-    // still access each of tracks' `alwaysReferenceByDirectory` property, it
-    // won't access that of *this* track - it will never proceed past the
-    // `exitWithoutDependency` step directly above, so there's no opportunity
-    // for recursion.
-    withResolvedReference({
-      ref: 'originalReleaseTrack',
-      data: 'trackData',
-      find: input.value(find.trackOriginalReleasesOnly),
-    }).outputs({
-      '#resolvedReference': '#originalRelease',
-    }),
-
-    exitWithoutDependency({
-      dependency: '#originalRelease',
-      value: input.value(false),
-    }),
-
-    withPropertyFromObject({
-      object: '#originalRelease',
-      property: input.value('name'),
-    }),
-
-    {
-      dependencies: ['name', '#originalRelease.name'],
-      compute: (continuation, {
-        name,
-        ['#originalRelease.name']: originalName,
-      }) => continuation({
-        ['#alwaysReferenceByDirectory']: name === originalName,
-      }),
-    },
-  ],
-});
diff --git a/src/data/composite/things/track/withContainingTrackSection.js b/src/data/composite/things/track/withContainingTrackSection.js
deleted file mode 100644
index 3d4d081e..00000000
--- a/src/data/composite/things/track/withContainingTrackSection.js
+++ /dev/null
@@ -1,20 +0,0 @@
-// Gets the track section containing this track from its album's track list.
-
-import {templateCompositeFrom} from '#composite';
-
-import {withUniqueReferencingThing} from '#composite/wiki-data';
-import {soupyReverse} from '#composite/wiki-properties';
-
-export default templateCompositeFrom({
-  annotation: `withContainingTrackSection`,
-
-  outputs: ['#trackSection'],
-
-  steps: () => [
-    withUniqueReferencingThing({
-      reverse: soupyReverse.input('trackSectionsWhichInclude'),
-    }).outputs({
-      ['#uniqueReferencingThing']: '#trackSection',
-    }),
-  ],
-});
diff --git a/src/data/composite/things/track/withDate.js b/src/data/composite/things/track/withDate.js
deleted file mode 100644
index b5a770e9..00000000
--- a/src/data/composite/things/track/withDate.js
+++ /dev/null
@@ -1,34 +0,0 @@
-// Gets the track's own date. This is either its dateFirstReleased property
-// or, if unset, the album's date.
-
-import {input, templateCompositeFrom} from '#composite';
-
-import withPropertyFromAlbum from './withPropertyFromAlbum.js';
-
-export default templateCompositeFrom({
-  annotation: `withDate`,
-
-  outputs: ['#date'],
-
-  steps: () => [
-    {
-      dependencies: ['dateFirstReleased'],
-      compute: (continuation, {dateFirstReleased}) =>
-        (dateFirstReleased
-          ? continuation.raiseOutput({'#date': dateFirstReleased})
-          : continuation()),
-    },
-
-    withPropertyFromAlbum({
-      property: input.value('date'),
-    }),
-
-    {
-      dependencies: ['#album.date'],
-      compute: (continuation, {['#album.date']: albumDate}) =>
-        (albumDate
-          ? continuation.raiseOutput({'#date': albumDate})
-          : continuation.raiseOutput({'#date': null})),
-    },
-  ],
-})
diff --git a/src/data/composite/things/track/withDirectorySuffix.js b/src/data/composite/things/track/withDirectorySuffix.js
deleted file mode 100644
index c063e158..00000000
--- a/src/data/composite/things/track/withDirectorySuffix.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import {input, templateCompositeFrom} from '#composite';
-
-import {raiseOutputWithoutDependency} from '#composite/control-flow';
-
-import withPropertyFromAlbum from './withPropertyFromAlbum.js';
-import withSuffixDirectoryFromAlbum from './withSuffixDirectoryFromAlbum.js';
-
-export default templateCompositeFrom({
-  annotation: `withDirectorySuffix`,
-
-  outputs: ['#directorySuffix'],
-
-  steps: () => [
-    withSuffixDirectoryFromAlbum(),
-
-    raiseOutputWithoutDependency({
-      dependency: '#suffixDirectoryFromAlbum',
-      mode: input.value('falsy'),
-      output: input.value({['#directorySuffix']: null}),
-    }),
-
-    withPropertyFromAlbum({
-      property: input.value('directorySuffix'),
-    }),
-
-    {
-      dependencies: ['#album.directorySuffix'],
-      compute: (continuation, {
-        ['#album.directorySuffix']: directorySuffix,
-      }) => continuation({
-        ['#directorySuffix']:
-          directorySuffix,
-      }),
-    },
-  ],
-});
diff --git a/src/data/composite/things/track/withHasUniqueCoverArt.js b/src/data/composite/things/track/withHasUniqueCoverArt.js
deleted file mode 100644
index f7e65f25..00000000
--- a/src/data/composite/things/track/withHasUniqueCoverArt.js
+++ /dev/null
@@ -1,64 +0,0 @@
-// Whether or not the track has "unique" cover artwork - a cover which is
-// specifically associated with this track in particular, rather than with
-// the track's album as a whole. This is typically used to select between
-// displaying the track artwork and a fallback, such as the album artwork
-// or a placeholder. (This property is named hasUniqueCoverArt instead of
-// the usual hasCoverArt to emphasize that it does not inherit from the
-// album.)
-
-import {input, templateCompositeFrom} from '#composite';
-import {empty} from '#sugar';
-
-import {withResolvedContribs} from '#composite/wiki-data';
-
-import withPropertyFromAlbum from './withPropertyFromAlbum.js';
-
-export default templateCompositeFrom({
-  annotation: 'withHasUniqueCoverArt',
-
-  outputs: ['#hasUniqueCoverArt'],
-
-  steps: () => [
-    {
-      dependencies: ['disableUniqueCoverArt'],
-      compute: (continuation, {disableUniqueCoverArt}) =>
-        (disableUniqueCoverArt
-          ? continuation.raiseOutput({
-              ['#hasUniqueCoverArt']: false,
-            })
-          : continuation()),
-    },
-
-    withResolvedContribs({
-      from: 'coverArtistContribs',
-      date: input.value(null),
-    }),
-
-    {
-      dependencies: ['#resolvedContribs'],
-      compute: (continuation, {
-        ['#resolvedContribs']: contribsFromTrack,
-      }) =>
-        (empty(contribsFromTrack)
-          ? continuation()
-          : continuation.raiseOutput({
-              ['#hasUniqueCoverArt']: true,
-            })),
-    },
-
-    withPropertyFromAlbum({
-      property: input.value('trackCoverArtistContribs'),
-    }),
-
-    {
-      dependencies: ['#album.trackCoverArtistContribs'],
-      compute: (continuation, {
-        ['#album.trackCoverArtistContribs']: contribsFromAlbum,
-      }) =>
-        continuation.raiseOutput({
-          ['#hasUniqueCoverArt']:
-            !empty(contribsFromAlbum),
-        }),
-    },
-  ],
-});
diff --git a/src/data/composite/things/track/withOriginalRelease.js b/src/data/composite/things/track/withOriginalRelease.js
deleted file mode 100644
index 7aefc64a..00000000
--- a/src/data/composite/things/track/withOriginalRelease.js
+++ /dev/null
@@ -1,70 +0,0 @@
-// Just includes the original release of this track as a dependency.
-// If this track isn't a rerelease, then it'll provide null, unless the
-// {selfIfOriginal} option is set, in which case it'll provide this track
-// itself. 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 {exitWithoutDependency, withResultOfAvailabilityCheck}
-  from '#composite/control-flow';
-import {withResolvedReference} from '#composite/wiki-data';
-import {soupyFind} from '#composite/wiki-properties';
-
-export default templateCompositeFrom({
-  annotation: `withOriginalRelease`,
-
-  inputs: {
-    selfIfOriginal: input({type: 'boolean', defaultValue: false}),
-    notFoundValue: input({defaultValue: null}),
-  },
-
-  outputs: ['#originalRelease'],
-
-  steps: () => [
-    withResultOfAvailabilityCheck({
-      from: 'originalReleaseTrack',
-    }),
-
-    {
-      dependencies: [
-        input.myself(),
-        input('selfIfOriginal'),
-        '#availability',
-      ],
-
-      compute: (continuation, {
-        [input.myself()]: track,
-        [input('selfIfOriginal')]: selfIfOriginal,
-        '#availability': availability,
-      }) =>
-        (availability
-          ? continuation()
-          : continuation.raiseOutput({
-              ['#originalRelease']:
-                (selfIfOriginal ? track : null),
-            })),
-    },
-
-    withResolvedReference({
-      ref: 'originalReleaseTrack',
-      find: soupyFind.input('track'),
-    }),
-
-    exitWithoutDependency({
-      dependency: '#resolvedReference',
-      value: input('notFoundValue'),
-    }),
-
-    {
-      dependencies: ['#resolvedReference'],
-
-      compute: (continuation, {
-        ['#resolvedReference']: resolvedReference,
-      }) =>
-        continuation({
-          ['#originalRelease']: resolvedReference,
-        }),
-    },
-  ],
-});
diff --git a/src/data/composite/things/track/withOtherReleases.js b/src/data/composite/things/track/withOtherReleases.js
deleted file mode 100644
index f8c1c3f0..00000000
--- a/src/data/composite/things/track/withOtherReleases.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import {input, templateCompositeFrom} from '#composite';
-
-import {exitWithoutDependency} from '#composite/control-flow';
-
-import withOriginalRelease from './withOriginalRelease.js';
-
-export default templateCompositeFrom({
-  annotation: `withOtherReleases`,
-
-  outputs: ['#otherReleases'],
-
-  steps: () => [
-    exitWithoutDependency({
-      dependency: 'trackData',
-      mode: input.value('empty'),
-    }),
-
-    withOriginalRelease({
-      selfIfOriginal: input.value(true),
-      notFoundValue: input.value([]),
-    }),
-
-    {
-      dependencies: [input.myself(), '#originalRelease', 'trackData'],
-      compute: (continuation, {
-        [input.myself()]: thisTrack,
-        ['#originalRelease']: originalRelease,
-        trackData,
-      }) => continuation({
-        ['#otherReleases']:
-          (originalRelease === thisTrack
-            ? []
-            : [originalRelease])
-            .concat(trackData.filter(track =>
-              track !== originalRelease &&
-              track !== thisTrack &&
-              track.originalReleaseTrack === originalRelease)),
-      }),
-    },
-  ],
-});
diff --git a/src/data/composite/things/track/withPropertyFromAlbum.js b/src/data/composite/things/track/withPropertyFromAlbum.js
deleted file mode 100644
index e9c5b56e..00000000
--- a/src/data/composite/things/track/withPropertyFromAlbum.js
+++ /dev/null
@@ -1,39 +0,0 @@
-// Gets a single property from this track's album, providing it as the same
-// property name prefixed with '#album.' (by default).
-
-import {input, templateCompositeFrom} from '#composite';
-
-import {withPropertyFromObject} from '#composite/data';
-
-import withAlbum from './withAlbum.js';
-
-export default templateCompositeFrom({
-  annotation: `withPropertyFromAlbum`,
-
-  inputs: {
-    property: input.staticValue({type: 'string'}),
-  },
-
-  outputs: ({
-    [input.staticValue('property')]: property,
-  }) => ['#album.' + property],
-
-  steps: () => [
-    withAlbum(),
-
-    withPropertyFromObject({
-      object: '#album',
-      property: input('property'),
-    }),
-
-    {
-      dependencies: ['#value', input.staticValue('property')],
-      compute: (continuation, {
-        ['#value']: value,
-        [input.staticValue('property')]: property,
-      }) => continuation({
-        ['#album.' + property]: value,
-      }),
-    },
-  ],
-});
diff --git a/src/data/composite/things/track/withPropertyFromOriginalRelease.js b/src/data/composite/things/track/withPropertyFromOriginalRelease.js
deleted file mode 100644
index fd37f6de..00000000
--- a/src/data/composite/things/track/withPropertyFromOriginalRelease.js
+++ /dev/null
@@ -1,86 +0,0 @@
-// 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}))),
-    },
-  ],
-});
diff --git a/src/data/composite/things/track/withSuffixDirectoryFromAlbum.js b/src/data/composite/things/track/withSuffixDirectoryFromAlbum.js
deleted file mode 100644
index 7159a3f4..00000000
--- a/src/data/composite/things/track/withSuffixDirectoryFromAlbum.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import {input, templateCompositeFrom} from '#composite';
-
-import {withResultOfAvailabilityCheck} from '#composite/control-flow';
-
-import withPropertyFromAlbum from './withPropertyFromAlbum.js';
-
-export default templateCompositeFrom({
-  annotation: `withSuffixDirectoryFromAlbum`,
-
-  inputs: {
-    flagValue: input({
-      defaultDependency: 'suffixDirectoryFromAlbum',
-      acceptsNull: true,
-    }),
-  },
-
-  outputs: ['#suffixDirectoryFromAlbum'],
-
-  steps: () => [
-    withResultOfAvailabilityCheck({
-      from: 'suffixDirectoryFromAlbum',
-    }),
-
-    {
-      dependencies: [
-        '#availability',
-        'suffixDirectoryFromAlbum'
-      ],
-
-      compute: (continuation, {
-        ['#availability']: availability,
-        ['suffixDirectoryFromAlbum']: flagValue,
-      }) =>
-        (availability
-          ? continuation.raiseOutput({['#suffixDirectoryFromAlbum']: flagValue})
-          : continuation()),
-    },
-
-    withPropertyFromAlbum({
-      property: input.value('suffixTrackDirectories'),
-    }),
-
-    {
-      dependencies: ['#album.suffixTrackDirectories'],
-      compute: (continuation, {
-        ['#album.suffixTrackDirectories']: suffixTrackDirectories,
-      }) => continuation({
-        ['#suffixDirectoryFromAlbum']:
-          suffixTrackDirectories,
-      }),
-    },
-  ],
-});
diff --git a/src/data/composite/things/track/withTrackArtDate.js b/src/data/composite/things/track/withTrackArtDate.js
deleted file mode 100644
index e2c4d8bc..00000000
--- a/src/data/composite/things/track/withTrackArtDate.js
+++ /dev/null
@@ -1,80 +0,0 @@
-// Gets the date of cover art release. This represents only the track's own
-// unique cover artwork, if any.
-//
-// If the 'fallback' option is false (the default), this will only output
-// the track's own coverArtDate or its album's trackArtDate. If 'fallback'
-// is set, and neither of these is available, it'll output the track's own
-// date instead.
-
-import {input, templateCompositeFrom} from '#composite';
-import {isDate} from '#validators';
-
-import {raiseOutputWithoutDependency} from '#composite/control-flow';
-
-import withDate from './withDate.js';
-import withHasUniqueCoverArt from './withHasUniqueCoverArt.js';
-import withPropertyFromAlbum from './withPropertyFromAlbum.js';
-
-export default templateCompositeFrom({
-  annotation: `withTrackArtDate`,
-
-  inputs: {
-    from: input({
-      validate: isDate,
-      defaultDependency: 'coverArtDate',
-      acceptsNull: true,
-    }),
-
-    fallback: input({
-      type: 'boolean',
-      defaultValue: false,
-    }),
-  },
-
-  outputs: ['#trackArtDate'],
-
-  steps: () => [
-    withHasUniqueCoverArt(),
-
-    raiseOutputWithoutDependency({
-      dependency: '#hasUniqueCoverArt',
-      mode: input.value('falsy'),
-      output: input.value({'#trackArtDate': null}),
-    }),
-
-    {
-      dependencies: [input('from')],
-      compute: (continuation, {
-        [input('from')]: from,
-      }) =>
-        (from
-          ? continuation.raiseOutput({'#trackArtDate': from})
-          : continuation()),
-    },
-
-    withPropertyFromAlbum({
-      property: input.value('trackArtDate'),
-    }),
-
-    {
-      dependencies: [
-        '#album.trackArtDate',
-        input('fallback'),
-      ],
-
-      compute: (continuation, {
-        ['#album.trackArtDate']: albumTrackArtDate,
-        [input('fallback')]: fallback,
-      }) =>
-        (albumTrackArtDate
-          ? continuation.raiseOutput({'#trackArtDate': albumTrackArtDate})
-       : fallback
-          ? continuation()
-          : continuation.raiseOutput({'#trackArtDate': null})),
-    },
-
-    withDate().outputs({
-      '#date': '#trackArtDate',
-    }),
-  ],
-});