///
/**
* Integration test pattern for when/unless operators.
*
* This pattern tests the transformation of && and || operators to when() and unless()
* built-in functions. The transformer converts:
* - `complexExpr && value` → `when(derive(complexExpr), value)`
* - `complexExpr || fallback` → `unless(derive(complexExpr), fallback)`
*
* Simple opaque refs (like `showPanel && value`) don't use when/unless,
* only complex expressions that need derivation.
*/
import { type Cell, Default, handler, lift, recipe, str } from "commontools";
interface WhenUnlessArgs {
items: Default;
showPanel: Default;
userName: Default;
count: Default;
}
const togglePanel = handler(
(_event: unknown, context: { showPanel: Cell }) => {
const current = context.showPanel.get() ?? false;
context.showPanel.set(!current);
},
);
const setUserName = handler(
(
event: { name: string } | undefined,
context: { userName: Cell },
) => {
context.userName.set(event?.name ?? "");
},
);
const addItem = handler(
(event: { item: string } | undefined, context: { items: Cell }) => {
const current = context.items.get() ?? [];
const item = event?.item ?? "item";
context.items.set([...current, item]);
},
);
const clearItems = handler(
(_event: unknown, context: { items: Cell }) => {
context.items.set([]);
},
);
const incrementCount = handler(
(
event: { amount?: number } | undefined,
context: { count: Cell },
) => {
const amount = typeof event?.amount === "number" ? event.amount : 1;
const current = context.count.get() ?? 0;
context.count.set(current + amount);
},
);
export const counterWithWhenUnlessOperators = recipe(
"Counter With When Unless Operators",
({ items, showPanel, userName, count }) => {
// Test 1: && with complex expression (items.length > 0)
// This should transform to: when(derive(...items.length > 0...), "has items")
const hasItemsMessage = lift(
(state: { itemCount: number }) => state.itemCount > 0 && "has items",
)({ itemCount: items.length });
// Test 2: || with complex expression (items.length)
// This should transform to: unless(derive(...items.length...), "no items")
const itemsOrDefault = lift(
(state: { itemCount: number }) => state.itemCount || "no items",
)({ itemCount: items.length });
// Test 3: && with derived boolean condition
// count > 5 && "high count"
const highCountMessage = lift(
(state: { count: number }) => state.count > 5 && "high count",
)({ count });
// Test 4: || for fallback with derived string
// userName || "Anonymous"
const displayName = lift(
(state: { name: string }) => state.name || "Anonymous",
)({ name: userName });
// Test 5: Chained && and || (a && b || c pattern)
// (items.length > 0 && userName) || "Guest with no items"
const userWithItems = lift(
(state: { hasItems: boolean; name: string }) =>
(state.hasItems && state.name) || "Guest with no items",
)({
hasItems: lift((len: number) => len > 0)(items.length),
name: userName,
});
// Test 6: Multiple && (a && b && c pattern)
// showPanel && items.length > 0 && "panel with items"
const panelWithItems = lift(
(state: { show: boolean; hasItems: boolean }) =>
state.show && state.hasItems && "panel with items",
)({
show: showPanel,
hasItems: lift((len: number) => len > 0)(items.length),
});
// Test 7: Multiple || (a || b || c pattern)
// userName || items[0] || "default"
const firstOption = lift(
(state: { name: string; firstItem: string | undefined }) =>
state.name || state.firstItem || "default",
)({
name: userName,
firstItem: lift((arr: string[]) => arr[0])(items),
});
// Derived values for assertions
const itemCount = lift((arr: string[]) => arr.length)(items);
const safeCount = lift((n: number | undefined) =>
typeof n === "number" ? n : 0
)(count);
// Summary label combining multiple results
const summary =
str`items=${itemCount} show=${showPanel} user=${displayName} count=${safeCount}`;
return {
// Input state
items,
showPanel,
userName,
count,
// Derived counts
itemCount,
safeCount,
// Test results - these exercise when/unless at runtime
hasItemsMessage,
itemsOrDefault,
highCountMessage,
displayName,
userWithItems,
panelWithItems,
firstOption,
// Summary
summary,
// Handlers for state manipulation
togglePanel: togglePanel({ showPanel }),
setUserName: setUserName({ userName }),
addItem: addItem({ items }),
clearItems: clearItems({ items }),
incrementCount: incrementCount({ count }),
};
},
);