rustlavel_view/ast.rs
1//! The parsed shape of a template.
2
3use crate::expr::Expr;
4use rustlavel_core::Error;
5use std::collections::BTreeMap;
6
7/// One renderable piece of a template.
8#[derive(Debug, Clone, PartialEq)]
9pub enum Node {
10 /// Literal markup.
11 Text(String),
12 /// `{{ expr }}` when escaped, `{!! expr !!}` when not.
13 Echo { expr: Expr, escaped: bool },
14 /// `@if` / `@elseif` / `@else`: the first branch whose condition is truthy
15 /// wins, otherwise `otherwise` runs if there is one.
16 If { branches: Vec<Branch>, otherwise: Option<Vec<Node>> },
17 /// `@foreach(subject as binding)`.
18 Foreach { subject: Expr, binding: String, body: Vec<Node> },
19 /// `@yield("name")`, with the optional fallback from `@yield("name", expr)`.
20 Yield { section: String, default: Option<Expr> },
21 /// `@include("partial")`.
22 Include(TemplateRef),
23}
24
25/// One arm of an `@if` chain.
26#[derive(Debug, Clone, PartialEq)]
27pub struct Branch {
28 pub condition: Expr,
29 pub body: Vec<Node>,
30}
31
32/// A reference from one template to another.
33///
34/// It keeps the position it was written at, so "that layout does not exist" can
35/// be reported with the same precision as a syntax error instead of surfacing
36/// as a bare file-not-found from somewhere deep in the renderer.
37#[derive(Debug, Clone, PartialEq)]
38pub struct TemplateRef {
39 /// The referenced view name, as written.
40 pub name: String,
41 /// The view the reference was written in.
42 pub file: String,
43 pub line: usize,
44 pub column: usize,
45}
46
47impl TemplateRef {
48 /// Blame this reference for a failure.
49 pub fn error(&self, message: impl Into<String>) -> Error {
50 Error::Template {
51 file: self.file.clone(),
52 line: self.line,
53 column: self.column,
54 message: message.into(),
55 }
56 }
57}
58
59/// A parsed template: what it renders, plus the layout wiring around it.
60#[derive(Debug, Clone, PartialEq)]
61pub struct Template {
62 /// The view name it was loaded under, e.g. `pages.home`.
63 pub name: String,
64 /// Everything outside a `@section`.
65 pub nodes: Vec<Node>,
66 /// The layout named by `@extends`, if any.
67 pub extends: Option<TemplateRef>,
68 /// Section bodies, keyed by name and hoisted out of `nodes`.
69 ///
70 /// Sections are captured rather than rendered in place: they exist to be
71 /// pulled into a layout by `@yield`, so a template that defines one and is
72 /// rendered on its own simply does not emit it.
73 pub sections: BTreeMap<String, Vec<Node>>,
74}