« 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/composite/control-flow
diff options
context:
space:
mode:
Diffstat (limited to 'src/data/composite/control-flow')
-rw-r--r--src/data/composite/control-flow/exposeWhetherDependencyAvailable.js42
-rw-r--r--src/data/composite/control-flow/flipFilter.js36
-rw-r--r--src/data/composite/control-flow/helpers/performAvailabilityCheck.js19
-rw-r--r--src/data/composite/control-flow/index.js3
-rw-r--r--src/data/composite/control-flow/raiseOutputWithoutDependency.js2
-rw-r--r--src/data/composite/control-flow/raiseOutputWithoutUpdateValue.js2
-rw-r--r--src/data/composite/control-flow/withAvailabilityFilter.js41
-rw-r--r--src/data/composite/control-flow/withResultOfAvailabilityCheck.js33
8 files changed, 151 insertions, 27 deletions
diff --git a/src/data/composite/control-flow/exposeWhetherDependencyAvailable.js b/src/data/composite/control-flow/exposeWhetherDependencyAvailable.js
new file mode 100644
index 00000000..a2fdd6b0
--- /dev/null
+++ b/src/data/composite/control-flow/exposeWhetherDependencyAvailable.js
@@ -0,0 +1,42 @@
+// Exposes true if a dependency is available, and false otherwise,
+// or the reverse if the `negate` input is set true.
+//
+// See withResultOfAvailabilityCheck for {mode} options.
+
+import {input, templateCompositeFrom} from '#composite';
+
+import inputAvailabilityCheckMode from './inputAvailabilityCheckMode.js';
+import withResultOfAvailabilityCheck from './withResultOfAvailabilityCheck.js';
+
+export default templateCompositeFrom({
+  annotation: `exposeWhetherDependencyAvailable`,
+
+  compose: false,
+
+  inputs: {
+    dependency: input({acceptsNull: true}),
+
+    mode: inputAvailabilityCheckMode(),
+
+    negate: input({type: 'boolean', defaultValue: false}),
+  },
+
+  steps: () => [
+    withResultOfAvailabilityCheck({
+      from: input('dependency'),
+      mode: input('mode'),
+    }),
+
+    {
+      dependencies: ['#availability', input('negate')],
+
+      compute: ({
+        ['#availability']: availability,
+        [input('negate')]: negate,
+      }) =>
+        (negate
+          ? !availability
+          : availability),
+    },
+  ],
+});
diff --git a/src/data/composite/control-flow/flipFilter.js b/src/data/composite/control-flow/flipFilter.js
new file mode 100644
index 00000000..995bacad
--- /dev/null
+++ b/src/data/composite/control-flow/flipFilter.js
@@ -0,0 +1,36 @@
+// Flips a filter, so that each true item becomes false, and vice versa.
+// Overwrites the provided dependency.
+//
+// See also:
+//  - withAvailabilityFilter
+
+import {input, templateCompositeFrom} from '#composite';
+
+export default templateCompositeFrom({
+  annotation: `flipFilter`,
+
+  inputs: {
+    filter: input({type: 'array'}),
+  },
+
+  outputs: ({
+    [input.staticDependency('filter')]: filterDependency,
+  }) => [filterDependency ?? '#flippedFilter'],
+
+  steps: () => [
+    {
+      dependencies: [
+        input('filter'),
+        input.staticDependency('filter'),
+      ],
+
+      compute: (continuation, {
+        [input('filter')]: filter,
+        [input.staticDependency('filter')]: filterDependency,
+      }) => continuation({
+        [filterDependency ?? '#flippedFilter']:
+          filter.map(item => !item),
+      }),
+    },
+  ],
+});
diff --git a/src/data/composite/control-flow/helpers/performAvailabilityCheck.js b/src/data/composite/control-flow/helpers/performAvailabilityCheck.js
new file mode 100644
index 00000000..0e44ab59
--- /dev/null
+++ b/src/data/composite/control-flow/helpers/performAvailabilityCheck.js
@@ -0,0 +1,19 @@
+import {empty} from '#sugar';
+
+export default function performAvailabilityCheck(value, mode) {
+  switch (mode) {
+    case 'null':
+      return value !== undefined && value !== null;
+
+    case 'empty':
+      return value !== undefined && !empty(value);
+
+    case 'falsy':
+      return !!value && (!Array.isArray(value) || !empty(value));
+
+    case 'index':
+      return typeof value === 'number' && value >= 0;
+  }
+
+  return undefined;
+}
diff --git a/src/data/composite/control-flow/index.js b/src/data/composite/control-flow/index.js
index 7fad88b2..778dc66b 100644
--- a/src/data/composite/control-flow/index.js
+++ b/src/data/composite/control-flow/index.js
@@ -9,6 +9,9 @@ export {default as exposeConstant} from './exposeConstant.js';
 export {default as exposeDependency} from './exposeDependency.js';
 export {default as exposeDependencyOrContinue} from './exposeDependencyOrContinue.js';
 export {default as exposeUpdateValueOrContinue} from './exposeUpdateValueOrContinue.js';
