repond-events
Version:
events for repond
111 lines (96 loc) • 3.9 kB
text/typescript
import { getState } from "repond";
import { repondEventsMeta } from "./meta";
import { ChainId, EvaluateParamsInfo, ParamMap, RawValue, ValueBlock, ValueRunInfo } from "./types";
function isValueBlock(value: any): value is ValueBlock {
return value && typeof value === "object" && value.type === "value" && "group" in value && "name" in value;
}
export function evaluateValue(
rawValue: RawValue | ValueBlock,
valueRunInfo: ValueRunInfo,
options: { isFast?: boolean } = {}
): RawValue | Promise<RawValue> {
if (typeof rawValue !== "object" || rawValue === null) {
return rawValue;
}
if (isValueBlock(rawValue)) {
return evaluateValueBlock(rawValue, valueRunInfo);
}
return rawValue;
}
function getValueRunInfoForParam(info: EvaluateParamsInfo, key: string): ValueRunInfo {
return {
addedBy: info.addedBy,
runBy: info.runBy,
parentChainId: info.parentChainId,
valueId: `${info.valueIdBase}.${key}`,
};
}
function getEvaluateParamsInfoFromValueRunInfo(valueRunInfo: ValueRunInfo): EvaluateParamsInfo {
return {
addedBy: valueRunInfo.addedBy,
runBy: valueRunInfo.runBy,
parentChainId: valueRunInfo.parentChainId,
valueIdBase: valueRunInfo.valueId,
};
}
/*
This is used in for EventBlock params, and ValueBlock params,
to evaluate the params and return a new object with the evaluated values.
it requires a valueIdBase to be passed in, which is the base of the valueId, (valueIdBase + paramName)
*/
export function evaluateParams(params: ParamMap, info: EvaluateParamsInfo): ParamMap | Promise<ParamMap> {
const paramEntries = Object.entries(params ?? {});
const evaluatedEntries = paramEntries.map(([key, value]) => {
const valueRunInfo = getValueRunInfoForParam(info, key);
const evaluatedValue = evaluateValue(value, valueRunInfo);
return [key, evaluatedValue];
});
const hasAsyncParam = evaluatedEntries.some(([, value]) => value instanceof Promise);
if (hasAsyncParam) {
return Promise.all(
evaluatedEntries.map(async ([key, value]) => {
const resolvedValue = await value;
return [key, resolvedValue];
})
).then((resolvedEntries) => {
return Object.fromEntries(resolvedEntries);
});
} else {
return Object.fromEntries(evaluatedEntries);
}
}
export function evaluateValueBlock(valueBlock: ValueBlock, valueRunInfo: ValueRunInfo): RawValue | Promise<RawValue> {
const valueDefinition = repondEventsMeta.allValueTypeGroups[valueBlock.group]?.[valueBlock.name];
if (!valueDefinition) {
throw new Error(`Value definition not found: ${valueBlock.group}.${valueBlock.name}`);
}
const paramsInfo = getEvaluateParamsInfoFromValueRunInfo(valueRunInfo);
const paramsWithDefaults = { ...valueDefinition.params, ...valueBlock.params };
const evaluatedParamsOrPromise = evaluateParams(paramsWithDefaults, paramsInfo);
// NOTE this won't be possible anymore, since there's no async values
if (evaluatedParamsOrPromise instanceof Promise) {
return evaluatedParamsOrPromise.then((evaluatedParams) => {
const result = valueDefinition.run(evaluatedParams, valueRunInfo, valueBlock);
return result;
});
} else {
const result = valueDefinition.run(evaluatedParamsOrPromise, valueRunInfo, valueBlock);
return result;
}
}
// Search up chains until it finds one that's in the resolveValueMap
// For non fast mode
export function resolveNearestGetEventValue(initialChainId: ChainId, value: any) {
let chainId: string | null = initialChainId;
let didResolve = false;
while (chainId) {
const chainState = getState("chains", chainId);
if (chainState && chainId in repondEventsMeta.resolveValueMap) {
repondEventsMeta.resolveValueMap[chainId]?.(value);
didResolve = true;
break;
}
chainId = chainState ? chainState.parentChainId : null;
}
return didResolve ? chainId : null;
}