« 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/composite.js75
1 files changed, 75 insertions, 0 deletions
diff --git a/src/data/things/composite.js b/src/data/things/composite.js
index 96abf4af..1f6482f6 100644
--- a/src/data/things/composite.js
+++ b/src/data/things/composite.js
@@ -1072,6 +1072,8 @@ export function raiseWithoutUpdateValue({
   ]);
 }
 
+// Turns an updating property's update value into a dependency, so it can be
+// conveniently passed to other functions.
 export function withUpdateValueAsDependency({
   into = '#updateValue',
 } = {}) {
@@ -1086,3 +1088,76 @@ export function withUpdateValueAsDependency({
     },
   };
 }
+
+// Flattens an array with one level of nested arrays, providing as dependencies
+// both the flattened array as well as the original starting indices of each
+// successive source array.
+export function withFlattenedArray({
+  from,
+  into = '#flattenedArray',
+  intoIndices = '#flattenedIndices',
+}) {
+  return {
+    annotation: `withFlattenedArray`,
+    flags: {expose: true, compose: true},
+
+    expose: {
+      mapDependencies: {from},
+      mapContinuation: {into, intoIndices},
+
+      compute({from: sourceArray}, continuation) {
+        const into = sourceArray.flat();
+        const intoIndices = [];
+
+        let lastEndIndex = 0;
+        for (const {length} of sourceArray) {
+          intoIndices.push(lastEndIndex);
+          lastEndIndex += length;
+        }
+
+        return continuation({into, intoIndices});
+      },
+    },
+  };
+}
+
+// After mapping the contents of a flattened array in-place (being careful to
+// retain the original indices by replacing unmatched results with null instead
+// of filtering them out), this function allows for recombining them. It will
+// filter out null and undefined items by default (pass {filter: false} to
+// disable this).
+export function withUnflattenedArray({
+  from,
+  fromIndices = '#flattenedIndices',
+  into = '#unflattenedArray',
+  filter = true,
+}) {
+  return {
+    annotation: `withUnflattenedArray`,
+    flags: {expose: true, compose: true},
+
+    expose: {
+      mapDependencies: {from, fromIndices},
+      mapContinuation: {into},
+      compute({from, fromIndices}, continuation) {
+        const arrays = [];
+
+        for (let i = 0; i < fromIndices.length; i++) {
+          const startIndex = fromIndices[i];
+          const endIndex =
+            (i === fromIndices.length - 1
+              ? from.length
+              : fromIndices[i + 1]);
+
+          const values = from.slice(startIndex, endIndex);
+          arrays.push(
+            (filter
+              ? values.filter(value => value !== null && value !== undefined)
+              : values));
+        }
+
+        return continuation({into: arrays});
+      },
+    },
+  };
+}