diff options
-rw-r--r-- | src/data/things/composite.js | 32 | ||||
-rw-r--r-- | src/util/sugar.js | 10 |
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 |