Files
pugz/docs/FEATURES_REFERENCE.md

12 KiB

Pugz Complete Features Reference

This document provides a comprehensive overview of ALL Pug features supported by Pugz, with examples from the demo templates.

Fully Supported Features

1. Doctypes

Declare the HTML document type at the beginning of your template.

Examples:

doctype html
doctype xml
doctype transitional
doctype strict
doctype frameset
doctype 1.1
doctype basic
doctype mobile

Demo Location: pages/all-features.pug (Section 1)

Rendered HTML:

<!DOCTYPE html>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

2. Tags

Basic HTML tags with automatic nesting based on indentation.

Examples:

// Basic tags
p This is a paragraph
div This is a div
span This is a span

// Nested tags
ul
  li Item 1
  li Item 2
  li Item 3

// Self-closing tags
img(src="/image.png")
br
hr
meta(charset="utf-8")

// Block expansion (inline nesting)
a: img(src="/icon.png")

Demo Location: pages/all-features.pug (Section 2)


3. Attributes

Basic Attributes:

a(href="/link" target="_blank" rel="noopener") Link
input(type="text" name="username" placeholder="Enter name")

Boolean Attributes:

input(type="checkbox" checked)
button(disabled) Disabled
option(selected) Selected

Class & ID Shorthand:

div#main-content Main content
.card Card element
#sidebar.widget.active Multiple classes with ID

Multiple Classes (Array):

div(class=['btn', 'btn-primary', 'btn-large']) Button

Style Attributes:

div(style="color: blue; font-weight: bold;") Styled text
div(style={color: 'red', background: 'yellow'}) Object style

Data Attributes:

div(data-id="123" data-name="example" data-active="true") Data attrs

Attribute Interpolation:

- var url = '/page'
a(href='/' + url) Link
a(href=url) Direct variable
button(class=`btn btn-${type}`) Template string

Demo Location: pages/attributes-demo.pug, pages/all-features.pug (Section 3)


4. Plain Text

Inline Text:

p This is inline text after the tag.

Piped Text:

p
  | This is piped text.
  | Multiple lines.
  | Each line starts with a pipe.

Block Text (Dot Notation):

script.
  if (typeof console !== 'undefined') {
    console.log('JavaScript block');
  }

style.
  .class { color: red; }

Literal HTML:

<div class="literal">
  <p>This is literal HTML</p>
</div>

Demo Location: pages/all-features.pug (Section 4)


5. Text Interpolation

Escaped Interpolation (Default - Safe):

p Hello, #{name}!
p Welcome to #{siteName}.

Unescaped Interpolation (Use with caution):

p Raw HTML: !{htmlContent}

Tag Interpolation:

p This has #[strong bold text] and #[a(href="/") links] inline.
p You can #[em emphasize] words in the middle of sentences.

Demo Location: pages/all-features.pug (Section 5)


6. Code (Buffered Output)

Escaped Buffered Code (Safe):

p= username
div= content
span= email

Unescaped Buffered Code (Unsafe):

div!= htmlContent
p!= rawMarkup

Demo Location: pages/all-features.pug (Section 6)


7. Comments

HTML Comments (Visible in Source):

// This appears in rendered HTML as <!-- comment -->
p Content after comment

Silent Comments (Not in Output):

//- This is NOT in the HTML output
p Content

Block Comments:

//-
  This entire block is commented out.
  Multiple lines.
  None of this appears in output.

Demo Location: pages/all-features.pug (Section 7)


8. Conditionals

If Statement:

if isLoggedIn
  p Welcome back!

If-Else:

if isPremium
  p Premium user
else
  p Free user

If-Else If-Else:

if role === "admin"
  p Admin access
else if role === "moderator"
  p Moderator access
else
  p Standard access

Unless (Negative Conditional):

unless isLoggedIn
  a(href="/login") Please log in

Demo Location: pages/conditional.pug, pages/all-features.pug (Section 8)


9. Case/When (Switch Statements)

Basic Case:

case status
  when "active"
    .badge Active
  when "pending"
    .badge Pending
  when "suspended"
    .badge Suspended
  default
    .badge Unknown

Multiple Values:

case userType
  when "admin"
  when "superadmin"
    p Administrative access
  when "user"
    p Standard access
  default
    p Guest access

Demo Location: pages/all-features.pug (Section 9)


10. Iteration (Each Loops)

Basic Each:

ul
  each item in items
    li= item

Each with Index:

ol
  each value, index in numbers
    li Item #{index}: #{value}

Each with Else (Fallback):

ul
  each product in products
    li= product
  else
    li No products available

Demo Location: pages/features-demo.pug, pages/all-features.pug (Section 10)


11. Mixins (Reusable Components)

Basic Mixin:

mixin button(text, type='primary')
  button(class=`btn btn-${type}`)= text

+button('Click Me')
+button('Submit', 'success')

Mixin with Default Parameters:

mixin card(title='Untitled', content='No content')
  .card
    .card-header= title
    .card-body= content

+card()
+card('My Title', 'My content')

Mixin with Blocks:

mixin article(title)
  .article
    h1= title
    if block
      block
    else
      p No content provided

