/// import { Cell, cell, Default, derive, handler, lift, recipe, str, } from "commontools"; interface NoOpCounterArgs { value: Default; } interface IncrementEvent { amount?: number; } const applyIncrement = handler( ( event: IncrementEvent | undefined, context: { value: Cell; updates: Cell; lastEvent: Cell; }, ) => { const amount = event?.amount; if (typeof amount !== "number" || !Number.isFinite(amount)) { return; } const currentRaw = context.value.get(); const currentValue = typeof currentRaw === "number" && Number.isFinite(currentRaw) ? currentRaw : 0; const next = currentValue + amount; context.value.set(next); const updateRaw = context.updates.get(); const applied = typeof updateRaw === "number" && Number.isFinite(updateRaw) ? updateRaw + 1 : 1; context.updates.set(applied); context.lastEvent.set(`applied ${amount}`); }, ); export const counterNoOpEvents = recipe( "Counter No-Op Events", ({ value }) => { const updates = cell(0); const lastEvent = cell("none"); const currentValue = lift((input: number | undefined) => typeof input === "number" && Number.isFinite(input) ? input : 0 )(value); const updateCount = lift((count: number | undefined) => typeof count === "number" && Number.isFinite(count) ? count : 0 )(updates); const lastEventView = lift((label: string | undefined) => typeof label === "string" && label.length > 0 ? label : "none" )(lastEvent); const hasChanges = derive(updateCount, (count) => count > 0); const status = derive( hasChanges, (changed) => (changed ? "changed" : "no changes"), ); const label = str`Counter value ${currentValue} (${status})`; return { value, currentValue, updateCount, hasChanges, status, label, lastEvent: lastEventView, increment: applyIncrement({ value, updates, lastEvent }), }; }, );