import { assert, assertEquals, assertStringIncludes } from "@std/assert"; import { COMMONFABRIC_TYPES } from "./commonfabric-test-types.ts"; import { transformSource } from "./utils.ts"; Deno.test( "Transform guards: nested block shadowing does not leak opaque alias roots", async () => { const source = `import { pattern } from "commonfabric"; const p = pattern((input: { user: { name: string }; value: { foo: number } }) => { const value = { foo: 1 }; { const value = input.user; void value.name; } return
{value.foo}
; }); `; const output = await transformSource(source); assertStringIncludes(output, 'const value = input.key("user");'); assertStringIncludes(output, "return
{value.foo}
;"); assert(!output.includes('value.key("foo")')); }, ); Deno.test( "Transform guards: plain callback parameter map is not rewritten in pattern", async () => { const source = `import { pattern } from "commonfabric"; const p = pattern((input: { ok: boolean }) => { const out = ((arr: number[]) => arr.map((x) => x + 1))([1, 2]); return
{out.length}
; }); `; const output = await transformSource(source); assertStringIncludes(output, "arr.map((x) => x + 1)"); assert(!output.includes(".mapWithPattern(")); }, ); Deno.test( "Transform guards: rewritten mapWithPattern callback uses key(...) canonicalization", async () => { const source = `import { pattern } from "commonfabric"; const p = pattern((input: { list: Array<{ name: string; age: number }> }) =>
{input.list.map(({ name }) => {name})}
); `; const output = await transformSource(source); assertStringIncludes(output, ".mapWithPattern("); assertStringIncludes( output, 'const name = __cf_pattern_input.key("element", "name");', ); }, ); Deno.test( "Transform guards: state property names that collide with method names still lower to key() access", async () => { for ( const { property, extraAssert } of [ { property: "filter", extraAssert: (output: string) => assert(!output.includes("filterWithPattern")), }, { property: "map", extraAssert: (_output: string) => {} }, { property: "set", extraAssert: (_output: string) => {} }, ] ) { const source = `import { pattern, UI } from "commonfabric"; interface State { ${property}: string; items?: string[] } const p = pattern((state) => ({ [UI]:
{state.${property}}
, })); `; const output = await transformSource(source, { types: COMMONFABRIC_TYPES, }); assertStringIncludes(output, `state.key("${property}")`); extraAssert(output); } }, ); Deno.test( "Transform guards: numeric element-access receiver keys use canonical numeric values", async () => { const source = `import { pattern } from "commonfabric"; interface Item { name: string } interface Group { items: Item[] } const p = pattern((input: { groups: Group[] }) => input.groups[1e2].items.map((item) => item.name) ); `; const output = await transformSource(source); assertStringIncludes( output, 'input.key("groups", "100", "items").mapWithPattern(', ); assert(!output.includes('"1e2"')); }, ); Deno.test( "Transform guards: unsupported reactive array find() does not lower to findWithPattern", async () => { const source = `import { pattern, UI } from "commonfabric"; interface Item { id: number; name: string } interface State { items: Item[] } const p = pattern((state) => ({ [UI]:
{state.items.find((item) => item.id === 1)?.name}
, })); `; const output = await transformSource(source, { types: COMMONFABRIC_TYPES }); assert(!output.includes("findWithPattern")); }, ); Deno.test( "Transform guards: aliased get-result callbacks inside computed stay plain", async () => { const source = `import { computed, pattern, UI } from "commonfabric"; interface Habit { name: string; } interface HabitLog { habitName: string; date: string; completed: boolean; } interface Input { habits: Habit[]; logs: HabitLog[]; todayDate: string; } export default pattern(({ habits, logs, todayDate }) => { return { [UI]:
{habits.map((habit) => { const doneToday = computed(() => { const logList = logs.get(); return logList.some( (log) => log.habitName === habit.name && log.date === todayDate && log.completed, ); }); return {doneToday ? "yes" : "no"}; })}
, }; }); `; const output = await transformSource(source, { types: COMMONFABRIC_TYPES, }); assertStringIncludes(output, "const logList = logs.get();"); assertStringIncludes( output, "return logList.some((log) => log.habitName === habit.name &&", ); assert( !output.includes("return logList.some((log) => __cfHelpers.when("), "aliased plain array some() callback should stay plain inside computed()/derive()", ); }, ); Deno.test( "Transform guards: ternary branch derive absorbs inner arithmetic instead of nesting", async () => { const source = `import { pattern, UI } from "commonfabric"; interface Item { id: number; price: number; } interface State { items: Item[]; discount: number; threshold: number; } export default pattern((state) => ({ [UI]: (
{state.items.map((item) => (
{item.price > state.threshold ? item.price * (1 - state.discount) : item.price}
))}
), })); `; const output = await transformSource(source, { types: COMMONFABRIC_TYPES, }); // After CT-1615 Phase 1, synthesized derives lower to lift-applied: // __cfHelpers.lift<...>(cb)(input) // Match `__cfHelpers.lift<` since the synthesized form always has // type arguments. assertEquals(output.match(/__cfHelpers\.lift { const source = `import { ifElse, pattern, UI } from "commonfabric"; interface Field { name: string; validationIssue?: { message: string }; } export default pattern<{ fields: Field[] }>((state) => ({ [UI]: (
{state.fields.map((field) => (
{ifElse( field.validationIssue !== undefined, {field.validationIssue?.message}, null, )}
))}
), })); `; const output = await transformSource(source, { types: COMMONFABRIC_TYPES, }); assertStringIncludes(output, "ifElse("); assertStringIncludes(output, "=> field.validationIssue !== undefined"); }, ); Deno.test( "Transform guards: helper-owned non-cell get() calls are not force-wrapped", async () => { const source = `import { ifElse, pattern, UI } from "commonfabric"; interface State { show: boolean; selected: string; } class Lookup { get(key: string): string | undefined { return key.toUpperCase(); } } export default pattern((state) => { const lookup = new Lookup(); return { [UI]:
{ifElse(state.show, lookup.get(state.selected), "missing")}
, }; }); `; const output = await transformSource(source, { types: COMMONFABRIC_TYPES, }); assertStringIncludes(output, "lookup.get("); assert( !/__cfHelpers\.(?:computed|derive)\([\s\S]{0,160}lookup\.get\(/.test( output, ), "expected non-cell helper-owned get() calls to remain plain method calls", ); }, ); Deno.test( "Transform guards: helper-owned child key references stay structural", async () => { const source = `import { Cell, Default, handler, lift, pattern, Stream } from "commonfabric"; const childIncrement = handler( (event: { amount?: number } | undefined, context: { value: Cell }) => { const amount = typeof event?.amount === "number" ? event.amount : 1; context.value.set((context.value.get() ?? 0) + amount); }, ); const forward = handler( (_event: unknown, context: { increment: Stream<{ amount?: number }> }) => { context.increment.send({ amount: 1 }); }, ); const childCounter = pattern<{ value: Default }>(({ value }) => ({ value, increment: childIncrement({ value }), })); const sum = lift((input: { left: number; right: number }) => input.left + input.right); export default pattern<{ left: Default; right: Default }>( ({ left, right }) => { const leftChild = childCounter({ value: left }); const rightChild = childCounter({ value: right }); return { total: sum({ left: leftChild.key("value"), right: rightChild.key("value"), }), forward: forward({ increment: rightChild.key("increment") }), }; }, ); `; const output = await transformSource(source, { types: COMMONFABRIC_TYPES, }); assertStringIncludes(output, 'left: leftChild.key("value")'); assertStringIncludes(output, 'right: rightChild.key("value")'); assertStringIncludes(output, 'increment: rightChild.key("increment")'); assert( !output.includes( '__cfHelpers.computed((): any => leftChild.key("value"))', ), "expected child value cell reference to stay structural inside helper-owned arguments", ); assert( !output.includes( '__cfHelpers.computed((): any => rightChild.key("increment"))', ), "expected child stream reference to stay structural inside helper-owned arguments", ); }, ); Deno.test( "Transform guards: ordinary helper calls with child key references stay structural", async () => { const source = `import { Cell, Default, handler, pattern, type Stream } from "commonfabric"; const asIncrementStream = ( ref: unknown, ): Stream<{ amount?: number }> => ref as Stream<{ amount?: number }>; const childIncrement = handler( (_event: { amount?: number } | undefined, _context: { value: Cell }) => {}, ); const bubbleToChild = handler( (_event: unknown, context: { childIncrement: Stream<{ amount?: number }> }) => { context.childIncrement.send({ amount: 1 }); }, ); const childCounter = pattern<{ value: Default }>(({ value }) => ({ value, increment: childIncrement({ value }), })); export default pattern<{ child: Default }>(({ child }) => { const childState = childCounter({ value: child }); return { bubbleToChild: bubbleToChild({ childIncrement: asIncrementStream(childState.key("increment")), }), }; }); `; const output = await transformSource(source, { types: COMMONFABRIC_TYPES, }); assertStringIncludes( output, 'childIncrement: asIncrementStream(childState.key("increment"))', ); assert( !/__cfHelpers\.(?:computed|derive)\([\s\S]{0,240}asIncrementStream\(childState\.key\("increment"\)\)/ .test( output, ), "expected child stream key reference to stay structural inside ordinary helper call arguments", ); }, );