+export {default as exposeWhetherDependencyAvailable} from './exposeWhetherDependencyAvailable.js';
+export {default as flipFilter} from './flipFilter.js';
 export {default as raiseOutputWithoutDependency} from './raiseOutputWithoutDependency.js';
 export {default as raiseOutputWithoutUpdateValue} from './raiseOutputWithoutUpdateValue.js';
+export {default as withAvailabilityFilter} from './withAvailabilityFilter.js';
 export {default as withResultOfAvailabilityCheck} from './withResultOfAvailabilityCheck.js';
diff --git a/src/data/composite/control-flow/raiseOutputWithoutDependency.js b/src/data/composite/control-flow/raiseOutputWithoutDependency.js
index 3d04f8a9..03d8036a 100644
--- a/src/data/composite/control-flow/raiseOutputWithoutDependency.js
+++ b/src/data/composite/control-flow/raiseOutputWithoutDependency.js
@@ -17,7 +17,7 @@ export default templateCompositeFrom({
 
   outputs: ({
     [input.staticValue('output')]: output,
-  }) => Object.keys(output ?? {}),
+  }) => Object.keys(output),
 
   steps: () => [
     withResultOfAvailabilityCheck({
diff --git a/src/data/composite/control-flow/raiseOutputWithoutUpdateValue.js b/src/data/composite/control-flow/raiseOutputWithoutUpdateValue.js
index ffa83a94..3c39f5ba 100644
--- a/src/data/composite/control-flow/raiseOutputWithoutUpdateValue.js
+++ b/src/data/composite/control-flow/raiseOutputWithoutUpdateValue.js
@@ -16,7 +16,7 @@ export default templateCompositeFrom({
 
   outputs: ({
     [input.staticValue('output')]: output,
-  }) => Object.keys(output ?? {}),
+  }) => Object.keys(output),
 
   steps: () => [
     withResultOfAvailabilityCheck({
diff --git a/src/data/composite/control-flow/withAvailabilityFilter.js b/src/data/composite/control-flow/withAvailabilityFilter.js
new file mode 100644
index 00000000..fd93af71
--- /dev/null
+++ b/src/data/composite/control-flow/withAvailabilityFilter.js
@@ -0,0 +1,41 @@
+// Performs the same availability check across all items of a list, providing
+// a list that's suitable anywhere a filter is expected.
+//
+// Accepts the same mode options as withResultOfAvailabilityCheck.
+//
+// See also:
+//  - flipFilter
+//  - withFilteredList
+//  - withResultOfAvailabilityCheck
+//
+
+import {input, templateCompositeFrom} from '#composite';
+
+import inputAvailabilityCheckMode from './inputAvailabilityCheckMode.js';
+
+import performAvailabilityCheck from './helpers/performAvailabilityCheck.js';
+
+export default templateCompositeFrom({
+  annotation: `withAvailabilityFilter`,
+
+  inputs: {
+    from: input({type: 'array'}),
+    mode: inputAvailabilityCheckMode(),
+  },
+
+  outputs: ['#availabilityFilter'],
+
+  steps: () => [
+    {
+      dependencies: [input('from'), input('mode')],
+      compute: (continuation, {
+        [input('from')]: list,
+        [input('mode')]: mode,
+      }) => continuation({
+        ['#availabilityFilter']:
+          list.map(value =>
+            performAvailabilityCheck(value, mode)),
+      }),
+    },
+  ],
+});
diff --git a/src/data/composite/control-flow/withResultOfAvailabilityCheck.js b/src/data/composite/control-flow/withResultOfAvailabilityCheck.js
index a6942014..c5221a62 100644
--- a/src/data/composite/control-flow/withResultOfAvailabilityCheck.js
+++ b/src/data/composite/control-flow/withResultOfAvailabilityCheck.js
@@ -17,15 +17,18 @@
 //  - exitWithoutUpdateValue
 //  - exposeDependencyOrContinue
 //  - exposeUpdateValueOrContinue
+//  - exposeWhetherDependencyAvailable
 //  - raiseOutputWithoutDependency
 //  - raiseOutputWithoutUpdateValue
+//  - withAvailabilityFilter
 //
 
 import {input, templateCompositeFrom} from '#composite';
-import {empty} from '#sugar';
 
 import inputAvailabilityCheckMode from './inputAvailabilityCheckMode.js';
 
+import performAvailabilityCheck from './helpers/performAvailabilityCheck.js';
+
 export default templateCompositeFrom({
   annotation: `withResultOfAvailabilityCheck`,
 
@@ -39,33 +42,13 @@ export default templateCompositeFrom({
   steps: () => [
     {
       dependencies: [input('from'), input('mode')],
-
       compute: (continuation, {
         [input('from')]: value,
         [input('mode')]: mode,
-      }) => {
-        let availability;
-
-        switch (mode) {
-          case 'null':
-            availability = value !== undefined && value !== null;
-            break;
-
-          case 'empty':
-            availability = value !== undefined && !empty(value);
-            break;
-
-          case 'falsy':
-            availability = !!value && (!Array.isArray(value) || !empty(value));
-            break;
-
-          case 'index':
-            availability = typeof value === 'number' && value >= 0;
-            break;
-        }
-
-        return continuation({'#availability': availability});
-      },
+      }) => continuation({
+        ['#availability']:
+          performAvailabilityCheck(value, mode),
+      }),
     },
   ],
 });