diff options
Diffstat (limited to 'src/data/composite.js')
-rw-r--r-- | src/data/composite.js | 175 |
1 files changed, 168 insertions, 7 deletions
diff --git a/src/data/composite.js b/src/data/composite.js index 33d69a68..ea7a3480 100644 --- a/src/data/composite.js +++ b/src/data/composite.js @@ -758,6 +758,9 @@ export function compositeFrom(description) { anyStepsUseUpdateValue || anyStepsUpdate; + const stepsFirstTimeCalling = + Array.from({length: steps.length}).fill(true); + const stepEntries = stitchArrays({ step: steps, stepComposes: stepsCompose, @@ -977,8 +980,16 @@ export function compositeFrom(description) { (expectingTransform ? {[input.updateValue()]: valueSoFar} : {}), - [input.myself()]: initialDependencies?.['this'] ?? null, - [input.thisProperty()]: initialDependencies?.['thisProperty'] ?? null, + + [input.myself()]: + (initialDependencies && Object.hasOwn(initialDependencies, 'this') + ? initialDependencies.this + : null), + + [input.thisProperty()]: + (initialDependencies && Object.hasOwn(initialDependencies, 'thisProperty') + ? initialDependencies.thisProperty + : null), }; const selectDependencies = @@ -1028,7 +1039,123 @@ export function compositeFrom(description) { const naturalEvaluate = () => { const [name, ...argsLayout] = getExpectedEvaluation(); - let args; + let args = argsLayout; + + let effectiveDependencies; + let reviewAccessedDependencies; + + if (stepsFirstTimeCalling[i]) { + const expressedDependencies = + selectDependencies; + + const remainingDependencies = + new Set(expressedDependencies); + + const unavailableDependencies = []; + const accessedDependencies = []; + + effectiveDependencies = + new Proxy(filteredDependencies, { + get(target, key) { + accessedDependencies.push(key); + remainingDependencies.delete(key); + + const value = target[key]; + + if (value === undefined) { + unavailableDependencies.push(key); + } + + return value; + }, + }); + + reviewAccessedDependencies = () => { + const topAggregate = + openAggregate({ + message: `Errors in accessed dependencies`, + }); + + const showDependency = dependency => + (isInputToken(dependency) + ? getInputTokenShape(dependency) + + `(` + + inspect(getInputTokenValue(dependency), {compact: true}) + + ')' + : dependency.toString()); + + let anyErrors = false; + + for (const dependency of remainingDependencies) { + topAggregate.push(new Error( + `Expected to access ${showDependency(dependency)}`)); + + anyErrors = true; + } + + for (const dependency of unavailableDependencies) { + const subAggregate = + openAggregate({ + message: + `Accessed ${showDependency(dependency)}, which is unavailable`, + }); + + let reason = false; + + if (!expressedDependencies.includes(dependency)) { + subAggregate.push(new Error( + `Missing from step's expressed dependencies`)); + reason = true; + } + + if (filterableDependencies[dependency] === undefined) { + subAggregate.push( + new Error( + `Not available` + + (isInputToken(dependency) + ? ` in input()-type dependencies` + : dependency.startsWith('#') + ? ` in local dependencies` + : ` on object dependencies`))); + reason = true; + } + + if (!reason) { + subAggregate.push(new Error( + `Not sure why this is unavailable, sorry!`)); + } + + topAggregate.call(subAggregate.close); + + anyErrors = true; + } + + if (anyErrors) { + topAggregate.push(new Error( + `These dependencies, in total, were accessed:` + + (empty(accessedDependencies) + ? ` (none)` + : accessedDependencies.length === 1 + ? showDependency(accessedDependencies[0]) + : `\n` + + accessedDependencies + .map(showDependency) + .map(line => ` - ${line}`) + .join('\n')))); + } + + topAggregate.close(); + }; + } else { + effectiveDependencies = filteredDependencies; + reviewAccessedDependencies = null; + } + + args = + args.map(arg => + (arg === filteredDependencies + ? effectiveDependencies + : arg)); if (stepComposes) { let continuation; @@ -1037,17 +1164,50 @@ export function compositeFrom(description) { _prepareContinuation(callingTransformForThisStep)); args = - argsLayout.map(arg => + args.map(arg => (arg === continuationSymbol ? continuation : arg)); } else { args = - argsLayout.filter(arg => arg !== continuationSymbol); + args.filter(arg => arg !== continuationSymbol); } - return expose[name](...args); - } + let stepError; + try { + return expose[name](...args); + } catch (error) { + stepError = error; + } finally { + stepsFirstTimeCalling[i] = false; + + let reviewError; + if (reviewAccessedDependencies) { + try { + reviewAccessedDependencies(); + } catch (error) { + reviewError = error; + } + } + + const stepPart = + `step ${i+1}` + + (isBase + ? ` (base)` + : ` of ${steps.length}`) + + (step.annotation ? `, ${step.annotation}` : ``); + + if (stepError && reviewError) { + throw new AggregateError( + [stepError, reviewError], + `Errors in ${stepPart}`); + } else if (stepError || reviewError) { + throw new Error( + `Error in ${stepPart}`, + {cause: stepError || reviewError}); + } + } + }; switch (step.cache) { // Warning! Highly WIP! @@ -1223,6 +1383,7 @@ export function compositeFrom(description) { `Error computing composition` + (annotation ? ` ${annotation}` : '')); error.cause = thrownError; + error[Symbol.for('hsmusic.aggregate.translucent')] = true; throw error; } }; |