Page
An Olyra source file may contain one or more page declarations. Each page declares a route, optional layout, data bindings, and a template:
extends "layout.olyra" is optional. During olyra render, the layout's slot node is replaced with the rendered page template.
page "/route" { extends "layout.olyra" action submit { email: String } data { rows = query: from Entity | select { field } } macro row_link(row) { <a href="/rows/{row.field}">{row.field}</a> } template { for row in rows { call row_link(row) } }}Globals
Multi-document sources may declare global data. Global bindings are checked and rendered before each page and are available to all page templates:
olyra build and olyra build-site apply globals to every page in the source.
global { data { settings = query: from Setting | select { title } }}Actions
Pages may declare typed POST actions:
Action field types are checked. Built-in scalar action field types are String, DateTime, Date, Bool, Int, and Number; VTI enum names are also accepted. Actions are emitted in render plan and route manifest JSON with method: "POST" and typed fields.
page "/signup" { action subscribe { email: String active: Bool } template { <form method="post"></form> }}Layouts And Fragments
Layouts and partials are separate Olyra document forms:
Use include "fragment.olyra" inside a template to render another Olyra document with the current bindings.
Layouts can declare data bindings. Those bindings are available while rendering the layout template for pages that extend it.
layout { data { settings = query: from Setting | select { title } } template { <html><body>slot</body></html> }} fragment { template { <li>{row.name}</li> }}Macros
Pages, layouts, and fragments may define reusable parameterized template macros:
Macro arguments are template paths. During type-checking, each parameter is bound to the argument type, so field access inside the macro body is checked the same way as field access in the caller. Macro calls are rendered inline.
macro user_item(user) { <li>{user.email}</li>} template { <ul>for u in users { call user_item(u) }</ul>}Data
Data bindings are named Aelir queries. The compiler parses and type-checks each query against a VTI package. Query result rows become the data available to the template.
Template
Templates are HTML-ish text plus checked Olyra controls:
formatters are upper, lower, and trim; formatters can be chained.
the query result row type.
- {binding.field} interpolates a scalar value and HTML-escapes it.
- {raw binding.field} interpolates a scalar value without escaping.
- {binding.field | upper} applies a formatter before escaping. Built-in
- for row in binding { ... } iterates a query result list and binds row to
- index is available inside each for body as a zero-based loop index.
- if row.flag { ... } else { ... } requires a Bool expression and renders
- call macro_name(arg.path) expands a parameterized macro with checked
- include "fragment.olyra" renders another Olyra document at that point.
Render Plan
olyra build emits stable manifest JSON:
Each page render plan contains:
else, for, macro calls, include, and slot nodes with resolved types where applicable.
- routes: route path to page entry.
- pages: per-page render plans.
- route: page route.
- extends: optional layout file.
- actions: typed POST actions and input fields.
- data: query bindings, source entity, query text, and typed result row.
- template: text, interpolation, raw interpolation flag, formatters, if,
HTML Render Runtime
olyra render type-checks the page, executes embedded Aelir queries against JSON rows, and renders the resulting bindings to HTML:
The JSON root must be an object keyed by entity name:
from the current render scope.
- {binding.field} resolves a scalar path and HTML-escapes it.
- {raw binding.field} resolves the same path without escaping.
- for row in users { ... } iterates the rows produced by the users query.
- index is a zero-based number for the current loop iteration.
- if row.active { ... } renders the body when the JSON value is truthy.
- else renders when the condition is false.
- call user_item(row) renders the macro body with parameter values copied
- include and extends paths are resolved relative to the page file by the
{ "User": [ { "id": "user_1", "email": "ada@example.test", "active": true } ]}Download
Olyra is in active development and has no public downloads or releases yet.
No public download artifacts are available yet for this language.
Looking for everything in one place? See the downloads index.