+article('Hello')
  p This is the article content.
  p Multiple paragraphs.

Mixin with Attributes:

mixin link(href, name)
  a(href=href)&attributes(attributes)= name

+link('/page', 'Link')(class="btn" target="_blank")

Rest Arguments:

mixin list(id, ...items)
  ul(id=id)
    each item in items
      li= item

+list('my-list', 1, 2, 3, 4)

Demo Location: mixins/*.pug, pages/all-features.pug (Section 11)


12. Includes (Partials)

Include external Pug files as partials:

include partials/header.pug
include partials/footer.pug

div.content
  p Main content

Demo Location: All pages use include for mixins and partials


13. Template Inheritance (Extends/Blocks)

Layout File (layouts/main.pug):

doctype html
html
  head
    block head
      title Default Title
  body
    include ../partials/header.pug
    
    block content
      p Default content
    
    include ../partials/footer.pug

Page File (pages/home.pug):

extends ../layouts/main.pug

block head
  title Home Page

block content
  h1 Welcome Home
  p This is the home page content.

Block Append/Prepend:

extends layout.pug

block append scripts
  script(src="/extra.js")

block prepend styles
  link(rel="stylesheet" href="/custom.css")

Demo Location: All pages in pages/ extend layouts from layouts/


Not Supported Features

1. Filters

Filters like :markdown, :coffee, :cdata are not supported.

Not Supported:

:markdown
  # Heading
  This is **markdown**

Workaround: Pre-process markdown to HTML before passing to template.


2. JavaScript Expressions

Unbuffered code and JavaScript expressions are not supported.

Not Supported:

- var x = 1
- var items = [1, 2, 3]
- if (x > 0) console.log('test')

Workaround: Pass data from Zig code instead of defining in template.


3. Nested Field Access

Only top-level field access is supported in data binding.

Not Supported:

p= user.name
p #{address.city}

Supported:

p= userName
p #{city}

Workaround: Flatten data structures before passing to template.


📊 Feature Support Matrix

Feature Runtime Mode Compiled Mode Notes
Doctypes All standard doctypes
Tags Including self-closing
Attributes Static and dynamic
Plain Text Inline, piped, block, literal
Interpolation Escaped and unescaped
Buffered Code = and !=
Comments HTML and silent
Conditionals 🚧 Partial compiled support
Case/When 🚧 Partial compiled support
Iteration Runtime only
Mixins Runtime only
Includes Runtime only
Extends/Blocks Runtime only
Filters Not supported
JS Expressions Not supported
Nested Fields Not supported

Legend:

  • Fully Supported
  • 🚧 Partial Support / In Progress
  • Not Supported

🎯 Usage Examples

Runtime Mode (Full Feature Support)

const std = @import("std");
const pugz = @import("pugz");

pub fn main() !void {
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer arena.deinit();
    
    const html = try pugz.renderTemplate(arena.allocator(),
        \\extends layouts/main.pug
        \\
        \\block content
        \\  h1 #{title}
        \\  each item in items
        \\    p= item
    , .{
        .title = "My Page",
        .items = &[_][]const u8{"One", "Two", "Three"},
    });
    
    std.debug.print("{s}\n", .{html});
}

Compiled Mode (Best Performance)

const std = @import("std");
const templates = @import("generated/root.zig");

pub fn main() !void {
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer arena.deinit();
    
    // Simple page without extends/loops/mixins
    const html = try templates.home.render(arena.allocator(), .{
        .title = "Home Page",
        .name = "Alice",
    });
    
    std.debug.print("{s}\n", .{html});
}

📂 Demo Files by Feature

Feature Demo File Description
All Features pages/all-features.pug Comprehensive demo of every feature
Attributes pages/attributes-demo.pug All attribute syntax variations
Features pages/features-demo.pug Mixins, loops, case, conditionals
Conditionals pages/conditional.pug Simple if/else example
Layouts layouts/main.pug Full layout with extends/blocks
Mixins mixins/*.pug Buttons, forms, cards, alerts
Partials partials/*.pug Header, footer components

🚀 Quick Start

  1. Compile the CLI tool:

    cd /path/to/pugz
    zig build
    
  2. Compile simple templates (no extends/includes):

    ./zig-out/bin/cli --dir src/tests/examples/cli-templates-demo --out generated pages
    
  3. Use runtime mode for full feature support:

    const engine = pugz.ViewEngine.init(.{
        .views_dir = "src/tests/examples/cli-templates-demo",
    });
    
    const html = try engine.render(allocator, "pages/all-features", data);
    

💡 Best Practices

  1. Use Runtime Mode for:

    • Templates with extends/includes
    • Dynamic mixins
    • Complex iteration patterns
    • Development and rapid iteration
  2. Use Compiled Mode for:

    • Simple static pages
    • High-performance production deployments
    • Maximum type safety
    • Embedded templates
  3. Security:

    • Always use #{} (escaped) for user input
    • Only use !{} (unescaped) for trusted content
    • Validate and sanitize data before passing to templates


Version: Pugz 1.0
Zig Version: 0.15.2
Pug Syntax Version: Pug 3