Skip to content

Conversation

@jlukic
Copy link
Member

@jlukic jlukic commented Jun 20, 2025

Implementation Summary: The {#async} Universal Block

1. Feature: The {#async} Block

This document summarizes the completed implementation of a new, universal template block designed to handle both asynchronous value resolution and synchronous variable scoping with a single, elegant, and declarative API.

2. Core Philosophy & Value

  • Unified API: Solves async/promise handling and synchronous let/aliasing with one construct, reducing the API surface area.
  • NL-First: All keywords are chosen for natural language readability. The common case of {#async getUsers as users} reads naturally without redundancy.
  • Developer Flexibility: Provides keyword aliases ({before}, {loading}) and ({error}, {catch}) to allow developers to choose the term that best fits their mental model.

3. Keyword API

  • Primary Keyword: {#async}
    • The general-purpose keyword for defining a value in a new scope. It is ideal for all use cases, including synchronous aliasing (let behavior).
    • Example: {#async state.user.profile as profile} or {#async getUsers() as users}

4. Syntax & Clauses

  • Main Clause (Success State)

    • Alias: {#async expression as alias}
    • Destructuring: {#async expression as { prop1, prop2, ...rest }}
    • Abbreviated: {#async expression}
      • When no as clause is provided, the resolved value is available via {this}.
  • Sub-Clauses (Optional, Fixed Branches)

    • Loading State: {before} and {loading} are interchangeable aliases.
    • Error State: {error} (injects default error variable) and {error as e} (custom alias).

5. Implementation Architecture

  • AST Structure

    • The template-compiler.js parses the syntax into an async node with dedicated, named properties for each optional clause. This is more precise and efficient for the renderer than a generic branches array, as our clauses are fixed and not repeatable.
    • AST Format:
      {
        "type": "async",
        "expression": "getUsers()",
        "as": "users",
        "parts": ["name", "email"],
        "rest": "otherProps",
      
        "content": [ /* Array of nodes for success state */ ],
      
        "loadingContent": [ /* Optional: Array of nodes for {before}/{loading} state */ ],
        "errorContent": [ /* Optional: Array of nodes for {error} state */ ],
        "errorAs": "e" // Optional: The alias for the error object
      }
  • Compiler & Renderer Responsibility

    • The template-compiler.js parses the {#async} grammar into the standard async AST node.
    • The renderer.js interprets the async AST node, invokes the directive, and manages the creation of new data contexts for child templates, following the pattern established in the {#each} implementation.
  • Reactivity & Runtime Logic

    • The stateful logic is encapsulated in a new Lit directive (reactive-async.js).
    • This directive is modeled on existing reactive directives.
    • The directive's core logic is wrapped in a Reaction.create() to establish a reactive context, ensuring the block re-evaluates when signals in the expression change.

6. Key Implementation Details

  • Expression Parsing: Added expression extraction to parseAsyncString() that handles both the expression and as clause correctly.
  • Error Alias Parsing: Implemented parsing for {error as e} syntax using a normalization approach in the compiler.
  • Destructuring Support: Full support for object destructuring with rest operator using shallow copying for safety.
  • Promise Handling: The directive handles both synchronous values and Promise-based async operations.
  • Reactive Integration: Follows existing directive patterns with Reaction.create() for automatic re-evaluation when expressions change.

@vercel
Copy link

vercel bot commented Jun 20, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
semantic-next ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 20, 2025 8:03pm

@github-actions github-actions bot added Templating Modifies templating package Tests Modifies tests Docs Modifies documentation labels Jun 20, 2025
@jlukic jlukic changed the base branch from main to next July 1, 2025 20:57
@jlukic jlukic merged commit 065bce7 into next Jul 1, 2025
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Docs Modifies documentation Templating Modifies templating package Tests Modifies tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants