« 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/data/things/index.js2
-rw-r--r--src/data/things/sorting-rule.js139
-rwxr-xr-xsrc/upd8.js1
3 files changed, 142 insertions, 0 deletions
diff --git a/src/data/things/index.js b/src/data/things/index.js
index 9f033c23..309d0803 100644
--- a/src/data/things/index.js
+++ b/src/data/things/index.js
@@ -17,6 +17,7 @@ import * as groupClasses from './group.js';
 import * as homepageLayoutClasses from './homepage-layout.js';
 import * as languageClasses from './language.js';
 import * as newsEntryClasses from './news-entry.js';
+import * as sortingRuleClasses from './sorting-rule.js';
 import * as staticPageClasses from './static-page.js';
 import * as trackClasses from './track.js';
 import * as wikiInfoClasses from './wiki-info.js';
@@ -31,6 +32,7 @@ const allClassLists = {
   'homepage-layout.js': homepageLayoutClasses,
   'language.js': languageClasses,
   'news-entry.js': newsEntryClasses,
+  'sorting-rule.js': sortingRuleClasses,
   'static-page.js': staticPageClasses,
   'track.js': trackClasses,
   'wiki-info.js': wikiInfoClasses,
diff --git a/src/data/things/sorting-rule.js b/src/data/things/sorting-rule.js
new file mode 100644
index 00000000..88f37719
--- /dev/null
+++ b/src/data/things/sorting-rule.js
@@ -0,0 +1,139 @@
+export const SORTING_RULE_DATA_FILE = 'sorting-rules.yaml';
+
+import {input} from '#composite';
+import Thing from '#thing';
+import {isStringNonEmpty, strictArrayOf} from '#validators';
+import {documentModes} from '#yaml';
+
+import {
+  compareCaseLessSensitive,
+  sortByDate,
+  sortByDirectory,
+  sortByName,
+} from '#sort';
+
+import {flag} from '#composite/wiki-properties';
+
+export class SortingRule extends Thing {
+  static [Thing.friendlyName] = `Sorting Rule`;
+
+  static [Thing.getPropertyDescriptors] = () => ({
+    // Update & expose
+
+    active: flag(true),
+  });
+
+  static [Thing.yamlDocumentSpec] = {
+    fields: {
+      'Active': {property: 'active'},
+    },
+  };
+
+  static [Thing.getYamlLoadingSpec] = ({
+    documentModes: {allInOne},
+    thingConstructors: {DocumentSortingRule},
+  }) => ({
+    title: `Process sorting rules file`,
+    file: SORTING_RULE_DATA_FILE,
+
+    documentMode: allInOne,
+    documentThing: document =>
+      (document['Sort Documents']
+        ? DocumentSortingRule
+        : null),
+
+    save: (results) => ({sortingRules: results}),
+  });
+}
+
+export class DocumentSortingRule extends SortingRule {
+  static [Thing.getPropertyDescriptors] = () => ({
+    // Update & expose
+
+    // TODO: glob :plead:
+    filename: {
+      flags: {update: true, expose: true},
+      update: {
+        validate: isStringNonEmpty,
+      },
+    },
+
+    properties: {
+      flags: {update: true, expose: true},
+      update: {
+        validate: strictArrayOf(isStringNonEmpty),
+      },
+    },
+  });
+
+  static [Thing.yamlDocumentSpec] = Thing.extendDocumentSpec(SortingRule, {
+    fields: {
+      'Sort Documents': {property: 'filename'},
+      'By Properties': {property: 'properties'},
+    },
+  });
+
+  apply(layout) {
+    const fresh = {...layout};
+
+    let sortable = null;
+    switch (fresh.documentMode) {
+      case documentModes.headerAndEntries:
+        sortable = fresh.entryThings =
+          fresh.entryThings.slice();
+        break;
+
+      case documentModes.allInOne:
+        sortable = fresh.things =
+          fresh.things.slice();
+        break;
+
+      default:
+        throw new Error(`Invalid document type for sorting`);
+    }
+
+    if (this.properties) {
+      for (const property of this.properties.slice().reverse()) {
+        const get = thing => thing[property];
+        const lc = property.toLowerCase();
+
+        if (lc.endsWith('date')) {
+          sortByDate(sortable, {getDate: get});
+          continue;
+        }
+
+        if (lc.endsWith('directory')) {
+          sortByDirectory(sortable, {getDirectory: get});
+          continue;
+        }
+
+        if (lc.endsWith('name')) {
+          sortByName(sortable, {getName: get});
+          continue;
+        }
+
+        const values = sortable.map(get);
+
+        if (values.every(v => typeof v === 'string')) {
+          sortable.sort((a, b) =>
+            compareCaseLessSensitive(get(a), get(b)));
+          continue;
+        }
+
+        if (values.every(v => typeof v === 'number')) {
+          sortable.sort((a, b) => get(a) - get(b));
+          continue;
+        }
+
+        sortable.sort((a, b) =>
+          (get(a).toString() < get(b).toString()
+            ? -1
+         : get(a).toString() > get(b).toString()
+            ? +1
+            :  0));
+      }
+    }
+
+    return fresh;
+  }
+}
diff --git a/src/upd8.js b/src/upd8.js
index 93f09122..a3840424 100755
--- a/src/upd8.js
+++ b/src/upd8.js
@@ -1510,6 +1510,7 @@ async function main() {
         logThings('newsData', 'news entries');
       }
       logThings('staticPageData', 'static pages');
+      logThings('sortingRules', 'sorting rules');
       if (wikiData.homepageLayout) {
         logInfo` - ${1} homepage layout (${
           wikiData.homepageLayout.sections.length