yao/sui/docs/template-syntax.md
Max 097fb73416 Refactor SUI Command Arguments and Enhance Default Template Handling
- Updated the `build` and `watch` commands to accept a single argument for `<sui>` and made the `<template>` argument optional, improving usability.
- Introduced a default template assignment for the `agent` SUI, ensuring a more intuitive setup for users.
- Enhanced error messages for command usage to provide clearer guidance on expected input format.
- Added new OpenAPI file to the bindata, improving the framework's capabilities for API integration.
2026-01-01 10:28:45 +08:00

9.2 KiB

Template Syntax

SUI uses a simple template syntax for data binding, conditional rendering, and list iteration.

Data Interpolation

Use double curly braces {{ }} to output data:

<!-- Variable binding -->
<span>{{ name }}</span>
<span>{{ user.email }}</span>
<span>{{ items[0].title }}</span>

<!-- Default values (null coalescing) -->
<span>{{ title ?? 'Default Title' }}</span>
<span>{{ user.name ?? 'Anonymous' }}</span>

<!-- Expressions -->
<span>{{ price * quantity }}</span>
<span>{{ firstName + ' ' + lastName }}</span>
<span>{{ count > 0 ? 'Has items' : 'Empty' }}</span>

Conditional Rendering

Basic If

<div s:if="{{ isActive }}">Active</div>
<div s:if="{{ count > 0 }}">Has items</div>
<div s:if="{{ user != null }}">Logged in</div>

If-Elif-Else

<div s:if="{{ status == 'active' }}">Active</div>
<div s:elif="{{ status == 'pending' }}">Pending</div>
<div s:elif="{{ status == 'suspended' }}">Suspended</div>
<div s:else>Unknown</div>

Comparison Operators

Operator Description
== Equal
!= Not equal
> Greater than
< Less than
>= Greater than or equal
<= Less than or equal
&& Logical AND
|| Logical OR
! Logical NOT

Examples

<!-- Multiple conditions -->
<div s:if="{{ isAdmin && isActive }}">Admin Panel</div>
<div s:if="{{ age >= 18 || hasPermission }}">Access Granted</div>

<!-- Negation -->
<div s:if="{{ !isLoading }}">Content loaded</div>

<!-- Null checks -->
<div s:if="{{ user != null && user.verified }}">Verified User</div>

List Rendering

Basic Loop

<ul>
  <li s:for="{{ items }}" s:for-item="item">{{ item.name }}</li>
</ul>

With Index

<ul>
  <li s:for="{{ items }}" s:for-item="item" s:for-index="index">
    {{ index + 1 }}. {{ item.name }}
  </li>
</ul>

Nested Loops

<div s:for="{{ categories }}" s:for-item="category">
  <h3>{{ category.name }}</h3>
  <ul>
    <li s:for="{{ category.items }}" s:for-item="item">{{ item.title }}</li>
  </ul>
</div>

Loop with Conditional

<div s:for="{{ users }}" s:for-item="user" s:if="{{ user.active }}">
  {{ user.name }}
</div>

Object Iteration

<dl s:for="{{ settings }}" s:for-item="value" s:for-index="key">
  <dt>{{ key }}</dt>
  <dd>{{ value }}</dd>
</dl>

Variable Assignment

Use <s:set> to define variables:

<!-- Simple assignment -->
<s:set name="total" value="{{ price * quantity }}" />
<span>Total: {{ total }}</span>

<!-- Computed values -->
<s:set name="fullName" value="{{ firstName + ' ' + lastName }}" />
<s:set name="isExpensive" value="{{ price > 100 }}" />

<!-- From expressions -->
<s:set name="discountedPrice" value="{{ price * (1 - discount / 100) }}" />

Attribute Binding

Dynamic Attributes

<input value="{{ formData.email }}" />
<a href="{{ '/user/' + userId }}">Profile</a>
<img src="{{ imageUrl }}" alt="{{ imageAlt }}" />

Conditional Attributes

<!-- Attribute with condition -->
<button s:attr-disabled="{{ !isValid }}">Submit</button>
<input s:attr-readonly="{{ isLocked }}" />
<div s:attr-hidden="{{ !showPanel }}">Panel</div>

<!-- Class binding -->
<div class="base {{ isActive ? 'active' : '' }}">Content</div>

Spread Attributes

