« get me outta code hell

hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/content/dependencies/generateAlbumCommentaryPage.js5
-rw-r--r--src/content/dependencies/generateAlbumSidebarGroupBox.js4
-rw-r--r--src/content/dependencies/generateArtTagGalleryPage.js2
-rw-r--r--src/content/dependencies/generateArtTagInfoPage.js2
-rw-r--r--src/content/dependencies/generateArtistInfoPage.js2
-rw-r--r--src/content/dependencies/generateArtistInfoPageMusicVideosChunkItem.js2
-rw-r--r--src/content/dependencies/generateContributionTooltipExternalLinkSection.js10
-rw-r--r--src/content/dependencies/generateFlashInfoPage.js2
-rw-r--r--src/content/dependencies/generateGroupInfoPage.js2
-rw-r--r--src/content/dependencies/generateMusicVideo.js2
-rw-r--r--src/content/dependencies/generateReleaseInfoListenLine.js11
-rw-r--r--src/data/composite/wiki-properties/simpleDate.js2
-rw-r--r--src/data/composite/wiki-properties/urls.js7
-rw-r--r--src/data/things/ArtTag.js9
-rw-r--r--src/data/things/Artist.js4
-rw-r--r--src/data/things/MusicVideo.js27
-rw-r--r--src/data/things/Track.js10
-rw-r--r--src/data/things/album/Album.js3
-rw-r--r--src/data/things/flash/Flash.js3
-rw-r--r--src/data/things/group/Group.js4
-rw-r--r--src/data/yaml.js20
-rw-r--r--src/validators.js18
22 files changed, 106 insertions, 45 deletions
diff --git a/src/content/dependencies/generateAlbumCommentaryPage.js b/src/content/dependencies/generateAlbumCommentaryPage.js
index b6c8edf6..a380f468 100644
--- a/src/content/dependencies/generateAlbumCommentaryPage.js
+++ b/src/content/dependencies/generateAlbumCommentaryPage.js
@@ -51,7 +51,8 @@ export default {
         relation('linkAlbum', album);
 
       relations.albumCommentaryListeningLinks =
-        album.urls.map(url => relation('linkExternal', url));
+        album.urls
+          .map(entry => relation('linkExternal', entry.url));
 
       if (album.hasCoverArt) {
         relations.albumCommentaryCover =
@@ -74,7 +75,7 @@ export default {
     relations.trackCommentaryListeningLinks =
       query.tracksWithCommentary
         .map(track =>
-          track.urls.map(url => relation('linkExternal', url)));
+          track.urls.map(entry => relation('linkExternal', entry.url)));
 
     relations.trackCommentaryCovers =
       query.tracksWithCommentary
diff --git a/src/content/dependencies/generateAlbumSidebarGroupBox.js b/src/content/dependencies/generateAlbumSidebarGroupBox.js
index 0a9c0db9..15fedf75 100644
--- a/src/content/dependencies/generateAlbumSidebarGroupBox.js
+++ b/src/content/dependencies/generateAlbumSidebarGroupBox.js
@@ -38,8 +38,8 @@ export default {
       relation('linkGroup', group);
 
     relations.externalLinks =
-      group.urls.map(url =>
-        relation('linkExternal', url));
+      group.urls
+        .map(entry => relation('linkExternal', entry.url));
 
     if (group.descriptionShort) {
       relations.description =
diff --git a/src/content/dependencies/generateArtTagGalleryPage.js b/src/content/dependencies/generateArtTagGalleryPage.js
index 646975ef..ec0624d1 100644
--- a/src/content/dependencies/generateArtTagGalleryPage.js
+++ b/src/content/dependencies/generateArtTagGalleryPage.js
@@ -42,7 +42,7 @@ export default {
     if (!empty(artTag.extraReadingURLs)) {
       relations.extraReadingLinks =
         artTag.extraReadingURLs
-          .map(url => relation('linkExternal', url));
+          .map(entry => relation('linkExternal', entry.url));
     }
 
     if (!empty(artTag.directAncestorArtTags)) {
diff --git a/src/content/dependencies/generateArtTagInfoPage.js b/src/content/dependencies/generateArtTagInfoPage.js
index 683eeab6..db26260b 100644
--- a/src/content/dependencies/generateArtTagInfoPage.js
+++ b/src/content/dependencies/generateArtTagInfoPage.js
@@ -50,7 +50,7 @@ export default {
 
     extraReadingLinks:
       artTag.extraReadingURLs
-        .map(url => relation('linkExternal', url)),
+        .map(entry => relation('linkExternal', entry.url)),
 
     relatedArtTagLinks:
       artTag.relatedArtTags
diff --git a/src/content/dependencies/generateArtistInfoPage.js b/src/content/dependencies/generateArtistInfoPage.js
index 29bc34e6..3961dc49 100644
--- a/src/content/dependencies/generateArtistInfoPage.js
+++ b/src/content/dependencies/generateArtistInfoPage.js
@@ -62,7 +62,7 @@ export default {
 
     visitLinks:
       artist.urls
-        .map(url => relation('linkExternal', url)),
+        .map(entry => relation('linkExternal', entry.url)),
 
     tracksChunkedList:
       relation('generateArtistInfoPageTracksChunkedList', artist),
diff --git a/src/content/dependencies/generateArtistInfoPageMusicVideosChunkItem.js b/src/content/dependencies/generateArtistInfoPageMusicVideosChunkItem.js
index 8bae860d..570a984a 100644
--- a/src/content/dependencies/generateArtistInfoPageMusicVideosChunkItem.js
+++ b/src/content/dependencies/generateArtistInfoPageMusicVideosChunkItem.js
@@ -38,7 +38,7 @@ export default {
 
     externalLinks:
       query.musicVideo.urls
-        .map(url => relation('linkExternal', url)),
+        .map(entry => relation('linkExternal', entry.url)),
   }),
 
   data: (query, _artist, contribs) => ({
diff --git a/src/content/dependencies/generateContributionTooltipExternalLinkSection.js b/src/content/dependencies/generateContributionTooltipExternalLinkSection.js
index 210db1e9..cc61fab4 100644
--- a/src/content/dependencies/generateContributionTooltipExternalLinkSection.js
+++ b/src/content/dependencies/generateContributionTooltipExternalLinkSection.js
@@ -4,19 +4,21 @@ export default {
   relations: (relation, contribution) => ({
     icons:
       contribution.artist.urls
-        .map(url => relation('generateExternalIcon', url)),
+        .map(entry => relation('generateExternalIcon', entry.url)),
 
     handles:
       contribution.artist.urls
-        .map(url => relation('generateExternalHandle', url)),
+        .map(entry => relation('generateExternalHandle', entry.url)),
 
     platforms:
       contribution.artist.urls
-        .map(url => relation('generateExternalPlatform', url)),
+        .map(entry => relation('generateExternalPlatform', entry.url)),
   }),
 
   data: (contribution) => ({
-    urls: contribution.artist.urls,
+    urls:
+      contribution.artist.urls
+        .map(entry => entry.url),
   }),
 
   generate: (data, relations, {html, language}) =>
diff --git a/src/content/dependencies/generateFlashInfoPage.js b/src/content/dependencies/generateFlashInfoPage.js
index b4e8c757..b334412b 100644
--- a/src/content/dependencies/generateFlashInfoPage.js
+++ b/src/content/dependencies/generateFlashInfoPage.js
@@ -42,7 +42,7 @@ export default {
 
     externalLinks:
       query.urls
-        .map(url => relation('linkExternal', url)),
+        .map(entry => relation('linkExternal', entry.url)),
 
     artworkColumn:
       relation('generateFlashArtworkColumn', flash),
diff --git a/src/content/dependencies/generateGroupInfoPage.js b/src/content/dependencies/generateGroupInfoPage.js
index 0f3093b2..261d2212 100644
--- a/src/content/dependencies/generateGroupInfoPage.js
+++ b/src/content/dependencies/generateGroupInfoPage.js
@@ -51,7 +51,7 @@ export default {
 
     visitLinks:
       group.urls
-        .map(url => relation('linkExternal', url)),
+        .map(entry => relation('linkExternal', entry.url)),
 
     description:
       relation('transformContent', group.description),
diff --git a/src/content/dependencies/generateMusicVideo.js b/src/content/dependencies/generateMusicVideo.js
index e00b83b0..15eb233b 100644
--- a/src/content/dependencies/generateMusicVideo.js
+++ b/src/content/dependencies/generateMusicVideo.js
@@ -21,7 +21,7 @@ export default {
 
     watchLinks:
       musicVideo.urls
-        .map(url => relation('linkExternal', url)),
+        .map(entry => relation('linkExternal', entry.url)),
   }),
 
   data: (musicVideo, _thing) => ({
diff --git a/src/content/dependencies/generateReleaseInfoListenLine.js b/src/content/dependencies/generateReleaseInfoListenLine.js
index 97f248d6..cd3baaf2 100644
--- a/src/content/dependencies/generateReleaseInfoListenLine.js
+++ b/src/content/dependencies/generateReleaseInfoListenLine.js
@@ -64,7 +64,8 @@ export default {
 
   relations: (relation, query, _thing) => ({
     links:
-      query.urls.map(url => relation('linkExternal', url)),
+      query.urls
+        .map(entry => relation('linkExternal', entry.url)),
   }),
 
   data(query, thing) {
@@ -76,13 +77,13 @@ export default {
       unique([
         ...query.artists.flatMap(artist => artist.urls),
         ...query.artistGroups.flatMap(group => group.urls),
-      ]).map(url => new URL(url));
+      ]).map(entry => new URL(entry.url));
 
     const albumArtistURLs =
       unique([
         ...query.albumArtists.flatMap(artist => artist.urls),
         ...query.albumArtistGroups.flatMap(group => group.urls),
-      ]).map(url => new URL(url));
+      ]).map(entry => new URL(entry.url));
 
     const boundGetReleaseContext = urlString =>
       getReleaseContext(urlString, {
@@ -91,10 +92,10 @@ export default {
       });
 
     let releaseContexts =
-      query.urls.map(boundGetReleaseContext);
+      query.urls.map(({url}) => boundGetReleaseContext(url));
 
     const albumReleaseContexts =
-      query.album.urls.map(boundGetReleaseContext);
+      query.album.urls.map(({url}) => boundGetReleaseContext(url));
 
     const presentReleaseContexts =
       unique(releaseContexts.filter(Boolean));
diff --git a/src/data/composite/wiki-properties/simpleDate.js b/src/data/composite/wiki-properties/simpleDate.js
index f08d8323..238b906f 100644
--- a/src/data/composite/wiki-properties/simpleDate.js
+++ b/src/data/composite/wiki-properties/simpleDate.js
@@ -4,8 +4,6 @@
 
 import {isDate} from '#validators';
 
-// TODO: Not templateCompositeFrom.
-
 export default function() {
   return {
     flags: {update: true, expose: true},
diff --git a/src/data/composite/wiki-properties/urls.js b/src/data/composite/wiki-properties/urls.js
index 04ccf689..5525b462 100644
--- a/src/data/composite/wiki-properties/urls.js
+++ b/src/data/composite/wiki-properties/urls.js
@@ -1,14 +1,13 @@
 // A list of URLs! This will always be present on the data object, even if set
 // to an empty array or null.
 
-import {isCuratedURL, validateArrayItems} from '#validators';
-
-// TODO: Not templateCompositeFrom.
+import {isCuratedURLList} from '#validators';
+import {templateCompositeFrom} from '#composite';
 
 export default function() {
   return {
     flags: {update: true, expose: true},
-    update: {validate: validateArrayItems(isCuratedURL)},
+    update: {validate: isCuratedURLList},
     expose: {transform: value => value ?? []},
   };
 }
diff --git a/src/data/things/ArtTag.js b/src/data/things/ArtTag.js
index 9d35f54d..1da32b0a 100644
--- a/src/data/things/ArtTag.js
+++ b/src/data/things/ArtTag.js
@@ -2,7 +2,8 @@ import {input, V} from '#composite';
 import Thing from '#thing';
 import {unique} from '#sugar';
 import {isName} from '#validators';
-import {parseAdditionalNames, parseAnnotatedReferences} from '#yaml';
+import {parseAdditionalNames, parseAnnotatedReferences, parseURLs}
+  from '#yaml';
 
 import {
   exitWithoutDependency,
@@ -170,7 +171,11 @@ export class ArtTag extends Thing {
       'Short Name': {property: 'nameShort'},
       'Directory': {property: 'directory'},
       'Description': {property: 'description'},
-      'Extra Reading URLs': {property: 'extraReadingURLs'},
+
+      'Extra Reading URLs': {
+        property: 'extraReadingURLs',
+        transform: parseURLs,
+      },
 
       'Additional Names': {
         property: 'additionalNames',
diff --git a/src/data/things/Artist.js b/src/data/things/Artist.js
index 6ce448ff..64798527 100644
--- a/src/data/things/Artist.js
+++ b/src/data/things/Artist.js
@@ -4,7 +4,7 @@ import CacheableObject from '#cacheable-object';
 import {colors} from '#cli';
 import {input, V} from '#composite';
 import Thing from '#thing';
-import {parseArtistAliases, parseArtwork} from '#yaml';
+import {parseArtistAliases, parseArtwork, parseURLs} from '#yaml';
 
 import {
   sortAlbumsTracksChronologically,
@@ -351,7 +351,7 @@ export class Artist extends Thing {
     fields: {
       'Artist': {property: 'name'},
       'Directory': {property: 'directory'},
-      'URLs': {property: 'urls'},
+      'URLs': {property: 'urls', transform: parseURLs},
       'Context Notes': {property: 'contextNotes'},
 
       // note: doesn't really work as an independent field yet
diff --git a/src/data/things/MusicVideo.js b/src/data/things/MusicVideo.js
index 77c8c619..dbb99a7f 100644
--- a/src/data/things/MusicVideo.js
+++ b/src/data/things/MusicVideo.js
@@ -4,9 +4,16 @@ import {colors} from '#cli';
 import {input, V} from '#composite';
 import {empty} from '#sugar';
 import Thing from '#thing';
-import {is, isCuratedURL, isDate, isStringNonEmpty, validateArrayItems}
-  from '#validators';
-import {parseContributors, parseDate} from '#yaml';
+import {parseContributors, parseDate, parseURLs} from '#yaml';
+
+import {
+  is,
+  isCuratedURL,
+  isCuratedURLEntry,
+  isDate,
+  isStringNonEmpty,
+  validateArrayItems,
+} from '#validators';
 
 import {constituteFrom} from '#composite/wiki-data';
 
@@ -66,6 +73,7 @@ export class MusicVideo extends Thing {
       constituteFrom('thing', V('date')),
     ],
 
+    // This is a string, not a {url, annotation} entry.
     url: {
       flags: {update: true, expose: true},
 
@@ -77,7 +85,7 @@ export class MusicVideo extends Thing {
         dependencies: ['_urls'],
         transform: (url, {'_urls': urls}) =>
           (url          ? url
-         : !empty(urls) ? urls[0]
+         : !empty(urls) ? urls[0].url
                         : null),
       },
     },
@@ -86,14 +94,14 @@ export class MusicVideo extends Thing {
       flags: {update: true, expose: true},
 
       update: {
-        validate: validateArrayItems(isCuratedURL),
+        validate: validateArrayItems(isCuratedURLEntry),
       },
 
       expose: {
         dependencies: ['_url'],
         transform: (urls, {'_url': url}) =>
-          (url && urls ? [url, ...urls]
-         : url         ? [url]
+          (url && urls ? [{url}, ...urls]
+         : url         ? [{url}]
          :        urls ? urls
                        : []),
       },
@@ -142,8 +150,9 @@ export class MusicVideo extends Thing {
       'Label': {property: 'label'},
       'Directory': {property: 'unqualifiedDirectory'},
       'Date': {property: 'date', transform: parseDate},
-      'URL': {property: 'url'},
-      'URLs': {property: 'urls'},
+
+      'URL': {property: 'url'}, // Just a string, not an object
+      'URLs': {property: 'urls', transform: parseURLs},
 
       'Cover Art File Extension': {property: 'coverArtFileExtension'},
       'Cover Art Dimensions': {property: 'coverArtDimensions'},
diff --git a/src/data/things/Track.js b/src/data/things/Track.js
index 36e3733d..cb785211 100644
--- a/src/data/things/Track.js
+++ b/src/data/things/Track.js
@@ -35,6 +35,7 @@ import {
   parseDuration,
   parseLyrics,
   parseMusicVideos,
+  parseURLs,
 } from '#yaml';
 
 import {
@@ -1004,13 +1005,18 @@ export class Track extends Thing {
         transform: parseDuration,
       },
 
-      'Color': {property: 'color'},
+      'Color': {
+        property: 'color',
+      },
 
       'Needs Lyrics': {
         property: 'needsLyrics',
       },
 
-      'URLs': {property: 'urls'},
+      'URLs': {
+        property: 'urls',
+        transform: parseURLs,
+      },
 
       // Artworks
 
diff --git a/src/data/things/album/Album.js b/src/data/things/album/Album.js
index 61420e52..1ae10ab1 100644
--- a/src/data/things/album/Album.js
+++ b/src/data/things/album/Album.js
@@ -17,6 +17,7 @@ import {
   parseDimensions,
   parseMusicVideos,
   parseWallpaperParts,
+  parseURLs,
 } from '#yaml';
 
 import {withFlattenedList, withPropertyFromList} from '#composite/data';
@@ -651,7 +652,7 @@ export class Album extends Thing {
 
       'Color': {property: 'color'},
 
-      'URLs': {property: 'urls'},
+      'URLs': {property: 'urls', transform: parseURLs},
 
       // Artworks
       //  (Note - this YAML section is deliberately ordered differently
diff --git a/src/data/things/flash/Flash.js b/src/data/things/flash/Flash.js
index b06b0452..588fbae5 100644
--- a/src/data/things/flash/Flash.js
+++ b/src/data/things/flash/Flash.js
@@ -12,6 +12,7 @@ import {
   parseCreditingSources,
   parseDate,
   parseDimensions,
+  parseURLs,
 } from '#yaml';
 
 import {withPropertyFromObject} from '#composite/data';
@@ -216,7 +217,7 @@ export class Flash extends Thing {
       'Directory': {property: 'directory'},
       'Page': {property: 'page'},
       'Color': {property: 'color'},
-      'URLs': {property: 'urls'},
+      'URLs': {property: 'urls', transform: parseURLs},
 
       'Date': {
         property: 'date',
diff --git a/src/data/things/group/Group.js b/src/data/things/group/Group.js
index f8dd413e..99ad633b 100644
--- a/src/data/things/group/Group.js
+++ b/src/data/things/group/Group.js
@@ -1,7 +1,7 @@
 import {input, V} from '#composite';
 import Thing from '#thing';
 import {isBoolean} from '#validators';
-import {parseAnnotatedReferences, parseSerieses} from '#yaml';
+import {parseAnnotatedReferences, parseSerieses, parseURLs} from '#yaml';
 
 import {withPropertyFromObject} from '#composite/data';
 import {withUniqueReferencingThing} from '#composite/wiki-data';
@@ -176,7 +176,7 @@ export class Group extends Thing {
       },
 
       'Description': {property: 'description'},
-      'URLs': {property: 'urls'},
+      'URLs': {property: 'urls', transform: parseURLs},
 
       'Closely Linked Artists': {
         property: 'closelyLinkedArtists',
diff --git a/src/data/yaml.js b/src/data/yaml.js
index 58acb7c8..60017b3d 100644
--- a/src/data/yaml.js
+++ b/src/data/yaml.js
@@ -733,6 +733,26 @@ export function parseContributors(entries) {
   });
 }
 
+export function parseURLs(entries) {
+  return parseArrayEntries(entries, item => {
+    if (typeof item === 'object' && item['URL'])
+      return {
+        url: item['URL'],
+        annotation: item['Annotation'] ?? null,
+      };
+
+    if (typeof item !== 'string') return item;
+
+    const match = item.match(extractAccentRegex);
+    if (!match) return item;
+
+    return {
+      url: match.groups.main,
+      annotation: match.groups.accent,
+    };
+  });
+}
+
 export function parseAdditionalFiles(entries, {subdoc, AdditionalFile}) {
   return parseArrayEntries(entries, item => {
     if (typeof item !== 'object') return item;
diff --git a/src/validators.js b/src/validators.js
index 7dcd7b8c..2c3bd8e6 100644
--- a/src/validators.js
+++ b/src/validators.js
@@ -817,6 +817,24 @@ export function isCuratedURL(string) {
   return true;
 }
 
+export const validateURLEntry = (isURL) =>
+  validateProperties({
+    url: isURL,
+    annotation: optional(isStringNonEmpty),
+  });
+
+export const isURLEntry =
+  validateURLEntry(isURL);
+
+export const isCuratedURLEntry =
+  validateURLEntry(isCuratedURL);
+
+export const isURLList =
+  validateArrayItems(isURLEntry);
+
+export const isCuratedURLList =
+  validateArrayItems(isCuratedURLEntry);
+
 export function validateReference(type) {
   return (ref) => {
     isStringNonEmpty(ref);