Svelte → D IR{#if} @visible

{#if}@visible

Svelte’s {#if} looks like a branch. In a virtual DOM it is a branch: the consequent is created or destroyed as a separate tree. libwasm does not have that tree. It has a compiled struct graph and a way to skip a child. {#if ident} therefore prints as @visible!"child" on a bool ident that lives on the owner struct, plus setVisible / remount / unmount. The child is the same @child it would have been without the if. Visibility is a property of that child, not a second component type.

<script lang="d">
  bool open = false;
  void toggle() { this.update.open = !open; }
</script>
{#if open}
  <p>Visible</p>
{:else}
  <p>Hidden</p>
{/if}

this.update.open is the flip. libwasm update writes the field and fires setVisible. A bare open = !open in a handler is rewritten to this.update.open so the handle moves. IfToggle.svelte is this file. If you read the printed D and do not see @visible on open, ingest pointed at the wrong source.

Who owns the bool

The owner is the host struct when the {#if} is a direct child of the component. The owner is the parent element’s struct when the {#if} is nested inside an element. Nested flip is owner.update.cond = cond. Host-root if still emits setVisible!"child"(this, cond) and assigns not_cond for the else. Getting the owner wrong is how a page-level Flip hides a bool inside a child that happens to be called open too. Each owner carries its own field.

is a second @child with inverted setVisible. {:else if} is a nested IfBlock in elseKids, still multi-child @visible. Several consequent children — a <p>, a {@html}, a {#each} — attach to the same bool. The printer walks every walkable child, not only the first. Combo.svelte exists to prove that: one show hides or shows three different kinds of kid together.

Predicates

A predicate is not a miniature language. It is a D expression the printer already knows how to put on a bool or an int. {#if open} is the bool. {#if !off} inverts. {#if a && b} and {#if a || b} combine host bools. {#if on && !hide} is AND with a negation. {#if n > 0} is an int comparison. {#if who == extra} compares identifiers. {(ready && ok)} is the same AND with parentheses, which matters only because the scan once treated the parens as text.

Predicates that mention an item field{#if row.ok}, {#if hit.n > 0}, and every AND/OR/NOT mix of those with a host bool — do not belong to this page. The bool or int lives on the item, and a sync_* helper walks it.ok / it.n after put. That is {#each}, and it is the hardest IR in the language.