Skip to content

refactor: major template engine refactor (AST-based)#27

Open
Farrael wants to merge 18 commits intoElliesaur:mainfrom
Farrael:feature/template_ast
Open

refactor: major template engine refactor (AST-based)#27
Farrael wants to merge 18 commits intoElliesaur:mainfrom
Farrael:feature/template_ast

Conversation

@Farrael
Copy link
Contributor

@Farrael Farrael commented Feb 7, 2026

Summary

This PR introduces a complete rewrite of how templates are parsed and processed.
Templates are now compiled into an AST, producing:

  • a list of template nodes
  • a list of component definitions

These structures are cached to improve performance when updating values, without having to re-parse or rebuild the template (as long as the template itself or the component set doesn’t change).

What changed

AST-based processing

  • Templates are parsed once into an AST
  • Nodes and components are cached
  • Updating variables do not invalidates the AST
  • Re-parsing only happens when the template or components actually change
  • Adding for and each flow as attributes on HTML elements

Improved variable system

  • Item properties and zero-argument methods are supported and evaluated as requested
  • Suppliers are cached
  • Functions are supported (see below)

Functions in variables

  • Variables can now be functions
  • They receive the current variable stack as the first argument
  • They are not cached
  • This allows accessing context dynamically and executing logic when needed
  • See processor tests and callFunctionWithArguments for examples.

Each improvements

  • each blocks can optionally declare a loop variable name:
{{ each $items item }} ... {{ /each }}
  • Loop item properties can still be shortened:
{{$key}} instead of {{$item.key}}

…but only if it does not shadow an existing variable. (using the same name as a declared one)

Breaking changes

Declaration

  • All variables must now be explicitly declared using $.
  • All flow block like each and if should not use the symbol # at the beginning.

❌ Old:

{{#if variable ...}} ... {{/if}}

✅ New:

{{if $variable ...}} ... {{/if}}

Component syntax change

  • Components are no longer declared using template syntax.

❌ Old:

{{@special:foo=bar}}

✅ New:

<special foo="bar" />

Supplier / Function caching

  • Supplier and Function must now specify the caching policy when used

❌ Old:

setVariable("name", () -> heavy.computeName);

✅ New:

setVariable("name", () -> heavy.computeName, CachePolicy.CACHED);

Children support

  • Components can now receive children content, accessed via:
<slot:named> Default value </slot>
<slot:default/> 
<slot/> // Same as <slot:default/>
  • Components can define slots as input for resolution :
<my-component>
     <:header> My custom header </:header>
     Here, same as slot default !
     <:footer>
          My own footer
     </:footer>
</my-component>

Tip

$slot:<name> is still accessible as variable as a string already parsed and resolved

Variable resolution rules

  • Variables are only resolved for:
    • declared variable (block, user, ...)
    • context variable (using interface like before)
    • item properties
    • methods without arguments
  • Functions / Supplier should be explicitly opt-in for cache

Tests

  • A large number of tests were added to cover:
    • AST generation
    • caching behavior
    • variable resolution
    • components and children
    • function calls and context handling

Example

processor.setVariable("number", 12.847);

processor.registerComponent("statCard", """
    <div style="background-color: #2a2a3e; padding: 10; anchor-width: 120; anchor-height: 60;">
        <p style="color: #888888; font-size: 11;">{{$label}}</p>
        <p style="color: #ffffff; font-size: 18; font-weight: bold;">{{$value}}</p>
    </div>
""");

processor.setTemplate("""
    <statCard label="Blocks Placed" value={{$number}} />
""");

Notes

  • It would be good to test this branch on real-world use cases and report any issues we find before merging.
  • Some of the work here implement the same as kelpy (discord) did on Feature/template dx #28
    • <template> block are not implemented here

@MrMineO5 MrMineO5 self-requested a review February 7, 2026 22:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants