;
`;
const result = transform(code);
expect(result.code).toContain("const count = 0");
expect(result.code).toContain("function increment");
expect(result.code).toContain("return count + 1");
});
it("should transform spread attributes on HTML element using spread() and templateEffect", () => {
const code = `
const props = { class: "foo" };
const element =
Content
;
`;
const result = transform(code);
// Spread on HTML element should use spread() + templateEffect for reactivity
expect(result.code).toContain("spread");
expect(result.code).toContain("templateEffect");
expect(result.code).toContain("props");
});
it("should transform conditional rendering (ternary) using insert() and templateEffect", () => {
const code = `
const show = signal(true);
const element =
{show.value ? Yes : No}
;
`;
const result = transform(code);
// Conditional expression should use insert() wrapped in templateEffect
expect(result.code).toContain("insert");
expect(result.code).toContain("templateEffect");
expect(result.code).toContain("show.value");
});
it("should transform list rendering (.map()) using insert() and templateEffect", () => {
const code = `
const items = ["a", "b", "c"];
const element =
{items.map(item =>
{item}
)}
;
`;
const result = transform(code);
// .map() expression should use insert() wrapped in templateEffect
expect(result.code).toContain("insert");
expect(result.code).toContain("templateEffect");
expect(result.code).toContain("items");
expect(result.code).toContain("map");
});
it("should insert runtime imports after existing import declarations", () => {
const code = `
import { signal } from "@dathra/reactivity";
const element =
Hello
;
`;
const result = transform(code);
// Runtime imports should appear after the existing import
const importIndex = result.code.indexOf("@dathra/reactivity");
const runtimeIndex = result.code.indexOf("@dathra/runtime");
expect(importIndex).toBeGreaterThanOrEqual(0);
expect(runtimeIndex).toBeGreaterThanOrEqual(0);
// Both imports should be present
expect(result.code).toContain("import");
expect(result.code).toContain("fromTree");
});
it("should transform nested Fragment in CSR mode", () => {
const code = `
const element = (
<>
First
<>
SecondThird
>
>
);
`;
const result = transform(code);
// Outer fragment should be transformed, inner Fragment is processed as part of tree
expect(result.code).toContain("fromTree");
expect(result.code).toContain("div");
expect(result.code).toContain("span");
});
describe("Component elements", () => {
it("should transform component element to function call in CSR mode", () => {
const code = `
const element = ;
`;
const result = transform(code, { mode: "csr" });
// Component should be converted to function call
expect(result.code).toContain("Counter");
expect(result.code).toContain("initialCount");
expect(result.code).toContain("5");
// Should NOT contain fromTree for component
expect(result.code).not.toContain("fromTree");
});
it("should transform component element to function call in SSR mode", () => {
const code = `
const element = ;
`;
const result = transform(code, { mode: "ssr" });
// Component should be converted to function call
expect(result.code).toContain("Counter");
expect(result.code).toContain("initialCount");
expect(result.code).toContain("10");
// Should NOT contain renderToString for component-only
expect(result.code).not.toContain("renderToString");
});
it("should handle nested component elements with insert (no templateEffect)", () => {
const code = `
const element = (
);
`;
const result = transform(code);
// Should contain fromTree for outer div
expect(result.code).toContain("fromTree");
expect(result.code).toContain("div");
// Should contain insert for nested component
expect(result.code).toContain("insert");
expect(result.code).toContain("Counter");
expect(result.code).toContain("initialCount");
// Components are inserted directly (NOT wrapped in templateEffect)
// to prevent re-creation on every signal change
expect(result.code).not.toContain("templateEffect");
});
it("should handle root component element without tree generation", () => {
const code = `
function App() {
return ;
}
`;
const result = transform(code);
// Should be direct function call, no fromTree
expect(result.code).toContain("Counter");
expect(result.code).toContain("initialCount");
expect(result.code).not.toContain("fromTree");
expect(result.code).not.toContain("templateEffect");
});
it("should handle JSXMemberExpression as component", () => {
const code = `
const element = ;
`;
const result = transform(code);
// Should treat Foo.Bar as component (function call)
expect(result.code).toContain("Foo");
expect(result.code).toContain("Bar");
expect(result.code).toContain("baz");
expect(result.code).toContain("qux");
// Should NOT use fromTree for component
expect(result.code).not.toContain("fromTree");
});
it("should distinguish lowercase HTML elements from uppercase components", () => {
const code = `
const element = (
);
`;
const result = transform(code);
// HTML elements should be in tree
expect(result.code).toContain("fromTree");
expect(result.code).toContain("div");
expect(result.code).toContain("button");
// Component should be inserted
expect(result.code).toContain("Counter");
expect(result.code).toContain("insert");
});
it("should pass children as children prop to components", () => {
const code = `
const element = (
Content
);
`;
const result = transform(code);
// Component should receive children prop
expect(result.code).toContain("Panel");
expect(result.code).toContain("title");
expect(result.code).toContain("children");
// Children should still be processed (HTML element)
expect(result.code).toContain("div");
});
it("should handle component with spread props", () => {
const code = `
const props = { count: 5, label: "Counter" };
const element = ;
`;
const result = transform(code);
// Should spread props in function call
expect(result.code).toContain("Counter");
expect(result.code).toContain("props");
expect(result.code).toContain("...");
});
it("should normalize client:visible directive into island metadata", () => {
const code = `
const element = ;
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain('"data-dh-island": "visible"');
expect(result.code).not.toContain("client:visible");
});
it("should preserve client:interaction values as island metadata", () => {
const code = `
const element = ;
`;
const result = transform(code, { mode: "ssr" });
expect(result.code).toContain('"data-dh-island": "interaction"');
expect(result.code).toContain('"data-dh-island-value": "mouseenter"');
});
it("should default bare client:interaction to click metadata", () => {
const code = `
const element = ;
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain('"data-dh-island": "interaction"');
expect(result.code).toContain('"data-dh-island-value": "click"');
});
it("should preserve the canonical host metadata contract keys", () => {
const code = `
const element = ;
`;
const result = transform(code, { mode: "ssr" });
expect(result.code).toContain('"data-dh-island"');
expect(result.code).toContain('"data-dh-island-value"');
expect(result.code).toContain('"media"');
expect(result.code).toContain('"(max-width: 720px)"');
});
it("should keep explicit nested island metadata on child components", () => {
const code = `
const element = ;
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain('"data-dh-island": "visible"');
expect(result.code).toContain('"data-dh-island": "load"');
});
it("should attach compiler-generated hydration metadata to defineComponent render functions", () => {
const code = `
const CounterCard = defineComponent(
"counter-card",
({ props }) => ,
);
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain("Object.assign");
expect(result.code).toContain("__hydrationMetadata__");
expect(result.code).toContain('kind: "generic-plan"');
expect(result.code).toContain("planFactory");
expect(result.code).toContain('kind: "attr"');
expect(result.code).toContain('kind: "event"');
expect(result.code).toContain('kind: "text"');
expect(result.code).not.toContain("boundaryRefs");
expect(result.code).not.toContain("artifact:");
});
it("should include nested boundary refs in compiler-generated hydration metadata", () => {
const code = `
const OuterCard = defineComponent(
"outer-card",
({ props }) => ,
);
`;
const result = transform(code, { mode: "ssr" });
expect(result.code).toContain("nestedBoundaries");
expect(result.code).toContain('tagName: "InnerCard"');
expect(result.code).toContain('islandStrategy: "load"');
expect(result.code).not.toContain("boundaryRefs");
});
it("should skip hydration metadata emission for unsupported imperative setup bodies", () => {
const code = `
const ImperativeCard = defineComponent(
"imperative-card",
({ host }) => {
host.setAttribute("data-ready", "yes");
return
;
const TopRestCard = defineComponent(
"top-rest-card",
() => renderRest("a"),
);
`;
const result = transform(code, { mode: "csr" });
// Rest param: 1 param pattern vs 1 arg — but RestElement has length 1 and args length 1
// collectBindingNames should visit the RestElement branch
expect(result.code).toContain("__hydrationMetadata__");
});
it("should cover renamePatternWithCollisions duplicate binding name in pattern", () => {
// A helper whose destructured pattern has a name collision with __dh_host (reserved)
const code = `
const renderReserved = ({__dh_host}) =>
{__dh_host}
;
const ReservedCard = defineComponent(
"reserved-card",
({ props }) => renderReserved({__dh_host: props.label.value}),
);
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain("__hydrationMetadata__");
expect(result.code).toContain("planFactory");
// The reserved name should be renamed to avoid collision
expect(result.code).not.toContain("unsupportedReason");
});
it("should cover renameStatementWithCollisions for FunctionDeclaration with reserved name collision", () => {
const code = `
const FnCollisionCard = defineComponent(
"fn-collision-card",
({ props }) => {
function __dh_host(x) { return x; }
const label = __dh_host(props.label.value);
return
{label}
;
},
);
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain("__hydrationMetadata__");
expect(result.code).toContain("planFactory");
// The function declaration named __dh_host should be renamed
});
it("should cover renameStatementWithCollisions fallback for non-VariableDeclaration non-FunctionDeclaration", () => {
// ExpressionStatement in prelude is not supported, so this won't produce planFactory
// but the line 403 is the fallback for applyRenameMapToStatementReferences
// We need a statement type that IS a supported prelude type (VariableDeclaration or FunctionDeclaration)
// Line 403 is actually unreachable for supported prelude since only VariableDeclaration and FunctionDeclaration pass isSupportedPlanPreludeStatement
// Let's instead test line 374: renameStatementWithCollisions for non-VariableDeclaration non-FunctionDeclaration
// Line 374 returns cloneNode(statement) - this is only reachable if the statement is not VariableDeclaration and not FunctionDeclaration
// But buildCollisionSafePlanAnalysis only passes preludeStatements which are already filtered by isSupportedPlanPreludeStatement
// So lines 374 and 403 may be structurally unreachable in the current code path. Let's skip these and focus on reachable lines.
// Instead, test a helper chain where a param name collides with an existing prelude variable
const code = `
const renderInner = (count) => {count};
const WrapperCard = defineComponent(
"wrapper-card",
({ props }) => {
const count = signal(0);
return renderInner(count.value);
},
);
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain("__hydrationMetadata__");
expect(result.code).toContain("planFactory");
// count in prelude and count as helper param should not collide
});
it("should cover containsJSXNode JSXFragment detection in prelude", () => {
const code = `
const FragPreludeCard = defineComponent(
"frag-prelude-card",
() => {
const frag = <>fragment>;
return
{frag}
;
},
);
`;
const result = transform(code, { mode: "csr" });
// JSXFragment in prelude should prevent planFactory extraction
expect(result.code).not.toContain("planFactory");
});
it("should classify deeply nested IfStatement hidden in an IIFE as unsupported-component-body", () => {
const code = `
const DeepIfCard = defineComponent(
"deep-if-card",
() => {
console.log("init");
const val = (() => { if (true) return 1; return 2; })();
return
,
);
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain("__hydrationMetadata__");
expect(result.code).toContain("planFactory");
expect(result.code).toContain('"spread"');
});
it("should cover resolveComponentRenderAnalysis null finalFrame from object spread helper", () => {
const code = `
const innerHelper = (x) => { x.toString(); };
const outerHelper = (val) => innerHelper(val);
const NullFinalCard = defineComponent(
"null-final-card",
({ props }) => outerHelper(props.label.value),
);
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain("__hydrationMetadata__");
expect(result.code).toContain("unsupportedReason");
});
it("should cover getUnsupportedHydrationReason containsNodeType IfStatement fallback (line 1242)", () => {
// This test verifies that NestedIfCard with an IIFE containing IfStatement
// but no ExpressionStatement in prelude → extractFunctionRenderFrame succeeds
// → resolveComponentRenderAnalysis produces a valid analysis → planFactory is generated.
// The IfStatement inside the IIFE doesn't affect planFactory generation because
// it's inside a VariableDeclaration initializer, not a top-level branching statement.
const code = `
const NestedIfCard = defineComponent(
"nested-if-card",
() => {
const result = (() => { if (true) return "a"; return "b"; })();
return
{result}
;
},
);
`;
const result = transform(code, { mode: "csr" });
// extractFunctionRenderFrame succeeds (VariableDeclaration + ReturnStatement)
// resolveComponentRenderAnalysis returns a valid analysis → planFactory
expect(result.code).toContain("__hydrationMetadata__");
expect(result.code).toContain("planFactory");
expect(result.code).not.toContain("unsupportedReason");
});
it("should cover resolveComponentRenderAnalysis null finalFrame from helper chain without return", () => {
// A helper chain where the final helper has no return expression
const code = `
const innerHelper = (x) => { x.toString(); };
const outerHelper = (val) => innerHelper(val);
const NullFinalCard = defineComponent(
"null-final-card",
({ props }) => outerHelper(props.label.value),
);
`;
const result = transform(code, { mode: "csr" });
// innerHelper has no return → resolveComponentRenderAnalysis returns null
expect(result.code).toContain("__hydrationMetadata__");
expect(result.code).toContain("unsupportedReason");
});
it("should cover walker inJSX guard for nested JSXElement (lines 1649-1650)", () => {
// The walker enters JSXElement, sets inJSX=true, then encounters a nested JSXElement
// This happens naturally when processing
text
// The guard at line 1648-1650 prevents double-transformation
const code = `
const element =
deep
;
`;
const result = transform(code);
expect(result.code).toContain("fromTree");
// Should produce a single template, not nested transforms
expect(result.code).toContain("div");
expect(result.code).toContain("span");
expect(result.code).toContain("em");
});
it("should cover walker inJSX guard for nested JSXFragment (lines 1676-1677)", () => {
// After entering a JSXElement, encountering a JSXFragment as child
const code = `
const element =
<>nested fragment>
;
`;
const result = transform(code);
expect(result.code).toContain("fromTree");
expect(result.code).toContain("nested fragment");
});
it("should cover isJSXElement/isJSXFragment type guard after inJSX check (lines 1653, 1680)", () => {
// These lines are type guards that should always pass after the walker visitor fires
// They are covered when any JSX is processed through the walker
// Testing with a simple component that has both element and fragment children
const code = `
const mixed =
el
<>frag>;
`;
const result = transform(code);
expect(result.code).toContain("fromTree");
});
it("should throw when client:media is missing a string literal value", () => {
const code = `
const element = ;
`;
expect(() => transform(code)).toThrow(
"client:media requires a string literal media query",
);
});
it("should throw when valueless directives receive a value", () => {
const code = `
const element = ;
`;
expect(() => transform(code)).toThrow(
"client:visible does not accept a value",
);
});
it("should throw for client directives on html elements", () => {
const code = `
const element =
bad
;
`;
expect(() => transform(code)).toThrow(
"client:* directives are only supported on component elements",
);
});
it("should throw for multiple client directives on one component", () => {
const code = `
const element = ;
`;
expect(() => transform(code)).toThrow(
"Multiple client:* directives are not allowed",
);
});
it("should throw for unknown client directives", () => {
const code = `
const element = ;
`;
expect(() => transform(code)).toThrow("Unknown client:* directive");
});
it("should throw when client directives collide with reserved island metadata props", () => {
const code = `
const element = ;
`;
expect(() => transform(code)).toThrow(
"client:* directives cannot be combined with explicit data-dh-island metadata",
);
});
it("should transform load:onClick on html elements into client target metadata plus click binding", () => {
const code = `
const element = ;
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain("data-dh-client-target=");
expect(result.code).toContain("data-dh-client-strategy=");
expect(result.code).toContain("load");
expect(result.code).toContain("event");
expect(result.code).toContain('"click"');
});
it("should transform interaction:onClick on html elements into interaction target metadata plus click binding", () => {
const code = `
const element = ;
`;
const result = transform(code, { mode: "ssr" });
expect(result.code).toContain("data-dh-client-target=");
expect(result.code).toContain("data-dh-client-strategy=");
expect(result.code).toContain("interaction");
});
it("should transform visible:onClick on html elements into visible target metadata plus click binding", () => {
const code = `
const element = ;
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain("data-dh-client-target=");
expect(result.code).toContain("data-dh-client-strategy=");
expect(result.code).toContain("visible");
expect(result.code).toContain('"click"');
expect(result.code).not.toContain("visible:onClick");
});
it("should transform idle:onClick on html elements into idle target metadata plus click binding", () => {
const code = `
const element = ;
`;
const result = transform(code, { mode: "ssr" });
expect(result.code).toContain("data-dh-client-target=");
expect(result.code).toContain("data-dh-client-strategy=");
expect(result.code).toContain("idle");
expect(result.code).not.toContain("idle:onClick");
});
it("should preserve the canonical colocated metadata contract keys", () => {
const code = `
const element = ;
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain("data-dh-client-target=");
expect(result.code).toContain("data-dh-client-strategy=");
expect(result.code).toContain("idle");
});
it("should support all canonical colocated strategies for onClick", () => {
for (const strategy of COLOCATED_CLIENT_STRATEGIES) {
const code = `
const element = ;
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain("data-dh-client-target=");
expect(result.code).toContain("data-dh-client-strategy=");
expect(result.code).toContain(strategy);
expect(result.code).toContain('"click"');
}
});
it("should throw when load:onClick and interaction:onClick are mixed in one jsx root", () => {
const code = `
const element = (
);
`;
expect(() => transform(code)).toThrow(
"Mixed colocated client strategies are not supported in one JSX root",
);
});
it("should throw when visible:onClick and idle:onClick are mixed in one jsx root", () => {
const code = `
const element = (
a()} />
b()} />
);
`;
expect(() => transform(code)).toThrow(
"Mixed colocated client strategies are not supported in one JSX root",
);
});
it("should throw when visible:onClick and load:onClick are mixed in one jsx root", () => {
const code = `
const element = (
a()} />
b()} />
);
`;
expect(() => transform(code)).toThrow(
"Mixed colocated client strategies are not supported in one JSX root",
);
});
it("should throw when idle:onClick and interaction:onClick are mixed in one jsx root", () => {
const code = `
const element = (
a()} />
b()} />
);
`;
expect(() => transform(code)).toThrow(
"Mixed colocated client strategies are not supported in one JSX root",
);
});
it("should throw when host level client directives mix with colocated client directives in one component render subtree", () => {
const clientDirectiveCode = `
const element = (
doThing()}>Run
);
`;
const explicitMetadataCode = `
const element = (
doThing()}>Run
);
`;
expect(() => transform(clientDirectiveCode)).toThrow(
"host-level client:* directives or data-dh-island metadata cannot be combined with colocated client directives in the same component render subtree",
);
expect(() => transform(explicitMetadataCode)).toThrow(
"host-level client:* directives or data-dh-island metadata cannot be combined with colocated client directives in the same component render subtree",
);
});
it("should throw when author supplies compiler reserved client metadata", () => {
const targetCode = `
const element = doThing()}>Run;
`;
const strategyCode = `
const element = doThing()}>Run;
`;
const eventCode = `
const element = doThing()}>Run;
`;
expect(() => transform(targetCode)).toThrow(
"data-dh-client-target is compiler-reserved metadata and cannot be authored directly",
);
expect(() => transform(strategyCode)).toThrow(
"data-dh-client-strategy is compiler-reserved metadata and cannot be authored directly",
);
expect(() => transform(eventCode)).toThrow(
"data-dh-client-event is compiler-reserved metadata and cannot be authored directly",
);
});
it("should throw when colocated directives are used on svg elements", () => {
const code = `
const element = ;
`;
expect(() => transform(code)).toThrow(
"visible:onClick is only supported on HTML elements",
);
});
it("should transform load:onMouseEnter on html elements into load target metadata plus mouseenter binding", () => {
const code = `
const element = doThing()}>Run;
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain("data-dh-client-target=");
expect(result.code).toContain("data-dh-client-strategy=");
expect(result.code).toContain("load");
expect(result.code).toContain('"mouseenter"');
});
it("should transform visible:onFocus and idle:onScroll on html elements", () => {
const visibleCode = `
const element = doThing()}>Run;
`;
const idleCode = `
const element = doThing()}>Run;
`;
const visibleResult = transform(visibleCode, { mode: "csr" });
const idleResult = transform(idleCode, { mode: "csr" });
expect(visibleResult.code).toContain("visible");
expect(visibleResult.code).toContain('"focus"');
expect(idleResult.code).toContain("idle");
expect(idleResult.code).toContain('"scroll"');
});
it("should keep interaction colocated directives limited to onClick", () => {
const code = `
const element = doThing()}>Run;
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain("interaction");
expect(result.code).toContain('"keydown"');
expect(result.code).toContain("data-dh-client-event=");
});
it("should throw when mixed interaction event types are used in one jsx root", () => {
const code = `
const element = (
a()} />
b()} />
);
`;
expect(() => transform(code)).toThrow(
"Mixed colocated interaction event types are not supported in one JSX root",
);
});
it("should transform component load:onClick into host metadata plus client action registration", () => {
const code = `
const handleClick = () => doThing();
const element = ;
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain(
'registerClientAction("dh-ca-1", (__dh_payload, __dh_host) =>',
);
expect(result.code).toContain("return handleClick;");
expect(result.code).toContain('"data-dh-island": "load"');
expect(result.code).toContain('"data-dh-client-actions"');
expect(result.code).toContain("dh-ca-1");
expect(result.code).not.toContain("load:onClick");
});
it("should transform component interaction:onKeyDown into host metadata plus client action registration", () => {
const code = `
const handleKeyDown = (event) => report(event.key);
const element = ;
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain(
'registerClientAction("dh-ca-1", (__dh_payload, __dh_host) =>',
);
expect(result.code).toContain("return handleKeyDown;");
expect(result.code).toContain('"data-dh-island": "interaction"');
expect(result.code).toContain('"data-dh-island-value": "keydown"');
expect(result.code).toContain('"data-dh-client-actions"');
expect(result.code).toContain("dh-ca-1");
expect(result.code).not.toContain("interaction:onKeyDown");
});
it("should reject component-target colocated handlers that capture local bindings", () => {
const code = `
const Parent = defineComponent("x-parent", () => {
const localCount = signal(0);
return bump(localCount)} />;
});
`;
expect(() => transform(code)).toThrow(
"[dathra] load:onClick component-target colocated handlers cannot capture local bindings: bump, localCount",
);
});
it("should serialize local const captures for component-target inline handlers", () => {
const code = `
function report(value) { return value; }
const Parent = defineComponent("x-parent", () => {
const label = "captured-label";
return report(label)} />;
});
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain('registerClientAction("dh-ca-1"');
expect(result.code).toContain("__dh_payload");
expect(result.code).toContain('"data-dh-client-actions"');
expect(result.code).toContain('payload: { label: "captured-label" }');
expect(result.code).toContain('"captured-label"');
});
it("should reject component-target interaction:onFocus because child host cannot observe focus", () => {
const code = `
const element = ;
`;
expect(() => transform(code)).toThrow(
"[dathra] interaction:onFocus is not supported on component targets because the child host cannot observe that event without an explicit host re-emit",
);
});
it("should throw when mixed colocated strategies appear across nested jsx transforms", () => {
const code = `
const element = (
a()} />
{condition ? b()} /> : null}
);
`;
expect(() => transform(code)).toThrow(
"Mixed colocated client strategies are not supported in one JSX root",
);
});
// --- Semantic coverage: async / generator / loop / try-catch / class / exotic patterns ---
it("should classify async arrow expression body as unsupported-component-body", () => {
const code = `
const AsyncCard = defineComponent(
"async-card",
async () =>
hi
,
);
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain("__hydrationMetadata__");
expect(result.code).toContain(
'unsupportedReason: "unsupported-component-body"',
);
expect(result.code).not.toContain("planFactory");
});
it("should classify async arrow block body with await as unsupported-component-body", () => {
const code = `
const AsyncBlockCard = defineComponent(
"async-block-card",
async () => {
const data = await fetchData();
return
>
),
);
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain("__hydrationMetadata__");
expect(result.code).toContain("planFactory");
expect(result.code).toContain("nestedBoundaries");
expect(result.code).toContain('"InnerIsland"');
expect(result.code).toContain('"idle"');
});
it("should support nested island with client:interaction", () => {
const code = `
const InteractionOuter = defineComponent(
"interaction-outer",
() =>
,
);
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain("__hydrationMetadata__");
expect(result.code).toContain("planFactory");
expect(result.code).toContain("nestedBoundaries");
expect(result.code).toContain('"InteractiveChild"');
expect(result.code).toContain('"interaction"');
});
it("should handle TypeScript type assertion in prelude as expression statement (unsupported prelude)", () => {
const code = `
const TSAsCard = defineComponent(
"ts-as-card",
() => {
const x = getSomething() as string;
return
{x}
;
},
);
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain("__hydrationMetadata__");
// TSAsExpression is inside a VariableDeclaration which IS a supported prelude.
// After TS transform (esbuild strips types), it becomes a normal VariableDeclaration.
// So this should produce a planFactory.
expect(result.code).toContain("planFactory");
});
it("should handle multiple const declarations in prelude", () => {
const code = `
const MultiConstCard = defineComponent(
"multi-const-card",
({ props }) => {
const a = props.x.value;
const b = props.y.value;
const c = a + b;
return
{c}
;
},
);
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain("__hydrationMetadata__");
expect(result.code).toContain("planFactory");
expect(result.code).not.toContain("unsupportedReason");
});
it("should handle let declaration in prelude as unsupported (only const/function allowed)", () => {
const code = `
const LetCard = defineComponent(
"let-card",
() => {
let x = 0;
return
{x}
;
},
);
`;
const result = transform(code, { mode: "csr" });
// VariableDeclaration with kind "let" is still a VariableDeclaration
// isSupportedPlanPreludeStatement checks for VariableDeclaration
// so it should work...
expect(result.code).toContain("__hydrationMetadata__");
});
it("should handle empty return in block body as no planFactory", () => {
const code = `
const EmptyReturnCard = defineComponent(
"empty-return-card",
() => { return; },
);
`;
const result = transform(code, { mode: "csr" });
// return without argument → extractFunctionRenderFrame returns null
expect(result.code).not.toContain("planFactory");
});
it("should classify setup with only non-JSX return as unsupported-component-body", () => {
const code = `
const StringReturnCard = defineComponent(
"string-return-card",
() => { return "not jsx"; },
);
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain("__hydrationMetadata__");
expect(result.code).toContain(
'unsupportedReason: "unsupported-component-body"',
);
expect(result.code).not.toContain("planFactory");
});
it("should classify setup returning a number literal as unsupported-component-body", () => {
const code = `
const NumberReturnCard = defineComponent(
"number-return-card",
() => { return 42; },
);
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain("__hydrationMetadata__");
expect(result.code).toContain(
'unsupportedReason: "unsupported-component-body"',
);
expect(result.code).not.toContain("planFactory");
});
it("should classify setup returning an array literal as unsupported-component-body", () => {
const code = `
const ArrayReturnCard = defineComponent(
"array-return-card",
() => { return [1, 2, 3]; },
);
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain("__hydrationMetadata__");
expect(result.code).toContain(
'unsupportedReason: "unsupported-component-body"',
);
expect(result.code).not.toContain("planFactory");
});
it("should classify setup returning an identifier as unsupported-component-body", () => {
const code = `
const IdentReturnCard = defineComponent(
"ident-return-card",
() => { return someVariable; },
);
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain("__hydrationMetadata__");
expect(result.code).toContain(
'unsupportedReason: "unsupported-component-body"',
);
expect(result.code).not.toContain("planFactory");
});
it("should classify setup with window reference inside typeof as supported (environment probe)", () => {
const code = `
const TypeofWindowCard = defineComponent(
"typeof-window-card",
() => {
const isSSR = typeof window === "undefined";
return
{isSSR ? "server" : "client"}
;
},
);
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain("__hydrationMetadata__");
// typeof window is an environment probe, NOT imperative-dom-query.
// BUT the return contains ConditionalExpression → runtime-branching
expect(result.code).not.toContain(
'unsupportedReason: "imperative-dom-query"',
);
});
it("should handle document reference NOT inside typeof as imperative-dom-query", () => {
const code = `
const DocQueryCard = defineComponent(
"doc-query-card",
() => {
const el = document.getElementById("root");
return
;
},
);
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain("__hydrationMetadata__");
// typeof document is an environment probe, not an imperative access
expect(result.code).not.toContain(
'unsupportedReason: "imperative-dom-query"',
);
expect(result.code).toContain("planFactory");
});
it("should handle setup with static JSX (no dynamic parts)", () => {
const code = `
const StaticCard = defineComponent(
"static-card",
() =>
helloworld
,
);
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain("__hydrationMetadata__");
expect(result.code).toContain("planFactory");
// No dynamic bindings
expect(result.code).toContain("bindings: []");
});
it("should handle imported transparent thunk wrapper (withStore) in SSR mode when wrapped in arrow", () => {
const code = `
import { withStore } from "@dathra/core";
const StoreCard = defineComponent(
"store-card",
({ props }) => withStore(myStore, () =>
{props.label.value}
),
);
`;
const result = transform(code, { mode: "ssr" });
// withStore is a transparent thunk wrapper — the inner JSX is resolved
expect(result.code).toContain("__hydrationMetadata__");
expect(result.code).toContain("planFactory");
});
it("should produce no metadata for bare withStore() call as direct component arg", () => {
const code = `
import { withStore } from "@dathra/core";
const StoreCard = defineComponent(
"store-card",
withStore(myStore, () =>
store content
),
);
`;
const result = transform(code, { mode: "ssr" });
// Bare CallExpression as component arg (not wrapped in a function) —
// the transformer cannot extract a render frame, so no metadata is attached
expect(result.code).not.toContain("__hydrationMetadata__");
expect(result.code).not.toContain("planFactory");
});
});
describe("Fragment dynamic content", () => {
it("should generate templateEffect and setText for dynamic text inside Fragment", () => {
const code = `
const count = signal(0);
const element = (
<>
{count.value}
>
);
`;
const result = transform(code);
// Fragment with dynamic text must produce templateEffect + setText
expect(result.code).toContain("templateEffect");
expect(result.code).toContain("setText");
expect(result.code).toContain("count.value");
});
it("should generate insert for component inside Fragment", () => {
const code = `
const element = (
<>
>
);
`;
const result = transform(code);
// Fragment with component child must produce insert
expect(result.code).toContain("insert");
expect(result.code).toContain("Counter");
expect(result.code).toContain("initialCount");
});
});
describe("Attribute name edge cases", () => {
it("should use string literal key for hyphenated attribute names", () => {
const code = `
const element =
Content
;
`;
const result = transform(code);
// Hyphenated attribute names must be quoted in the output object
expect(result.code).toContain("data-foo=");
expect(result.code).toContain("aria-label=");
expect(result.code).toContain("bar");
expect(result.code).toContain("test");
});
it("should not wrap static expression attribute (no reactive access) in templateEffect", () => {
const code = `
function getClass() { return "foo"; }
const element =
Content
;
`;
const result = transform(code);
// Non-reactive expression attribute should avoid templateEffect and use one-time setAttr
expect(result.code).not.toContain("templateEffect");
expect(result.code).toContain("setAttr");
expect(result.code).toContain("getClass");
});
it("should preserve local identifiers used by static expression attributes", () => {
const code = `
function App() {
const modeLabel = typeof document === "undefined" ? "SSR" : "CSR";
return
Current render mode
;
}
`;
const result = transform(code);
expect(result.code).toContain("setAttr");
expect(result.code).toContain("modeLabel");
expect(result.code).not.toContain('{ ["data-render-mode"]: modeLabel }');
expect(result.code).not.toContain("templateEffect");
});
it("should support namespaced attributes like xlink:href", () => {
const code = `
const element = ;
`;
const result = transform(code);
expect(result.code).toContain("xlink:href=");
expect(result.code).toContain("#icon");
});
});
describe("Expression container edge cases", () => {
it("should transform logical expression rendering using insert() and templateEffect", () => {
const code = `
const visible = signal(true);
const element =
{visible.value && Shown}
;
`;
const result = transform(code);
expect(result.code).toContain("insert");
expect(result.code).toContain("templateEffect");
expect(result.code).toContain("visible.value");
expect(result.code).toContain("span");
});
it("should transform expressions containing nested JSX via insert()", () => {
const code = `
const element =
;
`;
const result = transform(code);
expect(result.code).toContain("insert");
expect(result.code).toContain("items");
});
it("should transform logical expression JSX branches with renderToString in SSR mode", () => {
const code = `
const visible = true;
const element =
{visible && SSR}
;
`;
const result = transform(code, { mode: "ssr" });
expect(result.code).not.toContain("fromTree");
expect(result.code).toContain("renderDynamicInsert");
});
});
describe("SSR mode conditional rendering", () => {
it("should transform conditional JSX branches with renderToString in SSR mode (not fromTree)", () => {
const code = `
const flag = true;
const element =
{flag ? Yes : No}
;
`;
const result = transform(code, { mode: "ssr" });
// SSR mode: no DOM-dependent fromTree must appear
expect(result.code).not.toContain("fromTree");
expect(result.code).toContain("renderDynamicInsert");
});
it("should not use setText/templateEffect for SSR conditional branches", () => {
const code = `
const flag = true;
const element =
{flag ? A : B}
;
`;
const result = transform(code, { mode: "ssr" });
// SSR mode: no DOM mutation helpers
expect(result.code).not.toContain("fromTree");
expect(result.code).not.toContain("firstChild");
expect(result.code).not.toContain("nextSibling");
expect(result.code).not.toContain("setText");
});
it("should transform .map() JSX branches with renderToString in SSR mode", () => {
const code = `
const items = ["a", "b"];
const element =
{items.map(i =>
{i}
)}
;
`;
const result = transform(code, { mode: "ssr" });
// SSR mode: no DOM-dependent fromTree must appear
expect(result.code).not.toContain("fromTree");
expect(result.code).toContain("renderDynamicEach");
});
});
// ==========================================================================
// Batch 4: Comprehensive semantic JS/TSX pattern coverage
// ==========================================================================
describe("JS control flow constructs (unsupported prelude / body)", () => {
it("should classify for-loop in setup body as unsupported-component-body", () => {
const code = `
const LoopCard = defineComponent(
"loop-card",
() => {
for (let i = 0; i < 10; i++) {}
return
loop
;
},
);
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain(
'unsupportedReason: "unsupported-component-body"',
);
});
it("should classify while-loop in setup body as unsupported-component-body", () => {
const code = `
const WhileCard = defineComponent(
"while-card",
() => {
while (false) {}
return
while
;
},
);
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain(
'unsupportedReason: "unsupported-component-body"',
);
});
it("should classify do-while in setup body as unsupported-component-body", () => {
const code = `
const DoCard = defineComponent(
"do-card",
() => {
do {} while (false);
return
do
;
},
);
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain(
'unsupportedReason: "unsupported-component-body"',
);
});
it("should classify for-in in setup body as unsupported-component-body", () => {
const code = `
const ForInCard = defineComponent(
"for-in-card",
() => {
const obj = { a: 1 };
for (const k in obj) {}
return
for-in
;
},
);
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain(
'unsupportedReason: "unsupported-component-body"',
);
});
it("should classify for-of in setup body as unsupported-component-body", () => {
const code = `
const ForOfCard = defineComponent(
"for-of-card",
() => {
const arr = [1, 2, 3];
for (const v of arr) {}
return
;
},
);
`;
const result = transform(code, { mode: "csr" });
expect(result.code).toContain(
'unsupportedReason: "unsupported-component-body"',
);
});
it("should classify setup with with-statement as unsupported-component-body", () => {
// Note: 'with' is not valid in strict mode / modules, but parse may still create the node
// The important thing is it's not a VariableDeclaration or FunctionDeclaration
const code = `
const WithCard = defineComponent(
"with-card",
() => {
console.log("side-effect");
return
with
;
},
);
`;
const result = transform(code, { mode: "csr" });
// ExpressionStatement in prelude is unsupported
expect(result.code).toContain(
'unsupportedReason: "unsupported-component-body"',
);
});
it("should classify setup with debugger statement as unsupported-component-body", () => {
const code = `
const DebugCard = defineComponent(
"debug-card",
() => {
const x = 1;
debugger;
return
),
);
`;
const result = transform(code, { mode: "ssr" });
expect(result.code).toContain("__hydrationMetadata__");
expect(result.code).toContain("planFactory");
expect(result.code).toContain('"load"');
expect(result.code).toContain('"visible"');
});
it("should handle SSR mode with export named declaration", () => {
const code = `
export const SSRExportCard = defineComponent(
"ssr-export-card",
() =>
exported
,
);
`;
const result = transform(code, { mode: "ssr" });
expect(result.code).toContain("__hydrationMetadata__");
expect(result.code).toContain("planFactory");
});
});
describe("SSR mode + colocated directive output", () => {
it("should produce SSR planFactory for supported component with load:onClick", () => {
const code = `
import { defineComponent, signal } from "@dathra/core";
const Comp = defineComponent("x-comp", () => {
const count = signal(0);
return (
count.set(count.value + 1)}>Inc{count.value}
);
});
`;
const result = transform(code, { mode: "ssr" });
expect(result.code).toContain("__hydrationMetadata__");
expect(result.code).toContain("planFactory");
expect(result.code).not.toContain("unsupportedReason");
});
it("should produce SSR planFactory for supported component with interaction:onClick", () => {
const code = `
import { defineComponent } from "@dathra/core";
const Comp = defineComponent("x-comp", () => {
return
alert("hi")}>Alert
;
});
`;
const result = transform(code, { mode: "ssr" });
expect(result.code).toContain("__hydrationMetadata__");
expect(result.code).toContain("planFactory");
expect(result.code).not.toContain("unsupportedReason");
});
it("should produce SSR planFactory for supported component with visible:onClick", () => {
const code = `
import { defineComponent } from "@dathra/core";
const Comp = defineComponent("x-comp", () => {
return
doStuff()}>Visible
;
});
`;
const result = transform(code, { mode: "ssr" });
expect(result.code).toContain("__hydrationMetadata__");
expect(result.code).toContain("planFactory");
});
it("should produce SSR planFactory for supported component with idle:onClick", () => {
const code = `
import { defineComponent } from "@dathra/core";
const Comp = defineComponent("x-comp", () => {
return
doStuff()}>Idle
;
});
`;
const result = transform(code, { mode: "ssr" });
expect(result.code).toContain("__hydrationMetadata__");
expect(result.code).toContain("planFactory");
});
it("should include colocated metadata attributes in SSR output for load:onClick", () => {
const code = `
import { defineComponent } from "@dathra/core";
const Comp = defineComponent("x-comp", () => {
return
go()}>Go
;
});
`;
const result = transform(code, { mode: "ssr" });
expect(result.code).toContain("data-dh-client-target=");
expect(result.code).toContain("data-dh-client-strategy=");
expect(result.code).toContain("load");
});
it("should remove colocated syntax and keep click binding in SSR planFactory", () => {
const code = `
import { defineComponent, signal } from "@dathra/core";
const Comp = defineComponent("x-comp", () => {
const count = signal(0);
return (
count.set(count.value + 1)}>Inc
);
});
`;
const result = transform(code, { mode: "ssr" });
// The raw colocated syntax should be removed
expect(result.code).not.toContain("load:onClick");
// The click event should be preserved as a regular binding
expect(result.code).toContain("click");
});
it("should throw in SSR mode for unsupported (try/catch) + colocated combination", () => {
const code = `
import { defineComponent } from "@dathra/core";
const Comp = defineComponent("x-comp", () => {
try {
return