///|
fn render_node_inner(
node : RenderNode,
context : LiquidContext,
state : RenderState,
) -> String {
if state.flow != Next {
return ""
}
match node {
Text(text) => text
Output(expression, report_missing) =>
render_expression(expression, context, state, report_missing)
For(loop_var, collection, body, modifiers, otherwise) =>
render_for(
loop_var, collection, body, modifiers, otherwise, context, state,
)
If(condition, then_body, elsif_branches, else_body) => {
let condition_result = condition.eval(context, state)
let body_to_render = if condition_result {
then_body
} else {
// Check elsif branches
let mut found_elsif = false
let mut elsif_body : Array[RenderNode] = []
for branch in elsif_branches {
let (elsif_condition, elsif_nodes) = branch
if elsif_condition.eval(context, state) {
elsif_body = elsif_nodes
found_elsif = true
break
}
}
if found_elsif {
elsif_body
} else {
match else_body {
Some(else_nodes) => else_nodes
None => []
}
}
}
render_nodes(body_to_render, context, state)
}
Unless(condition, body) => {
let condition_result = condition.eval(context, state)
if condition_result {
"" // Unless renders body only when condition is false
} else {
render_nodes(body, context, state)
}
}
Case(expression, when_branches, else_body) => {
let expr_value = expression.eval(context, state)
// Check each when branch
for branch in when_branches {
let (when_value, when_body) = branch
if @semantics.values_equal(expr_value, when_value.eval(context, state)) {
return render_nodes(when_body, context, state)
}
}
// If no when branch matched, use else body
match else_body {
Some(else_nodes) => render_nodes(else_nodes, context, state)
None => ""
}
}
Assign(var_name, expression) => {
// Parse and evaluate the expression
let value = expression.eval(context, state)
context.set(var_name, value)
"" // Assign doesn't produce output
}
Cycle(group, values) => {
if values.is_empty() {
return ""
}
let key = if group == "default" {
"implicit:" +
values.map(fn(v) { v.length().to_string() + ":" + v }).join("")
} else {
"named:" + @semantics.unquote_argument(group)
}
let index = state.cycles.get(key).unwrap_or(0) % values.length()
state.cycles[key] = (index + 1) % values.length()
values[index]
}
TableRow(loop_var, collection, body, cols) =>
render_table_row(loop_var, collection, body, cols, context, state)
Break => {
if state.loops > 0 {
state.flow = Break
}
""
}
Continue => {
if state.loops > 0 {
state.flow = Continue
}
""
}
Liquid(body) => render_nodes(body, context, state)
Section(section_name) =>
// Section tag - render section placeholder
""
Style(css_content) =>
// Style tag - render CSS content
""
Include(template_name) =>
render_partial(template_name, context, state, false)
Render(template_name) => render_partial(template_name, context, state, true)
Capture(var_name, content) => {
let captured_output = render_nodes(content, context, state)
// Store captured content in context
context.set(var_name, @value.string_value(captured_output))
// Capture doesn't produce direct output
""
}
Increment(name) => {
let current = state.counters.get(name).unwrap_or(0)
state.counters[name] = current + 1
current.to_string()
}
Decrement(name) => {
let current = state.counters.get(name).unwrap_or(0) - 1
state.counters[name] = current
current.to_string()
}
IfChanged(body) => {
let output = render_nodes(body, context, state)
if state.previous == Some(output) {
return ""
}
state.previous = Some(output)
output
}
Layout(layout_name) =>
// Layout tag - specify which layout to use
// This is typically processed at the template level, not during rendering
// For now, return a comment indicating the layout
""
Block(block_name, default_content) => {
// Block tag - define a content block that can be overridden
// Use a simple key without dots to avoid nested object access issues
let block_key = "__block_" + block_name
match context.get(block_key) {
Some(value) => value.to_string()
None => render_nodes(default_content, context, state)
}
}
Content =>
// Content tag - placeholder for main template content in layouts
match context.get("__content__") {
Some(value) => value.to_string()
None => ""
}
}
}
// Compare two values with an operator