« 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/things
diff options
context:
space:
mode:
Diffstat (limited to 'src/data/things')
-rw-r--r--src/data/things/language.js49
-rw-r--r--src/data/things/track.js23
2 files changed, 55 insertions, 17 deletions
diff --git a/src/data/things/language.js b/src/data/things/language.js
index 997cf31e..43f69f3d 100644
--- a/src/data/things/language.js
+++ b/src/data/things/language.js
@@ -4,16 +4,16 @@ import {withAggregate} from '#aggregate';
 import CacheableObject from '#cacheable-object';
 import {input} from '#composite';
 import * as html from '#html';
-import {empty, withEntries} from '#sugar';
+import {accumulateSum, empty, withEntries} from '#sugar';
 import {isLanguageCode} from '#validators';
 import Thing from '#thing';
 import {languageOptionRegex} from '#wiki-data';
 
 import {
+  externalLinkSpec,
   getExternalLinkStringOfStyleFromDescriptors,
   getExternalLinkStringsFromDescriptors,
   isExternalLinkContext,
-  isExternalLinkSpec,
   isExternalLinkStyle,
 } from '#external-links';
 
@@ -82,13 +82,6 @@ export class Language extends Thing {
       update: {validate: (t) => typeof t === 'object'},
     },
 
-    // List of descriptors for providing to external link utilities when using
-    // language.formatExternalLink - refer to #external-links for info.
-    externalLinkSpec: {
-      flags: {update: true, expose: true},
-      update: {validate: isExternalLinkSpec},
-    },
-
     // Expose only
 
     isLanguage: [
@@ -106,12 +99,14 @@ export class Language extends Thing {
 
     intl_date: this.#intlHelper(Intl.DateTimeFormat, {full: true}),
     intl_dateYear: this.#intlHelper(Intl.DateTimeFormat, {year: 'numeric'}),
+    intl_dateMonthDay: this.#intlHelper(Intl.DateTimeFormat, {month: 'numeric', day: 'numeric'}),
     intl_number: this.#intlHelper(Intl.NumberFormat),
     intl_listConjunction: this.#intlHelper(Intl.ListFormat, {type: 'conjunction'}),
     intl_listDisjunction: this.#intlHelper(Intl.ListFormat, {type: 'disjunction'}),
     intl_listUnit: this.#intlHelper(Intl.ListFormat, {type: 'unit'}),
     intl_pluralCardinal: this.#intlHelper(Intl.PluralRules, {type: 'cardinal'}),
     intl_pluralOrdinal: this.#intlHelper(Intl.PluralRules, {type: 'ordinal'}),
+    intl_wordSegmenter: this.#intlHelper(Intl.Segmenter, {granularity: 'word'}),
 
     validKeys: {
       flags: {expose: true},
@@ -169,6 +164,15 @@ export class Language extends Thing {
     }
   }
 
+  countWords(text) {
+    this.assertIntlAvailable('intl_wordSegmenter');
+
+    const string = html.resolve(text, {normalize: 'plain'});
+    const segments = this.intl_wordSegmenter.segment(string);
+
+    return accumulateSum(segments, segment => segment.isWordLike ? 1 : 0);
+  }
+
   getUnitForm(value) {
     this.assertIntlAvailable('intl_pluralCardinal');
     return this.intl_pluralCardinal.select(value);
@@ -350,13 +354,19 @@ export class Language extends Thing {
 
       partInProgress += template.slice(lastIndex, match.index);
 
-      for (const insertionItem of html.smush(insertion).content) {
+      const insertionItems = html.smush(insertion).content;
+      if (insertionItems.length === 1 && typeof insertionItems[0] !== 'string') {
+        // Push the insertion exactly as it is, rather than manipulating.
+        if (partInProgress) outputParts.push(partInProgress);
+        outputParts.push(insertion);
+        partInProgress = '';
+      } else for (const insertionItem of insertionItems) {
         if (typeof insertionItem === 'string') {
           // Join consecutive strings together.
           partInProgress += insertionItem;
         } else {
           // Push the string part in progress, then the insertion as-is.
-          outputParts.push(partInProgress);
+          if (partInProgress) outputParts.push(partInProgress);
           outputParts.push(insertionItem);
           partInProgress = '';
         }
@@ -470,6 +480,15 @@ export class Language extends Thing {
     return this.intl_dateYear.format(date);
   }
 
+  formatMonthDay(date) {
+    if (date === null || date === undefined) {
+      return html.blank();
+    }
+
+    this.assertIntlAvailable('intl_dateMonthDay');
+    return this.intl_dateMonthDay.format(date);
+  }
+
   formatYearRange(startDate, endDate) {
     // formatYearRange expects both values to be present, but if both are null
     // or both are undefined, that's just blank content.
@@ -648,10 +667,6 @@ export class Language extends Thing {
     style = 'platform',
     context = 'generic',
   } = {}) {
-    if (!this.externalLinkSpec) {
-      throw new TypeError(`externalLinkSpec unavailable`);
-    }
-
     // Null or undefined url is blank content.
     if (url === null || url === undefined) {
       return html.blank();
@@ -660,7 +675,7 @@ export class Language extends Thing {
     isExternalLinkContext(context);
 
     if (style === 'all') {
-      return getExternalLinkStringsFromDescriptors(url, this.externalLinkSpec, {
+      return getExternalLinkStringsFromDescriptors(url, externalLinkSpec, {
         language: this,
         context,
       });
@@ -669,7 +684,7 @@ export class Language extends Thing {
     isExternalLinkStyle(style);
 
     const result =
-      getExternalLinkStringOfStyleFromDescriptors(url, style, this.externalLinkSpec, {
+      getExternalLinkStringOfStyleFromDescriptors(url, style, externalLinkSpec, {
         language: this,
         context,
       });
diff --git a/src/data/things/track.js b/src/data/things/track.js
index 93193b6a..64790a61 100644
--- a/src/data/things/track.js
+++ b/src/data/things/track.js
@@ -393,6 +393,17 @@ export class Track extends Thing {
 
     // > Update & expose - Referenced tracks
 
+    previousProductionTracks: [
+      inheritFromMainRelease({
+        notFoundValue: input.value([]),
+      }),
+
+      referenceList({
+        class: input.value(Track),
+        find: soupyFind.input('trackMainReleasesOnly'),
+      }),
+    ],
+
     referencedTracks: [
       inheritFromMainRelease({
         notFoundValue: input.value([]),
@@ -563,6 +574,10 @@ export class Track extends Thing {
       }),
     ],
 
+    followingProductionTracks: reverseReferenceList({
+      reverse: soupyReverse.input('tracksWhichAreFollowingProductionsOf'),
+    }),
+
     referencedByTracks: reverseReferenceList({
       reverse: soupyReverse.input('tracksWhichReference'),
     }),
@@ -701,6 +716,7 @@ export class Track extends Thing {
 
       // Referenced tracks
 
+      'Previous Productions': {property: 'previousProductionTracks'},
       'Referenced Tracks': {property: 'referencedTracks'},
       'Sampled Tracks': {property: 'sampledTracks'},
 
@@ -912,6 +928,13 @@ export class Track extends Thing {
       referencing: track => track.isSecondaryRelease ? [track] : [],
       referenced: track => [track.mainReleaseTrack],
     },
+
+    tracksWhichAreFollowingProductionsOf: {
+      bindTo: 'trackData',
+
+      referencing: track => track,
+      referenced: track => track.previousProductionTracks,
+    },
   };
 
   // Track YAML loading is handled in album.js.