« 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/files
diff options
context:
space:
mode:
Diffstat (limited to 'src/data/files')
-rw-r--r--src/data/files/album.js74
-rw-r--r--src/data/files/art-tag.js32
-rw-r--r--src/data/files/artist.js16
-rw-r--r--src/data/files/flash.js78
-rw-r--r--src/data/files/group.js45
-rw-r--r--src/data/files/homepage-layout.js87
-rw-r--r--src/data/files/index.js10
-rw-r--r--src/data/files/news.js16
-rw-r--r--src/data/files/sorting-rule.js13
-rw-r--r--src/data/files/static-page.js24
-rw-r--r--src/data/files/wiki-info.js10
11 files changed, 405 insertions, 0 deletions
diff --git a/src/data/files/album.js b/src/data/files/album.js
new file mode 100644
index 00000000..84cda226
--- /dev/null
+++ b/src/data/files/album.js
@@ -0,0 +1,74 @@
+import * as path from 'node:path';
+
+import {traverse} from '#node-utils';
+import {sortAlbumsTracksChronologically, sortChronologically} from '#sort';
+import {empty} from '#sugar';
+
+export default ({
+  documentModes: {headerAndEntries},
+  thingConstructors: {Album, Track, TrackSection},
+}) => ({
+  title: `Process album files`,
+
+  files: dataPath =>
+    traverse(path.join(dataPath, 'album'), {
+      filterFile: name => path.extname(name) === '.yaml',
+      prefixPath: 'album',
+    }),
+
+  documentMode: headerAndEntries,
+  headerDocumentThing: Album,
+  entryDocumentThing: document =>
+    ('Section' in document
+      ? TrackSection
+      : Track),
+
+  connect({header: album, entries}) {
+    const trackSections = [];
+
+    let currentTrackSection = new TrackSection();
+    let currentTrackSectionTracks = [];
+
+    Object.assign(currentTrackSection, {
+      name: `Default Track Section`,
+      isDefaultTrackSection: true,
+    });
+
+    const closeCurrentTrackSection = () => {
+      if (
+        currentTrackSection.isDefaultTrackSection &&
+        empty(currentTrackSectionTracks)
+      ) {
+        return;
+      }
+
+      currentTrackSection.tracks = currentTrackSectionTracks;
+      currentTrackSection.album = album;
+
+      trackSections.push(currentTrackSection);
+    };
+
+    for (const entry of entries) {
+      if (entry instanceof TrackSection) {
+        closeCurrentTrackSection();
+        currentTrackSection = entry;
+        currentTrackSectionTracks = [];
+        continue;
+      }
+
+      entry.album = album;
+      entry.trackSection = currentTrackSection;
+
+      currentTrackSectionTracks.push(entry);
+    }
+
+    closeCurrentTrackSection();
+
+    album.trackSections = trackSections;
+  },
+
+  sort({albumData, trackData}) {
+    sortChronologically(albumData);
+    sortAlbumsTracksChronologically(trackData);
+  },
+});
diff --git a/src/data/files/art-tag.js b/src/data/files/art-tag.js
new file mode 100644
index 00000000..67a22ca7
--- /dev/null
+++ b/src/data/files/art-tag.js
@@ -0,0 +1,32 @@
+import {readFile} from 'node:fs/promises';
+import * as path from 'node:path';
+
+import {traverse} from '#node-utils';
+import {sortAlphabetically} from '#sort';
+
+export default ({
+  documentModes: {allTogether},
+  thingConstructors: {ArtTag},
+}) => ({
+  title: `Process art tags file`,
+
+  files: dataPath =>
+    Promise.allSettled([
+      readFile(path.join(dataPath, 'tags.yaml'))
+        .then(() => ['tags.yaml']),
+
+      traverse(path.join(dataPath, 'art-tags'), {
+        filterFile: name => path.extname(name) === '.yaml',
+        prefixPath: 'art-tags',
+      }),
+    ]).then(results => results
+        .filter(({status}) => status === 'fulfilled')
+        .flatMap(({value}) => value)),
+
+  documentMode: allTogether,
+  documentThing: ArtTag,
+
+  sort({artTagData}) {
+    sortAlphabetically(artTagData);
+  },
+});
diff --git a/src/data/files/artist.js b/src/data/files/artist.js
new file mode 100644
index 00000000..ef971171
--- /dev/null
+++ b/src/data/files/artist.js
@@ -0,0 +1,16 @@
+import {sortAlphabetically} from '#sort';
+
+export default ({
+  documentModes: {allInOne},
+  thingConstructors: {Artist},
+}) => ({
+  title: `Process artists file`,
+  file: 'artists.yaml',
+
+  documentMode: allInOne,
+  documentThing: Artist,
+
+  sort({artistData}) {
+    sortAlphabetically(artistData);
+  },
+});
diff --git a/src/data/files/flash.js b/src/data/files/flash.js
new file mode 100644
index 00000000..3e4f750f
--- /dev/null
+++ b/src/data/files/flash.js
@@ -0,0 +1,78 @@
+import {sortFlashesChronologically} from '#sort';
+
+export default ({
+  documentModes: {allInOne},
+  thingConstructors: {Flash, FlashAct, FlashSide},
+}) => ({
+  title: `Process flashes file`,
+  file: 'flashes.yaml',
+
+  documentMode: allInOne,
+  documentThing: document =>
+    ('Side' in document
+      ? FlashSide
+   : 'Act' in document
+      ? FlashAct
+      : Flash),
+
+  connect(results) {
+    let thing, i;
+
+    for (i = 0; thing = results[i]; i++) {
+      if (thing.isFlashSide) {
+        const side = thing;
+        const acts = [];
+
+        for (i++; thing = results[i]; i++) {
+          if (thing.isFlashAct) {
+            const act = thing;
+            const flashes = [];
+
+            for (i++; thing = results[i]; i++) {
+              if (thing.isFlash) {
+                const flash = thing;
+
+                flash.act = act;
+                flashes.push(flash);
+
+                continue;
+              }
+
+              i--;
+              break;
+            }
+
+            act.side = side;
+            act.flashes = flashes;
+            acts.push(act);
+
+            continue;
+          }
+
+          if (thing.isFlash) {
+            throw new Error(`Flashes must be under an act`);
+          }
+
+          i--;
+          break;
+        }
+
+        side.acts = acts;
+
+        continue;
+      }
+
+      if (thing.isFlashAct) {
+        throw new Error(`Acts must be under a side`);
+      }
+
+      if (thing.isFlash) {
+        throw new Error(`Flashes must be under a side and act`);
+      }
+    }
+  },
+
+  sort({flashData}) {
+    sortFlashesChronologically(flashData);
+  },
+});
diff --git a/src/data/files/group.js b/src/data/files/group.js
new file mode 100644
index 00000000..c10cbf98
--- /dev/null
+++ b/src/data/files/group.js
@@ -0,0 +1,45 @@
+import Thing from '#thing';
+
+export default ({
+  documentModes: {allInOne},
+  thingConstructors: {Group, GroupCategory},
+}) => ({
+  title: `Process groups file`,
+  file: 'groups.yaml',
+
+  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,
+});
diff --git a/src/data/files/homepage-layout.js b/src/data/files/homepage-layout.js
new file mode 100644
index 00000000..646beff6
--- /dev/null
+++ b/src/data/files/homepage-layout.js
@@ -0,0 +1,87 @@
+import {empty} from '#sugar';
+
+export default ({
+  documentModes: {allInOne},
+  thingConstructors: {
+    HomepageLayout,
+    HomepageLayoutActionsRow,
+    HomepageLayoutAlbumCarouselRow,
+    HomepageLayoutAlbumGridRow,
+    HomepageLayoutRow,
+    HomepageLayoutSection,
+  },
+}) => ({
+  title: `Process homepage layout file`,
+  file: 'homepage.yaml',
+
+  documentMode: allInOne,
+  documentThing: document => {
+    if (document['Homepage']) {
+      return HomepageLayout;
+    }
+
+    if (document['Section']) {
+      return HomepageLayoutSection;
+    }
+
+    if (document['Row']) {
+      switch (document['Row']) {
+        case 'actions':
+          return HomepageLayoutActionsRow;
+        case 'album carousel':
+          return HomepageLayoutAlbumCarouselRow;
+        case 'album grid':
+          return HomepageLayoutAlbumGridRow;
+        default:
+          throw new TypeError(`Unrecognized row type ${document['Row']}`);
+      }
+    }
+
+    return null;
+  },
+
+  connect(results) {
+    if (!empty(results) && !(results[0] instanceof HomepageLayout)) {
+      throw new Error(`Expected 'Homepage' document at top of homepage layout file`);
+    }
+
+    const homepageLayout = results[0];
+    const sections = [];
+
+    let currentSection = null;
+    let currentSectionRows = [];
+
+    const closeCurrentSection = () => {
+      if (currentSection) {
+        for (const row of currentSectionRows) {
+          row.section = currentSection;
+        }
+
+        currentSection.rows = currentSectionRows;
+        sections.push(currentSection);
+
+        currentSection = null;
+        currentSectionRows = [];
+      }
+    };
+
+    for (const entry of results.slice(1)) {
+      if (entry instanceof HomepageLayout) {
+        throw new Error(`Expected only one 'Homepage' document in total`);
+      } else if (entry instanceof HomepageLayoutSection) {
+        closeCurrentSection();
+        currentSection = entry;
+      } else if (entry instanceof HomepageLayoutRow) {
+        if (currentSection) {
+          currentSectionRows.push(entry);
+        } else {
+          throw new Error(`Expected a 'Section' document to add following rows into`);
+        }
+      }
+    }
+
+    closeCurrentSection();
+
+    homepageLayout.sections = sections;
+  },
+});
diff --git a/src/data/files/index.js b/src/data/files/index.js
new file mode 100644
index 00000000..f3efebad
--- /dev/null
+++ b/src/data/files/index.js
@@ -0,0 +1,10 @@
+export {default as getAlbumLoadingSpec} from './album.js';
+export {default as getArtistLoadingSpec} from './artist.js';
+export {default as getArtTagLoadingSpec} from './art-tag.js';
+export {default as getFlashLoadingSpec} from './flash.js';
+export {default as getGroupLoadingSpec} from './group.js';
+export {default as getHomepageLayoutLoadingSpec} from './homepage-layout.js';
+export {default as getNewsLoadingSpec} from './news.js';
+export {default as getSortingRuleLoadingSpec} from './sorting-rule.js';
+export {default as getStaticPageLoadingSpec} from './static-page.js';
+export {default as getWikiInfoLoadingSpec} from './wiki-info.js';
diff --git a/src/data/files/news.js b/src/data/files/news.js
new file mode 100644
index 00000000..5b4a3029
--- /dev/null
+++ b/src/data/files/news.js
@@ -0,0 +1,16 @@
+import {sortChronologically} from '#sort';
+
+export default ({
+  documentModes: {allInOne},
+  thingConstructors: {NewsEntry},
+}) => ({
+  title: `Process news data file`,
+  file: 'news.yaml',
+
+  documentMode: allInOne,
+  documentThing: NewsEntry,
+
+  sort({newsData}) {
+    sortChronologically(newsData, {latestFirst: true});
+  },
+});
diff --git a/src/data/files/sorting-rule.js b/src/data/files/sorting-rule.js
new file mode 100644
index 00000000..61e1df23
--- /dev/null
+++ b/src/data/files/sorting-rule.js
@@ -0,0 +1,13 @@
+export default ({
+  documentModes: {allInOne},
+  thingConstructors: {DocumentSortingRule},
+}) => ({
+  title: `Process sorting rules file`,
+  file: 'sorting-rules.yaml',
+
+  documentMode: allInOne,
+  documentThing: document =>
+    (document['Sort Documents']
+      ? DocumentSortingRule
+      : null),
+});
diff --git a/src/data/files/static-page.js b/src/data/files/static-page.js
new file mode 100644
index 00000000..c7622bc8
--- /dev/null
+++ b/src/data/files/static-page.js
@@ -0,0 +1,24 @@
+import * as path from 'node:path';
+
+import {traverse} from '#node-utils';
+import {sortAlphabetically} from '#sort';
+
+export default ({
+  documentModes: {onePerFile},
+  thingConstructors: {StaticPage},
+}) => ({
+  title: `Process static page files`,
+
+  files: dataPath =>
+    traverse(path.join(dataPath, 'static-page'), {
+      filterFile: name => path.extname(name) === '.yaml',
+      prefixPath: 'static-page',
+    }),
+
+  documentMode: onePerFile,
+  documentThing: StaticPage,
+
+  sort({staticPageData}) {
+    sortAlphabetically(staticPageData);
+  },
+});
diff --git a/src/data/files/wiki-info.js b/src/data/files/wiki-info.js
new file mode 100644
index 00000000..a466ab0b
--- /dev/null
+++ b/src/data/files/wiki-info.js
@@ -0,0 +1,10 @@
+export default ({
+  documentModes: {oneDocumentTotal},
+  thingConstructors: {WikiInfo},
+}) => ({
+  title: `Process wiki info file`,
+  file: 'wiki-info.yaml',
+
+  documentMode: oneDocumentTotal,
+  documentThing: WikiInfo,
+});