<!-- Spread object as attributes -->
<div ...props></div>
<input ...inputAttrs />

Raw HTML Output

By default, output is HTML-escaped. Use s:raw for raw HTML:

<!-- Escaped (safe) -->
<div>{{ htmlContent }}</div>

<!-- Raw HTML (use with caution) -->
<div s:raw="true">{{ htmlContent }}</div>

Expression Engine

SUI uses Expr (v1.17) as the expression engine. Expr provides a powerful expression language with operators, functions, and more.

SUI Custom Functions

Function Description Example
P_(proc, ...) Call a Yao process {{ P_('models.user.Find', 1) }}
True(value) Check if value is truthy {{ True(user) }}
False(value) Check if value is falsy {{ False(error) }}
Empty(value) Check if array/object is empty {{ Empty(items) }}

Expr Built-in Functions

Expr provides many built-in functions. Here are commonly used ones:

Function Description Example
len(array) Get length of array/string/map {{ len(items) }}
all(array, pred) Check if all elements match {{ all(users, .active) }}
any(array, pred) Check if any element matches {{ any(items, .price > 100) }}
one(array, pred) Check if exactly one matches {{ one(users, .admin) }}
none(array, pred) Check if no elements match {{ none(items, .deleted) }}
map(array, mapper) Transform array elements {{ map(users, .name) }}
filter(array, pred) Filter array by predicate {{ filter(items, .active) }}
find(array, pred) Find first matching element {{ find(users, .id == 1) }}
count(array, pred) Count matching elements {{ count(items, .price > 50) }}
sum(array) Sum of array elements {{ sum(prices) }}
mean(array) Average of array elements {{ mean(scores) }}
min(array) Minimum value {{ min(prices) }}
max(array) Maximum value {{ max(scores) }}
first(array) First element {{ first(items) }}
last(array) Last element {{ last(items) }}
take(array, n) Take first n elements {{ take(items, 5) }}
keys(map) Get map keys {{ keys(settings) }}
values(map) Get map values {{ values(settings) }}
contains(a, b) Check if a contains b {{ contains(name, 'test') }}
startsWith(s, pre) Check string prefix {{ startsWith(url, 'https') }}
endsWith(s, suf) Check string suffix {{ endsWith(file, '.pdf') }}
upper(s) Uppercase string {{ upper(name) }}
lower(s) Lowercase string {{ lower(email) }}
trim(s) Trim whitespace {{ trim(input) }}
split(s, sep) Split string {{ split(tags, ',') }}
join(array, sep) Join array to string {{ join(names, ', ') }}
int(v) Convert to integer {{ int(value) }}
float(v) Convert to float {{ float(value) }}
string(v) Convert to string {{ string(count) }}
now() Current time {{ now() }}
date(s) Parse date string {{ date('2024-01-01') }}
duration(s) Parse duration string {{ duration('1h30m') }}

For the complete list of built-in functions and operators, see the Expr Language Definition.

Examples

<!-- SUI custom functions -->
<div s:if="{{ Empty(users) }}">No users found</div>
<span>{{ P_('utils.formatDate', createdAt) }}</span>

<!-- Array operations -->
<span>Total: {{ len(items) }} items</span>
<span>Active: {{ count(users, .active) }}</span>
<span>Sum: {{ sum(map(items, .price)) }}</span>

<!-- String operations -->
<span>{{ upper(first(split(name, ' '))) }}</span>

<!-- Filtering -->
<div s:for="{{ filter(items, .price > 100) }}" s:for-item="item">
  {{ item.name }}
</div>

String Operations

<!-- Concatenation -->
<span>{{ 'Hello, ' + name + '!' }}</span>

<!-- Template literals (in expressions) -->
<a href="{{ '/users/' + userId + '/edit' }}">Edit</a>

Arithmetic Operations

<!-- Basic math -->
<span>{{ price * quantity }}</span>
<span>{{ total / count }}</span>
<span>{{ value + 10 }}</span>
<span>{{ index - 1 }}</span>

<!-- Percentage -->
<span>{{ (completed / total) * 100 }}%</span>

Comments

HTML comments are preserved in output:

<!-- This comment appears in output -->

Whitespace Control

SUI preserves whitespace by default. For minified output, use build options:

yao sui build <sui> <template>       # Minified (production)
yao sui build <sui> <template> -D    # Preserved (development, --debug)