///
import {
type Cell,
cell,
Default,
derive,
handler,
lift,
recipe,
str,
} from "commontools";
interface NestedHandlerArgs {
value: Default;
history: Default;
}
type StageEntry = {
base: number;
multiplier: number;
delta: number;
tag: string;
};
type PreparedSnapshot = {
delta: number;
tag: string;
};
type PipelineHistoryEntry = {
value: number;
delta: number;
tag: string;
};
interface StageContext {
stage: Cell;
preparedCount: Cell;
lastPrepared: Cell;
}
const updateStage = (
event: { amount?: number; multiplier?: number; tag?: string } | undefined,
context: StageContext,
) => {
const base = typeof event?.amount === "number" ? event.amount : 0;
const multiplier = typeof event?.multiplier === "number"
? event.multiplier
: 1;
const safeMultiplier = Number.isFinite(multiplier) ? multiplier : 1;
const safeBase = Number.isFinite(base) ? base : 0;
const tag = typeof event?.tag === "string" && event.tag.length > 0
? event.tag
: "pipeline";
const delta = safeBase * safeMultiplier;
context.stage.set({
base: safeBase,
multiplier: safeMultiplier,
delta,
tag,
});
const preparedSoFar = context.preparedCount.get() ?? 0;
context.preparedCount.set(preparedSoFar + 1);
context.lastPrepared.set({ delta, tag });
};
const applyStagedAdjustment = handler(
(
_event: unknown,
context: {
value: Cell;
history: Cell;
stage: Cell;
appliedCount: Cell;
},
) => {
applyStageEntry(context);
},
);
const applyStageEntry = (
context: {
value: Cell;
history: Cell;
stage: Cell;
appliedCount: Cell;
},
) => {
const staged = context.stage.get();
if (!staged) return;
const currentValue = context.value.get() ?? 0;
const nextValue = currentValue + staged.delta;
context.value.set(nextValue);
const existingHistory = context.history.get();
const history = Array.isArray(existingHistory) ? existingHistory.slice() : [];
history.push({
value: nextValue,
delta: staged.delta,
tag: staged.tag,
});
context.history.set(history);
const appliedSoFar = context.appliedCount.get() ?? 0;
context.appliedCount.set(appliedSoFar + 1);
context.stage.set(undefined);
};
const stageOnly = handler(
(
event: { amount?: number; multiplier?: number; tag?: string } | undefined,
context: StageContext,
) => {
updateStage(event, context);
},
);
const composeAndApply = handler(
(
event: { amount?: number; multiplier?: number; tag?: string } | undefined,
context: StageContext & {
value: Cell;
history: Cell;
stage: Cell;
appliedCount: Cell;
},
) => {
updateStage(event, context);
applyStageEntry(context);
},
);
/** Pattern composing nested handlers to simulate staged pipelines. */
export const counterWithNestedHandlerComposition = recipe(
"Counter With Nested Handler Composition",
({ value, history }) => {
const stage = cell(undefined);
const preparedCount = cell(0);
const appliedCount = cell(0);
const lastPrepared = cell({
delta: 0,
tag: "pipeline",
});
const commit = applyStagedAdjustment({
value,
history,
stage,
appliedCount,
});
const stageHandler = stageOnly({
stage,
preparedCount,
lastPrepared,
});
const process = composeAndApply({
stage,
preparedCount,
lastPrepared,
value,
history,
appliedCount,
});
const preparedView = lift((count: number | undefined) => count ?? 0)(
preparedCount,
);
const appliedView = lift((count: number | undefined) => count ?? 0)(
appliedCount,
);
const historyView = lift((entries: PipelineHistoryEntry[] | undefined) =>
Array.isArray(entries) ? entries : []
)(history);
const lastPreparedView = lift(
(entry: PreparedSnapshot | undefined) =>
entry ?? { delta: 0, tag: "pipeline" },
)(lastPrepared);
const stageStatus = derive(
stage,
(current) => current.get() ? `staged:${current.get()!.tag}` : "idle",
);
const label = str`${preparedView} prepared, ${appliedView} applied`;
return {
value,
history: historyView,
stats: {
prepared: preparedView,
applied: appliedView,
},
lastPrepared: lastPreparedView,
stageStatus,
label,
pipeline: {
stage: stageHandler,
commit,
process,
},
};
},
);