« 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.js32
-rw-r--r--src/util/sugar.js10
2 files changed, 29 insertions, 13 deletions
diff --git a/src/data/things/composite.js b/src/data/things/composite.js
index de6827c6..33f49e9b 100644
--- a/src/data/things/composite.js
+++ b/src/data/things/composite.js
@@ -16,6 +16,7 @@ import {
   filterProperties,
   openAggregate,
   stitchArrays,
+  typeAppearance,
   unique,
   withAggregate,
 } from '#sugar';
@@ -381,7 +382,9 @@ input.staticDependency = _valueIntoToken('input.staticDependency');
 input.staticValue = _valueIntoToken('input.staticValue');
 
 function isInputToken(token) {
-  if (typeof token === 'object') {
+  if (token === null) {
+    return false;
+  } else if (typeof token === 'object') {
     return token.symbol === Symbol.for('hsmusic.composite.input');
   } else if (typeof token === 'symbol') {
     return token.description.startsWith('hsmusic.composite.input');
@@ -653,26 +656,29 @@ export function templateCompositeFrom(description) {
         push(new Error(`Required these inputs: ${missingInputNames.join(', ')}`));
       }
 
-      if (!empty(expectedStaticDependencyInputNames)) {
-        push(new Error(`Expected static dependencies: ${expectedStaticDependencyInputNames.join(', ')}`));
+      const inputAppearance = name =>
+        (isInputToken(inputOptions[name])
+          ? `${getInputTokenShape(inputOptions[name])}() call`
+          : `dependency name`);
+
+      for (const name of expectedStaticDependencyInputNames) {
+        const appearance = inputAppearance(name);
+        push(new Error(`${name}: Expected dependency name, got ${appearance}`));
       }
 
-      if (!empty(expectedStaticValueInputNames)) {
-        push(new Error(`Expected static values: ${expectedStaticValueInputNames.join(', ')}`));
+      for (const name of expectedStaticValueInputNames) {
+        const appearance = inputAppearance(name)
+        push(new Error(`${name}: Expected input.value() call, got ${appearance}`));
       }
 
       for (const name of expectedValueProvidingTokenInputNames) {
-        const shapeOrType =
-          (isInputToken(inputOptions[name])
-            ? getInputTokenShape(inputOptions[name])
-            : typeof inputOptions[name]);
-
-        push(new Error(`${name}: Expected dependency name or value-providing input() call, got ${shapeOrType}`));
+        const appearance = getInputTokenShape(inputOptions[name]);
+        push(new Error(`${name}: Expected dependency name or value-providing input() call, got ${appearance}`));
       }
 
       for (const name of wrongTypeInputNames) {
-        const type = typeof inputOptions[name];
-        push(new Error(`${name}: Expected string or input() call, got ${type}`));
+        const type = typeAppearance(inputOptions[name]);
+        push(new Error(`${name}: Expected dependency name or input() call, got ${type}`));
       }
 
       for (const error of validateFailedErrors) {
diff --git a/src/util/sugar.js b/src/util/sugar.js
index 24d409fb..ef6ab18c 100644
--- a/src/util/sugar.js
+++ b/src/util/sugar.js
@@ -230,6 +230,16 @@ export function escapeRegex(string) {
   return string.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
 }
 
+// Gets the "look" of some arbitrary value. It's like typeof, but smarter.
+// Don't use this for actually validating types - it's only suitable for
+// inclusion in error messages.
+export function typeAppearance(value) {
+  if (value === null) return 'null';
+  if (value === undefined) return 'undefined';
+  if (Array.isArray(value)) return 'array';
+  return typeof value;
+}
+
 // Binds default values for arguments in a {key: value} type function argument
 // (typically the second argument, but may be overridden by providing a
 // [bindOpts.bindIndex] argument). Typically useful for preparing a function for