refactor: replace ArrayListUnmanaged with ArrayList per Zig 0.15 standards

- Renamed std.ArrayListUnmanaged to std.ArrayList across all source files
- Updated CLAUDE.md with Zig version standards rule
- Removed debug print from mixin test
- No API changes (allocator still passed to methods)
This commit is contained in:
2026-01-29 22:50:52 +05:30
parent b53aa16010
commit 2c98dab144
29 changed files with 122 additions and 124 deletions

View File

@@ -4,7 +4,7 @@ const helpers = @import("helpers.zig");
pub const Data = struct {}; pub const Data = struct {};
pub fn render(allocator: std.mem.Allocator, _: Data) ![]const u8 { pub fn render(allocator: std.mem.Allocator, _: Data) ![]const u8 {
var buf: std.ArrayListUnmanaged(u8) = .{}; var buf: std.ArrayList(u8) = .{};
defer buf.deinit(allocator); defer buf.deinit(allocator);
try buf.appendSlice(allocator, "<div class=\"'friend'\"><h3>friend_name</h3><p>friend_email</p><p>friend_about</p><span class=\"'tag'\">tag_value</span></div>"); try buf.appendSlice(allocator, "<div class=\"'friend'\"><h3>friend_name</h3><p>friend_email</p><p>friend_about</p><span class=\"'tag'\">tag_value</span></div>");

View File

@@ -4,7 +4,7 @@
const std = @import("std"); const std = @import("std");
/// Append HTML-escaped string to buffer /// Append HTML-escaped string to buffer
pub fn appendEscaped(buf: *std.ArrayListUnmanaged(u8), allocator: std.mem.Allocator, str: []const u8) !void { pub fn appendEscaped(buf: *std.ArrayList(u8), allocator: std.mem.Allocator, str: []const u8) !void {
for (str) |c| { for (str) |c| {
switch (c) { switch (c) {
'&' => try buf.appendSlice(allocator, "&amp;"), '&' => try buf.appendSlice(allocator, "&amp;"),

View File

@@ -4,7 +4,7 @@ const helpers = @import("helpers.zig");
pub const Data = struct {}; pub const Data = struct {};
pub fn render(allocator: std.mem.Allocator, _: Data) ![]const u8 { pub fn render(allocator: std.mem.Allocator, _: Data) ![]const u8 {
var buf: std.ArrayListUnmanaged(u8) = .{}; var buf: std.ArrayList(u8) = .{};
defer buf.deinit(allocator); defer buf.deinit(allocator);
try buf.appendSlice(allocator, "<p>Active</p><p>Inactive</p>"); try buf.appendSlice(allocator, "<p>Active</p><p>Inactive</p>");

View File

@@ -4,7 +4,7 @@ const helpers = @import("helpers.zig");
pub const Data = struct {}; pub const Data = struct {};
pub fn render(allocator: std.mem.Allocator, _: Data) ![]const u8 { pub fn render(allocator: std.mem.Allocator, _: Data) ![]const u8 {
var buf: std.ArrayListUnmanaged(u8) = .{}; var buf: std.ArrayList(u8) = .{};
defer buf.deinit(allocator); defer buf.deinit(allocator);
try buf.appendSlice(allocator, "<li><a href=\"/project\">project_name</a>: project_description</li>"); try buf.appendSlice(allocator, "<li><a href=\"/project\">project_name</a>: project_description</li>");

View File

@@ -4,7 +4,7 @@ const helpers = @import("helpers.zig");
pub const Data = struct {}; pub const Data = struct {};
pub fn render(allocator: std.mem.Allocator, _: Data) ![]const u8 { pub fn render(allocator: std.mem.Allocator, _: Data) ![]const u8 {
var buf: std.ArrayListUnmanaged(u8) = .{}; var buf: std.ArrayList(u8) = .{};
defer buf.deinit(allocator); defer buf.deinit(allocator);
try buf.appendSlice(allocator, "<div><h3>result_title</h3><span>$result_price</span></div>"); try buf.appendSlice(allocator, "<div><h3>result_title</h3><span>$result_price</span></div>");

View File

@@ -4,7 +4,7 @@ const helpers = @import("helpers.zig");
pub const Data = struct {}; pub const Data = struct {};
pub fn render(allocator: std.mem.Allocator, _: Data) ![]const u8 { pub fn render(allocator: std.mem.Allocator, _: Data) ![]const u8 {
var buf: std.ArrayListUnmanaged(u8) = .{}; var buf: std.ArrayList(u8) = .{};
defer buf.deinit(allocator); defer buf.deinit(allocator);
try buf.appendSlice(allocator, "<p>Hello World</p>"); try buf.appendSlice(allocator, "<p>Hello World</p>");

View File

@@ -4,7 +4,7 @@ const helpers = @import("helpers.zig");
pub const Data = struct {}; pub const Data = struct {};
pub fn render(allocator: std.mem.Allocator, _: Data) ![]const u8 { pub fn render(allocator: std.mem.Allocator, _: Data) ![]const u8 {
var buf: std.ArrayListUnmanaged(u8) = .{}; var buf: std.ArrayList(u8) = .{};
defer buf.deinit(allocator); defer buf.deinit(allocator);
try buf.appendSlice(allocator, "<!DOCTYPE html><html><head><title>My Site</title></head><body><h1>Welcome</h1><p>This is a simple page</p></body></html>"); try buf.appendSlice(allocator, "<!DOCTYPE html><html><head><title>My Site</title></head><body><h1>Welcome</h1><p>This is a simple page</p></body></html>");

View File

@@ -4,7 +4,7 @@ const helpers = @import("helpers.zig");
pub const Data = struct {}; pub const Data = struct {};
pub fn render(allocator: std.mem.Allocator, _: Data) ![]const u8 { pub fn render(allocator: std.mem.Allocator, _: Data) ![]const u8 {
var buf: std.ArrayListUnmanaged(u8) = .{}; var buf: std.ArrayList(u8) = .{};
defer buf.deinit(allocator); defer buf.deinit(allocator);
try buf.appendSlice(allocator, "<h1>Header</h1><h2>Header2</h2><h3>Header3</h3><h4>Header4</h4><h5>Header5</h5><h6>Header6</h6><ul><li>item1</li><li>item2</li><li>item3</li></ul>"); try buf.appendSlice(allocator, "<h1>Header</h1><h2>Header2</h2><h3>Header3</h3><h4>Header4</h4><h5>Header5</h5><h6>Header6</h6><ul><li>item1</li><li>item2</li><li>item3</li></ul>");

View File

@@ -1,6 +1,6 @@
.{ .{
.name = .pugz, .name = .pugz,
.version = "0.3.7", .version = "0.3.8",
.fingerprint = 0x822db0790e17621d, // Changing this has security and trust implications. .fingerprint = 0x822db0790e17621d, // Changing this has security and trust implications.
.minimum_zig_version = "0.15.2", .minimum_zig_version = "0.15.2",
.dependencies = .{}, .dependencies = .{},

View File

@@ -12,6 +12,10 @@ Pugz is a Pug-like HTML template engine written in Zig 0.15.2. It compiles Pug t
- When the user specifies a new rule, update this CLAUDE.md file to include it. - When the user specifies a new rule, update this CLAUDE.md file to include it.
- Code comments are required but must be meaningful, not bloated. Focus on explaining "why" not "what". Avoid obvious comments like "// increment counter" - instead explain complex logic, non-obvious decisions, or tricky edge cases. - Code comments are required but must be meaningful, not bloated. Focus on explaining "why" not "what". Avoid obvious comments like "// increment counter" - instead explain complex logic, non-obvious decisions, or tricky edge cases.
- **All documentation files (.md) must be saved to the `docs/` directory.** Do not create .md files in the root directory or examples directories - always place them in `docs/`. - **All documentation files (.md) must be saved to the `docs/` directory.** Do not create .md files in the root directory or examples directories - always place them in `docs/`.
- **Follow Zig standards for the version specified in `build.zig.zon`** (currently 0.15.2). This includes:
- Use `std.ArrayList(T)` instead of the deprecated `std.ArrayListUnmanaged(T)` (renamed in Zig 0.15)
- Pass allocator to method calls (`append`, `deinit`, etc.) as per the unmanaged pattern
- Check Zig release notes for API changes when updating the minimum Zig version
- **Publish command**: Only when user explicitly says "publish", do the following: - **Publish command**: Only when user explicitly says "publish", do the following:
1. Bump the fix version (patch version in build.zig.zon) 1. Bump the fix version (patch version in build.zig.zon)
2. Git commit with appropriate message 2. Git commit with appropriate message

View File

@@ -85,7 +85,7 @@ pub const CompilerError = error{
pub const Compiler = struct { pub const Compiler = struct {
allocator: Allocator, allocator: Allocator,
options: CompilerOptions, options: CompilerOptions,
output: std.ArrayListUnmanaged(u8), output: std.ArrayList(u8),
indent_level: usize = 0, indent_level: usize = 0,
has_doctype: bool = false, has_doctype: bool = false,
has_tag: bool = false, has_tag: bool = false,

View File

@@ -233,7 +233,7 @@ fn compileSingleFile(
} }
fn findPugFiles(allocator: mem.Allocator, dir_path: []const u8) ![][]const u8 { fn findPugFiles(allocator: mem.Allocator, dir_path: []const u8) ![][]const u8 {
var results: std.ArrayListUnmanaged([]const u8) = .{}; var results: std.ArrayList([]const u8) = .{};
errdefer { errdefer {
for (results.items) |item| allocator.free(item); for (results.items) |item| allocator.free(item);
results.deinit(allocator); results.deinit(allocator);
@@ -243,7 +243,7 @@ fn findPugFiles(allocator: mem.Allocator, dir_path: []const u8) ![][]const u8 {
return results.toOwnedSlice(allocator); return results.toOwnedSlice(allocator);
} }
fn findPugFilesRecursive(allocator: mem.Allocator, dir_path: []const u8, results: *std.ArrayListUnmanaged([]const u8)) !void { fn findPugFilesRecursive(allocator: mem.Allocator, dir_path: []const u8, results: *std.ArrayList([]const u8)) !void {
var dir = try fs.cwd().openDir(dir_path, .{ .iterate = true }); var dir = try fs.cwd().openDir(dir_path, .{ .iterate = true });
defer dir.close(); defer dir.close();
@@ -277,7 +277,7 @@ fn makeTemplateName(allocator: mem.Allocator, path: []const u8) ![]const u8 {
else else
path; path;
var result: std.ArrayListUnmanaged(u8) = .{}; var result: std.ArrayList(u8) = .{};
defer result.deinit(allocator); defer result.deinit(allocator);
for (without_ext) |c| { for (without_ext) |c| {
@@ -298,7 +298,7 @@ fn makeFlatFileName(allocator: mem.Allocator, path: []const u8) ![]const u8 {
else else
path; path;
var result: std.ArrayListUnmanaged(u8) = .{}; var result: std.ArrayList(u8) = .{};
defer result.deinit(allocator); defer result.deinit(allocator);
for (without_ext) |c| { for (without_ext) |c| {
@@ -315,14 +315,14 @@ fn makeFlatFileName(allocator: mem.Allocator, path: []const u8) ![]const u8 {
} }
fn generateRootZig(allocator: mem.Allocator, output_dir: []const u8, template_map: *std.StringHashMap([]const u8)) !void { fn generateRootZig(allocator: mem.Allocator, output_dir: []const u8, template_map: *std.StringHashMap([]const u8)) !void {
var output: std.ArrayListUnmanaged(u8) = .{}; var output: std.ArrayList(u8) = .{};
defer output.deinit(allocator); defer output.deinit(allocator);
try output.appendSlice(allocator, "// Auto-generated by Pugz build step\n"); try output.appendSlice(allocator, "// Auto-generated by Pugz build step\n");
try output.appendSlice(allocator, "// This file exports all compiled templates\n\n"); try output.appendSlice(allocator, "// This file exports all compiled templates\n\n");
// Sort template names // Sort template names
var names: std.ArrayListUnmanaged([]const u8) = .{}; var names: std.ArrayList([]const u8) = .{};
defer names.deinit(allocator); defer names.deinit(allocator);
var iter = template_map.keyIterator(); var iter = template_map.keyIterator();

View File

@@ -1,7 +1,7 @@
const std = @import("std"); const std = @import("std");
const mem = std.mem; const mem = std.mem;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const ArrayListUnmanaged = std.ArrayListUnmanaged; const ArrayList = std.ArrayList;
// ============================================================================ // ============================================================================
// Pug Error - Error formatting with source context // Pug Error - Error formatting with source context
@@ -47,7 +47,7 @@ pub const PugError = struct {
/// Format as JSON-like structure for serialization /// Format as JSON-like structure for serialization
pub fn toJson(self: *const PugError, allocator: Allocator) ![]const u8 { pub fn toJson(self: *const PugError, allocator: Allocator) ![]const u8 {
var result: ArrayListUnmanaged(u8) = .{}; var result: ArrayList(u8) = .{};
errdefer result.deinit(allocator); errdefer result.deinit(allocator);
try result.appendSlice(allocator, "{\"code\":\""); try result.appendSlice(allocator, "{\"code\":\"");
@@ -76,7 +76,7 @@ pub const PugError = struct {
}; };
/// Append JSON-escaped string to result /// Append JSON-escaped string to result
fn appendJsonEscaped(allocator: Allocator, result: *ArrayListUnmanaged(u8), s: []const u8) !void { fn appendJsonEscaped(allocator: Allocator, result: *ArrayList(u8), s: []const u8) !void {
for (s) |c| { for (s) |c| {
switch (c) { switch (c) {
'"' => try result.appendSlice(allocator, "\\\""), '"' => try result.appendSlice(allocator, "\\\""),
@@ -150,7 +150,7 @@ fn formatErrorMessage(
) ![]const u8 { ) ![]const u8 {
_ = code; // Code is embedded in PugError struct _ = code; // Code is embedded in PugError struct
var result: ArrayListUnmanaged(u8) = .{}; var result: ArrayList(u8) = .{};
errdefer result.deinit(allocator); errdefer result.deinit(allocator);
// Header: filename:line:column or Pug:line:column // Header: filename:line:column or Pug:line:column
@@ -231,7 +231,7 @@ fn formatErrorMessage(
/// Split source into lines (handles \n, \r\n, \r) /// Split source into lines (handles \n, \r\n, \r)
fn splitLines(allocator: Allocator, src: []const u8) ![][]const u8 { fn splitLines(allocator: Allocator, src: []const u8) ![][]const u8 {
var lines: ArrayListUnmanaged([]const u8) = .{}; var lines: ArrayList([]const u8) = .{};
errdefer lines.deinit(allocator); errdefer lines.deinit(allocator);
var start: usize = 0; var start: usize = 0;

View File

@@ -180,13 +180,13 @@ pub const Token = struct {
}; };
// ============================================================================ // ============================================================================
// Character Parser State (simplified) - Zig 0.15 style with ArrayListUnmanaged // Character Parser State (simplified) - Zig 0.15 style with ArrayList
// ============================================================================ // ============================================================================
const BracketType = enum { paren, brace, bracket }; const BracketType = enum { paren, brace, bracket };
const CharParserState = struct { const CharParserState = struct {
nesting_stack: std.ArrayListUnmanaged(BracketType) = .{}, nesting_stack: std.ArrayList(BracketType) = .{},
in_string: bool = false, in_string: bool = false,
string_char: ?u8 = null, string_char: ?u8 = null,
in_template: bool = false, in_template: bool = false,
@@ -320,7 +320,7 @@ const BracketExpressionResult = struct {
}; };
// ============================================================================ // ============================================================================
// Lexer - Zig 0.15 style with ArrayListUnmanaged // Lexer - Zig 0.15 style with ArrayList
// ============================================================================ // ============================================================================
pub const Lexer = struct { pub const Lexer = struct {
@@ -332,10 +332,10 @@ pub const Lexer = struct {
interpolated: bool, interpolated: bool,
lineno: usize, lineno: usize,
colno: usize, colno: usize,
indent_stack: std.ArrayListUnmanaged(usize) = .{}, indent_stack: std.ArrayList(usize) = .{},
indent_re_type: ?IndentType = null, indent_re_type: ?IndentType = null,
interpolation_allowed: bool, interpolation_allowed: bool,
tokens: std.ArrayListUnmanaged(Token) = .{}, tokens: std.ArrayList(Token) = .{},
ended: bool, ended: bool,
last_error: ?LexerError = null, last_error: ?LexerError = null,
@@ -359,7 +359,7 @@ pub const Lexer = struct {
} }
// Normalize line endings // Normalize line endings
var normalized: std.ArrayListUnmanaged(u8) = .{}; var normalized: std.ArrayList(u8) = .{};
errdefer normalized.deinit(allocator); errdefer normalized.deinit(allocator);
var i: usize = 0; var i: usize = 0;
@@ -378,7 +378,7 @@ pub const Lexer = struct {
} }
} }
var indent_stack: std.ArrayListUnmanaged(usize) = .{}; var indent_stack: std.ArrayList(usize) = .{};
try indent_stack.append(allocator, 0); try indent_stack.append(allocator, 0);
const input_slice = try normalized.toOwnedSlice(allocator); const input_slice = try normalized.toOwnedSlice(allocator);
@@ -1349,7 +1349,7 @@ pub const Lexer = struct {
/// Validates that brackets in an expression are balanced /// Validates that brackets in an expression are balanced
fn validateExpressionBrackets(self: *Lexer, expr: []const u8) bool { fn validateExpressionBrackets(self: *Lexer, expr: []const u8) bool {
var bracket_stack = std.ArrayListUnmanaged(u8){}; var bracket_stack = std.ArrayList(u8){};
defer bracket_stack.deinit(self.allocator); defer bracket_stack.deinit(self.allocator);
var in_string: u8 = 0; var in_string: u8 = 0;
@@ -2309,8 +2309,8 @@ pub const Lexer = struct {
self.tokens.append(self.allocator, start_token) catch return false; self.tokens.append(self.allocator, start_token) catch return false;
var string_ptr: usize = 0; var string_ptr: usize = 0;
var tokens_list: std.ArrayListUnmanaged([]const u8) = .{}; var tokens_list: std.ArrayList([]const u8) = .{};
var token_indent_list: std.ArrayListUnmanaged(bool) = .{}; var token_indent_list: std.ArrayList(bool) = .{};
defer tokens_list.deinit(self.allocator); defer tokens_list.deinit(self.allocator);
defer token_indent_list.deinit(self.allocator); defer token_indent_list.deinit(self.allocator);
@@ -2451,7 +2451,7 @@ pub const Lexer = struct {
var in_string: u8 = 0; var in_string: u8 = 0;
// Track bracket stack - inside #[...] you can have (...) and {...} for attrs/code // Track bracket stack - inside #[...] you can have (...) and {...} for attrs/code
var bracket_stack = std.ArrayListUnmanaged(u8){}; var bracket_stack = std.ArrayList(u8){};
defer bracket_stack.deinit(self.allocator); defer bracket_stack.deinit(self.allocator);
bracket_stack.append(self.allocator, '[') catch return; bracket_stack.append(self.allocator, '[') catch return;

View File

@@ -102,10 +102,10 @@ pub fn link(allocator: Allocator, ast: *Node) LinkerError!LinkerResult {
// Handle extends // Handle extends
if (extends_node) |ext_node| { if (extends_node) |ext_node| {
// Get mixins and expected blocks from current template // Get mixins and expected blocks from current template
var mixins = std.ArrayListUnmanaged(*Node){}; var mixins = std.ArrayList(*Node){};
defer mixins.deinit(allocator); defer mixins.deinit(allocator);
var expected_blocks = std.ArrayListUnmanaged(*Node){}; var expected_blocks = std.ArrayList(*Node){};
defer expected_blocks.deinit(allocator); defer expected_blocks.deinit(allocator);
try collectMixinsAndBlocks(allocator, result.ast, &mixins, &expected_blocks); try collectMixinsAndBlocks(allocator, result.ast, &mixins, &expected_blocks);
@@ -178,8 +178,8 @@ fn findDeclaredBlocks(allocator: Allocator, ast: *Node) LinkerError!BlockDefinit
fn collectMixinsAndBlocks( fn collectMixinsAndBlocks(
allocator: Allocator, allocator: Allocator,
ast: *Node, ast: *Node,
mixins: *std.ArrayListUnmanaged(*Node), mixins: *std.ArrayList(*Node),
expected_blocks: *std.ArrayListUnmanaged(*Node), expected_blocks: *std.ArrayList(*Node),
) LinkerError!void { ) LinkerError!void {
for (ast.nodes.items) |node| { for (ast.nodes.items) |node| {
switch (node.type) { switch (node.type) {

View File

@@ -357,7 +357,7 @@ pub fn pathJoin(allocator: Allocator, base: []const u8, relative: []const u8) ![
const base_dir = dirname(base); const base_dir = dirname(base);
// Handle .. and . components // Handle .. and . components
var result = std.ArrayListUnmanaged(u8){}; var result = std.ArrayList(u8){};
errdefer result.deinit(allocator); errdefer result.deinit(allocator);
try result.appendSlice(allocator, base_dir); try result.appendSlice(allocator, base_dir);

View File

@@ -289,7 +289,7 @@ fn substituteArgs(
} }
// Perform substitution // Perform substitution
var result = std.ArrayListUnmanaged(u8){}; var result = std.ArrayList(u8){};
errdefer result.deinit(allocator); errdefer result.deinit(allocator);
var i: usize = 0; var i: usize = 0;
@@ -335,7 +335,7 @@ fn evaluateStringConcat(allocator: Allocator, expr: []const u8) ![]const u8 {
// Check if there's a + operator (string concat) // Check if there's a + operator (string concat)
_ = mem.indexOf(u8, expr, " + ") orelse return expr; _ = mem.indexOf(u8, expr, " + ") orelse return expr;
var result = std.ArrayListUnmanaged(u8){}; var result = std.ArrayList(u8){};
errdefer result.deinit(allocator); errdefer result.deinit(allocator);
var remaining = expr; var remaining = expr;
@@ -386,7 +386,7 @@ fn bindArguments(
bindings: *std.StringHashMapUnmanaged([]const u8), bindings: *std.StringHashMapUnmanaged([]const u8),
) MixinError!void { ) MixinError!void {
// Parse parameter names from definition: "text, type" or "text, type='primary'" // Parse parameter names from definition: "text, type" or "text, type='primary'"
var param_names = std.ArrayListUnmanaged([]const u8){}; var param_names = std.ArrayList([]const u8){};
defer param_names.deinit(allocator); defer param_names.deinit(allocator);
var param_iter = mem.splitSequence(u8, params, ","); var param_iter = mem.splitSequence(u8, params, ",");
@@ -409,7 +409,7 @@ fn bindArguments(
} }
// Parse argument values from call: "'Click', 'primary'" or "text='Click'" // Parse argument values from call: "'Click', 'primary'" or "text='Click'"
var arg_values = std.ArrayListUnmanaged([]const u8){}; var arg_values = std.ArrayList([]const u8){};
defer arg_values.deinit(allocator); defer arg_values.deinit(allocator);
// Simple argument parsing - split by comma but respect quotes // Simple argument parsing - split by comma but respect quotes
@@ -589,12 +589,6 @@ test "bindArguments - with default value in param" {
// This is how it appears: params have default, args are the call args // This is how it appears: params have default, args are the call args
try bindArguments(allocator, "text, type=\"primary\"", "\"Click Me\", \"primary\"", &bindings); try bindArguments(allocator, "text, type=\"primary\"", "\"Click Me\", \"primary\"", &bindings);
std.debug.print("\nBindings:\n", .{});
var iter = bindings.iterator();
while (iter.next()) |entry| {
std.debug.print(" {s} = '{s}'\n", .{ entry.key_ptr.*, entry.value_ptr.* });
}
try std.testing.expectEqualStrings("Click Me", bindings.get("text").?); try std.testing.expectEqualStrings("Click Me", bindings.get("text").?);
try std.testing.expectEqualStrings("primary", bindings.get("type").?); try std.testing.expectEqualStrings("primary", bindings.get("type").?);
} }

View File

@@ -110,7 +110,7 @@ pub const Node = struct {
filename: ?[]const u8 = null, filename: ?[]const u8 = null,
// Block fields // Block fields
nodes: std.ArrayListUnmanaged(*Node) = .{}, nodes: std.ArrayList(*Node) = .{},
// NamedBlock additional fields // NamedBlock additional fields
name: ?[]const u8 = null, // Also used for Tag, Mixin, Filter name: ?[]const u8 = null, // Also used for Tag, Mixin, Filter
@@ -118,8 +118,8 @@ pub const Node = struct {
// Tag fields // Tag fields
self_closing: bool = false, self_closing: bool = false,
attrs: std.ArrayListUnmanaged(Attribute) = .{}, attrs: std.ArrayList(Attribute) = .{},
attribute_blocks: std.ArrayListUnmanaged(AttributeBlock) = .{}, attribute_blocks: std.ArrayList(AttributeBlock) = .{},
is_inline: bool = false, is_inline: bool = false,
text_only: bool = false, text_only: bool = false,
self_closing_allowed: bool = false, self_closing_allowed: bool = false,
@@ -150,7 +150,7 @@ pub const Node = struct {
file: ?FileReference = null, file: ?FileReference = null,
// Include fields // Include fields
filters: std.ArrayListUnmanaged(*Node) = .{}, filters: std.ArrayList(*Node) = .{},
// InterpolatedTag fields // InterpolatedTag fields
expr: ?[]const u8 = null, expr: ?[]const u8 = null,
@@ -247,7 +247,7 @@ pub const Parser = struct {
allocator: Allocator, allocator: Allocator,
tokens: []const Token, tokens: []const Token,
pos: usize = 0, pos: usize = 0,
deferred: std.ArrayListUnmanaged(Token) = .{}, deferred: std.ArrayList(Token) = .{},
filename: ?[]const u8 = null, filename: ?[]const u8 = null,
src: ?[]const u8 = null, src: ?[]const u8 = null,
in_mixin: usize = 0, in_mixin: usize = 0,
@@ -475,7 +475,7 @@ pub const Parser = struct {
fn parseText(self: *Parser, allow_block: bool) !*Node { fn parseText(self: *Parser, allow_block: bool) !*Node {
const lineno = self.peek().loc.start.line; const lineno = self.peek().loc.start.line;
var tags = std.ArrayListUnmanaged(*Node){}; var tags = std.ArrayList(*Node){};
defer tags.deinit(self.allocator); defer tags.deinit(self.allocator);
while (true) { while (true) {
@@ -548,8 +548,8 @@ pub const Parser = struct {
} }
} }
fn parseTextHtml(self: *Parser) !std.ArrayListUnmanaged(*Node) { fn parseTextHtml(self: *Parser) !std.ArrayList(*Node) {
var nodes = std.ArrayListUnmanaged(*Node){}; var nodes = std.ArrayList(*Node){};
var current_node: ?*Node = null; var current_node: ?*Node = null;
while (true) { while (true) {
@@ -922,7 +922,7 @@ pub const Parser = struct {
const line = tok.loc.start.line; const line = tok.loc.start.line;
const column = tok.loc.start.column; const column = tok.loc.start.column;
var text = std.ArrayListUnmanaged(u8){}; var text = std.ArrayList(u8){};
defer text.deinit(self.allocator); defer text.deinit(self.allocator);
if (self.peek().type == .start_pipeless_text) { if (self.peek().type == .start_pipeless_text) {
@@ -1095,7 +1095,7 @@ pub const Parser = struct {
fn parseIncludeFilter(self: *Parser) !*Node { fn parseIncludeFilter(self: *Parser) !*Node {
const tok = try self.expect(.filter); const tok = try self.expect(.filter);
var filter_attrs = std.ArrayListUnmanaged(Attribute){}; var filter_attrs = std.ArrayList(Attribute){};
if (self.peek().type == .start_attributes) { if (self.peek().type == .start_attributes) {
filter_attrs = try self.attrs(null); filter_attrs = try self.attrs(null);
@@ -1115,7 +1115,7 @@ pub const Parser = struct {
fn parseFilter(self: *Parser) !*Node { fn parseFilter(self: *Parser) !*Node {
const tok = try self.expect(.filter); const tok = try self.expect(.filter);
var filter_attrs = std.ArrayListUnmanaged(Attribute){}; var filter_attrs = std.ArrayList(Attribute){};
if (self.peek().type == .start_attributes) { if (self.peek().type == .start_attributes) {
filter_attrs = try self.attrs(null); filter_attrs = try self.attrs(null);
@@ -1483,11 +1483,11 @@ pub const Parser = struct {
fn tag_(self: *Parser, tag: *Node, self_closing_allowed: bool) !void { fn tag_(self: *Parser, tag: *Node, self_closing_allowed: bool) !void {
var seen_attrs = false; var seen_attrs = false;
var attribute_names = std.ArrayListUnmanaged([]const u8){}; var attribute_names = std.ArrayList([]const u8){};
defer attribute_names.deinit(self.allocator); defer attribute_names.deinit(self.allocator);
// Collect class values to merge into single attribute // Collect class values to merge into single attribute
var class_values = std.ArrayListUnmanaged([]const u8){}; var class_values = std.ArrayList([]const u8){};
defer class_values.deinit(self.allocator); defer class_values.deinit(self.allocator);
var class_line: usize = 0; var class_line: usize = 0;
var class_column: usize = 0; var class_column: usize = 0;
@@ -1689,10 +1689,10 @@ pub const Parser = struct {
} }
} }
fn attrs(self: *Parser, attribute_names: ?*std.ArrayListUnmanaged([]const u8)) !std.ArrayListUnmanaged(Attribute) { fn attrs(self: *Parser, attribute_names: ?*std.ArrayList([]const u8)) !std.ArrayList(Attribute) {
_ = try self.expect(.start_attributes); _ = try self.expect(.start_attributes);
var result = std.ArrayListUnmanaged(Attribute){}; var result = std.ArrayList(Attribute){};
var tok = self.advance(); var tok = self.advance();
while (tok.type == .attribute) { while (tok.type == .attribute) {

View File

@@ -1,7 +1,7 @@
const std = @import("std"); const std = @import("std");
const mem = std.mem; const mem = std.mem;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const ArrayListUnmanaged = std.ArrayListUnmanaged; const ArrayList = std.ArrayList;
// ============================================================================ // ============================================================================
// Pug Runtime - HTML generation utilities // Pug Runtime - HTML generation utilities
@@ -45,7 +45,7 @@ pub fn escape(allocator: Allocator, html: []const u8) ![]const u8 {
return try allocator.dupe(u8, html); return try allocator.dupe(u8, html);
} }
var result: ArrayListUnmanaged(u8) = .{}; var result: ArrayList(u8) = .{};
errdefer result.deinit(allocator); errdefer result.deinit(allocator);
for (html) |c| { for (html) |c| {
@@ -84,7 +84,7 @@ pub fn style(allocator: Allocator, val: StyleValue) ![]const u8 {
return try allocator.dupe(u8, s); return try allocator.dupe(u8, s);
}, },
.object => |props| { .object => |props| {
var result: ArrayListUnmanaged(u8) = .{}; var result: ArrayList(u8) = .{};
errdefer result.deinit(allocator); errdefer result.deinit(allocator);
for (props) |prop| { for (props) |prop| {
@@ -111,7 +111,7 @@ pub const AttrValue = union(enum) {
/// Returns empty string for false/null values. /// Returns empty string for false/null values.
/// For true values, returns terse form " key" or full form " key="key"". /// For true values, returns terse form " key" or full form " key="key"".
pub fn attr(allocator: Allocator, key: []const u8, val: AttrValue, escaped: bool, terse: bool) ![]const u8 { pub fn attr(allocator: Allocator, key: []const u8, val: AttrValue, escaped: bool, terse: bool) ![]const u8 {
var result: ArrayListUnmanaged(u8) = .{}; var result: ArrayList(u8) = .{};
errdefer result.deinit(allocator); errdefer result.deinit(allocator);
try appendAttr(allocator, &result, key, val, escaped, terse); try appendAttr(allocator, &result, key, val, escaped, terse);
if (result.items.len == 0) { if (result.items.len == 0) {
@@ -122,7 +122,7 @@ pub fn attr(allocator: Allocator, key: []const u8, val: AttrValue, escaped: bool
/// Append attribute directly to output buffer - avoids intermediate allocations /// Append attribute directly to output buffer - avoids intermediate allocations
/// This is the preferred method for rendering attributes in hot paths /// This is the preferred method for rendering attributes in hot paths
pub fn appendAttr(allocator: Allocator, output: *ArrayListUnmanaged(u8), key: []const u8, val: AttrValue, escaped: bool, terse: bool) !void { pub fn appendAttr(allocator: Allocator, output: *ArrayList(u8), key: []const u8, val: AttrValue, escaped: bool, terse: bool) !void {
switch (val) { switch (val) {
.none => return, .none => return,
.boolean => |b| { .boolean => |b| {
@@ -186,7 +186,7 @@ pub const ClassCondition = struct {
/// Arrays are flattened, objects include keys with truthy values. /// Arrays are flattened, objects include keys with truthy values.
/// Optimized to minimize allocations by writing directly to result buffer. /// Optimized to minimize allocations by writing directly to result buffer.
pub fn classes(allocator: Allocator, val: ClassValue, escaping: ?[]const bool) ![]const u8 { pub fn classes(allocator: Allocator, val: ClassValue, escaping: ?[]const bool) ![]const u8 {
var result: ArrayListUnmanaged(u8) = .{}; var result: ArrayList(u8) = .{};
errdefer result.deinit(allocator); errdefer result.deinit(allocator);
try classesInternal(allocator, val, escaping, &result, 0); try classesInternal(allocator, val, escaping, &result, 0);
@@ -204,7 +204,7 @@ fn classesInternal(
allocator: Allocator, allocator: Allocator,
val: ClassValue, val: ClassValue,
escaping: ?[]const bool, escaping: ?[]const bool,
result: *ArrayListUnmanaged(u8), result: *ArrayList(u8),
depth: usize, depth: usize,
) !void { ) !void {
switch (val) { switch (val) {
@@ -236,7 +236,7 @@ fn classesInternal(
const had_content = start_len > 0; const had_content = start_len > 0;
// Temporarily collect the class string // Temporarily collect the class string
var temp: ArrayListUnmanaged(u8) = .{}; var temp: ArrayList(u8) = .{};
defer temp.deinit(allocator); defer temp.deinit(allocator);
try classesInternal(allocator, item, null, &temp, depth + 1); try classesInternal(allocator, item, null, &temp, depth + 1);
@@ -256,7 +256,7 @@ fn classesInternal(
/// Append escaped HTML directly to result buffer (avoids intermediate allocation) /// Append escaped HTML directly to result buffer (avoids intermediate allocation)
/// Public for use by codegen and other modules /// Public for use by codegen and other modules
pub fn appendEscaped(allocator: Allocator, result: *ArrayListUnmanaged(u8), html: []const u8) !void { pub fn appendEscaped(allocator: Allocator, result: *ArrayList(u8), html: []const u8) !void {
for (html) |c| { for (html) |c| {
if (escapeChar(c)) |escaped| { if (escapeChar(c)) |escaped| {
try result.appendSlice(allocator, escaped); try result.appendSlice(allocator, escaped);
@@ -350,7 +350,7 @@ pub fn isHtmlEntity(str: []const u8) bool {
/// Escape for text content - escapes < > & (NOT quotes) /// Escape for text content - escapes < > & (NOT quotes)
/// Preserves existing HTML entities like &#8217; or &amp; /// Preserves existing HTML entities like &#8217; or &amp;
/// Shared across codegen.zig and template.zig. /// Shared across codegen.zig and template.zig.
pub fn appendTextEscaped(allocator: Allocator, output: *ArrayListUnmanaged(u8), str: []const u8) Allocator.Error!void { pub fn appendTextEscaped(allocator: Allocator, output: *ArrayList(u8), str: []const u8) Allocator.Error!void {
var i: usize = 0; var i: usize = 0;
while (i < str.len) { while (i < str.len) {
const c = str[i]; const c = str[i];
@@ -396,7 +396,7 @@ pub const AttrEntry = struct {
/// Render multiple attributes. /// Render multiple attributes.
/// Class attributes are processed specially and placed first. /// Class attributes are processed specially and placed first.
pub fn attrs(allocator: Allocator, entries: []const AttrEntry, terse: bool) ![]const u8 { pub fn attrs(allocator: Allocator, entries: []const AttrEntry, terse: bool) ![]const u8 {
var result: ArrayListUnmanaged(u8) = .{}; var result: ArrayList(u8) = .{};
errdefer result.deinit(allocator); errdefer result.deinit(allocator);
// First pass: find and render class attribute // First pass: find and render class attribute
@@ -459,7 +459,7 @@ pub const MergedValue = struct {
key: []const u8, key: []const u8,
value: MergeValue, value: MergeValue,
allocator: Allocator, allocator: Allocator,
owned_strings: ArrayListUnmanaged([]const u8), owned_strings: ArrayList([]const u8),
pub fn deinit(self: *MergedValue) void { pub fn deinit(self: *MergedValue) void {
for (self.owned_strings.items) |s| { for (self.owned_strings.items) |s| {
@@ -474,7 +474,7 @@ fn ensureTrailingSemicolon(allocator: Allocator, s: []const u8) ![]const u8 {
if (s.len == 0) return try allocator.dupe(u8, ""); if (s.len == 0) return try allocator.dupe(u8, "");
if (s[s.len - 1] == ';') return try allocator.dupe(u8, s); if (s[s.len - 1] == ';') return try allocator.dupe(u8, s);
var result: ArrayListUnmanaged(u8) = .{}; var result: ArrayList(u8) = .{};
errdefer result.deinit(allocator); errdefer result.deinit(allocator);
try result.appendSlice(allocator, s); try result.appendSlice(allocator, s);
try result.append(allocator, ';'); try result.append(allocator, ';');
@@ -495,9 +495,9 @@ fn styleToString(allocator: Allocator, val: StyleValue) ![]const u8 {
/// Merged attributes result with O(1) lookups for class/style /// Merged attributes result with O(1) lookups for class/style
pub const MergedAttrs = struct { pub const MergedAttrs = struct {
allocator: Allocator, allocator: Allocator,
entries: ArrayListUnmanaged(MergedAttrEntry), entries: ArrayList(MergedAttrEntry),
owned_strings: ArrayListUnmanaged([]const u8), owned_strings: ArrayList([]const u8),
owned_class_arrays: ArrayListUnmanaged([][]const u8), owned_class_arrays: ArrayList([][]const u8),
// O(1) index tracking for special keys // O(1) index tracking for special keys
class_idx: ?usize = null, class_idx: ?usize = null,
style_idx: ?usize = null, style_idx: ?usize = null,
@@ -751,7 +751,7 @@ fn mergeStyleValue(result: *MergedAttrs, idx: usize, value: MergedAttrValue) !vo
const s2 = try ensureTrailingSemicolon(allocator, s); const s2 = try ensureTrailingSemicolon(allocator, s);
defer allocator.free(s2); defer allocator.free(s2);
var combined: ArrayListUnmanaged(u8) = .{}; var combined: ArrayList(u8) = .{};
errdefer combined.deinit(allocator); errdefer combined.deinit(allocator);
try combined.appendSlice(allocator, s1); try combined.appendSlice(allocator, s1);
try combined.appendSlice(allocator, s2); try combined.appendSlice(allocator, s2);
@@ -842,7 +842,7 @@ pub const PugError = struct {
}; };
fn formatErrorMessage(allocator: Allocator, err_message: []const u8, filename: ?[]const u8, line: usize, src: []const u8) ![]const u8 { fn formatErrorMessage(allocator: Allocator, err_message: []const u8, filename: ?[]const u8, line: usize, src: []const u8) ![]const u8 {
var result: ArrayListUnmanaged(u8) = .{}; var result: ArrayList(u8) = .{};
errdefer result.deinit(allocator); errdefer result.deinit(allocator);
// Add filename and line // Add filename and line

View File

@@ -44,7 +44,7 @@ pub const StripCommentsError = error{
// ============================================================================ // ============================================================================
pub const StripCommentsResult = struct { pub const StripCommentsResult = struct {
tokens: std.ArrayListUnmanaged(Token), tokens: std.ArrayList(Token),
err: ?PugError = null, err: ?PugError = null,
pub fn deinit(self: *StripCommentsResult, allocator: Allocator) void { pub fn deinit(self: *StripCommentsResult, allocator: Allocator) void {

View File

@@ -97,7 +97,7 @@ pub fn renderWithData(allocator: Allocator, source: []const u8, data: anytype) !
/// Render a pre-parsed AST with data. Use this for better performance when /// Render a pre-parsed AST with data. Use this for better performance when
/// rendering the same template multiple times - parse once, render many. /// rendering the same template multiple times - parse once, render many.
pub fn renderAst(allocator: Allocator, ast: *Node, data: anytype) ![]const u8 { pub fn renderAst(allocator: Allocator, ast: *Node, data: anytype) ![]const u8 {
var output = std.ArrayListUnmanaged(u8){}; var output = std.ArrayList(u8){};
errdefer output.deinit(allocator); errdefer output.deinit(allocator);
// Detect doctype to set terse mode // Detect doctype to set terse mode
@@ -122,7 +122,7 @@ pub fn renderAstWithMixins(allocator: Allocator, ast: *Node, data: anytype, regi
/// Render a pre-parsed AST with data, mixin registry, and render options. /// Render a pre-parsed AST with data, mixin registry, and render options.
pub fn renderAstWithMixinsAndOptions(allocator: Allocator, ast: *Node, data: anytype, registry: *const MixinRegistry, options: RenderOptions) ![]const u8 { pub fn renderAstWithMixinsAndOptions(allocator: Allocator, ast: *Node, data: anytype, registry: *const MixinRegistry, options: RenderOptions) ![]const u8 {
var output = std.ArrayListUnmanaged(u8){}; var output = std.ArrayList(u8){};
errdefer output.deinit(allocator); errdefer output.deinit(allocator);
// Detect doctype to set terse mode // Detect doctype to set terse mode
@@ -213,14 +213,14 @@ fn detectDoctype(node: *Node, ctx: *RenderContext) void {
const whitespace_sensitive_tags = runtime.whitespace_sensitive_tags; const whitespace_sensitive_tags = runtime.whitespace_sensitive_tags;
/// Write indentation (two spaces per level) /// Write indentation (two spaces per level)
fn writeIndent(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), level: u32) Allocator.Error!void { fn writeIndent(allocator: Allocator, output: *std.ArrayList(u8), level: u32) Allocator.Error!void {
var i: u32 = 0; var i: u32 = 0;
while (i < level) : (i += 1) { while (i < level) : (i += 1) {
try output.appendSlice(allocator, " "); try output.appendSlice(allocator, " ");
} }
} }
fn renderNode(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), node: *Node, data: anytype, ctx: *const RenderContext) Allocator.Error!void { fn renderNode(allocator: Allocator, output: *std.ArrayList(u8), node: *Node, data: anytype, ctx: *const RenderContext) Allocator.Error!void {
switch (node.type) { switch (node.type) {
.Block, .NamedBlock => { .Block, .NamedBlock => {
for (node.nodes.items) |child| { for (node.nodes.items) |child| {
@@ -251,7 +251,7 @@ fn renderNode(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), node: *
} }
} }
fn renderTag(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), tag: *Node, data: anytype, ctx: *const RenderContext) Allocator.Error!void { fn renderTag(allocator: Allocator, output: *std.ArrayList(u8), tag: *Node, data: anytype, ctx: *const RenderContext) Allocator.Error!void {
const name = tag.name orelse "div"; const name = tag.name orelse "div";
const is_whitespace_sensitive = whitespace_sensitive_tags.has(name); const is_whitespace_sensitive = whitespace_sensitive_tags.has(name);
@@ -393,13 +393,13 @@ fn evaluateAttrValue(allocator: Allocator, val: ?[]const u8, data: anytype) !run
return .{ .string = v }; return .{ .string = v };
} }
fn renderText(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), text: *Node, data: anytype) Allocator.Error!void { fn renderText(allocator: Allocator, output: *std.ArrayList(u8), text: *Node, data: anytype) Allocator.Error!void {
if (text.val) |val| { if (text.val) |val| {
try processInterpolation(allocator, output, val, false, data); try processInterpolation(allocator, output, val, false, data);
} }
} }
fn renderCode(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), code: *Node, data: anytype, ctx: *const RenderContext) Allocator.Error!void { fn renderCode(allocator: Allocator, output: *std.ArrayList(u8), code: *Node, data: anytype, ctx: *const RenderContext) Allocator.Error!void {
if (code.buffer) { if (code.buffer) {
if (code.val) |val| { if (code.val) |val| {
// Check if it's a string literal (quoted) // Check if it's a string literal (quoted)
@@ -441,7 +441,7 @@ fn renderCode(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), code: *
} }
/// Render mixin definition or call /// Render mixin definition or call
fn renderMixin(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), node: *Node, data: anytype, ctx: *const RenderContext) Allocator.Error!void { fn renderMixin(allocator: Allocator, output: *std.ArrayList(u8), node: *Node, data: anytype, ctx: *const RenderContext) Allocator.Error!void {
// Mixin definitions are skipped (only mixin calls render) // Mixin definitions are skipped (only mixin calls render)
if (!node.call) return; if (!node.call) return;
@@ -494,7 +494,7 @@ fn bindMixinArguments(
bindings: *std.StringHashMapUnmanaged([]const u8), bindings: *std.StringHashMapUnmanaged([]const u8),
) !void { ) !void {
// Parse parameter names from definition: "text, type" or "text, type='primary'" // Parse parameter names from definition: "text, type" or "text, type='primary'"
var param_names = std.ArrayListUnmanaged([]const u8){}; var param_names = std.ArrayList([]const u8){};
defer param_names.deinit(allocator); defer param_names.deinit(allocator);
var param_iter = std.mem.splitSequence(u8, params, ","); var param_iter = std.mem.splitSequence(u8, params, ",");
@@ -517,7 +517,7 @@ fn bindMixinArguments(
} }
// Parse argument values from call: "'Click', 'primary'" or "text='Click'" // Parse argument values from call: "'Click', 'primary'" or "text='Click'"
var arg_values = std.ArrayListUnmanaged([]const u8){}; var arg_values = std.ArrayList([]const u8){};
defer arg_values.deinit(allocator); defer arg_values.deinit(allocator);
// Simple argument parsing - split by comma but respect quotes // Simple argument parsing - split by comma but respect quotes
@@ -572,7 +572,7 @@ fn stripQuotes(val: []const u8) []const u8 {
return val; return val;
} }
fn renderEach(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), each: *Node, data: anytype, ctx: *const RenderContext) Allocator.Error!void { fn renderEach(allocator: Allocator, output: *std.ArrayList(u8), each: *Node, data: anytype, ctx: *const RenderContext) Allocator.Error!void {
const collection_name = each.obj orelse return; const collection_name = each.obj orelse return;
const item_name = each.val orelse "item"; const item_name = each.val orelse "item";
_ = item_name; _ = item_name;
@@ -623,7 +623,7 @@ fn renderEach(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), each: *
} }
} }
fn renderNodeWithItem(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), node: *Node, data: anytype, item: []const u8, ctx: *const RenderContext) Allocator.Error!void { fn renderNodeWithItem(allocator: Allocator, output: *std.ArrayList(u8), node: *Node, data: anytype, item: []const u8, ctx: *const RenderContext) Allocator.Error!void {
switch (node.type) { switch (node.type) {
.Block, .NamedBlock => { .Block, .NamedBlock => {
for (node.nodes.items) |child| { for (node.nodes.items) |child| {
@@ -649,7 +649,7 @@ fn renderNodeWithItem(allocator: Allocator, output: *std.ArrayListUnmanaged(u8),
} }
} }
fn renderTagWithItem(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), tag: *Node, data: anytype, item: []const u8, ctx: *const RenderContext) Allocator.Error!void { fn renderTagWithItem(allocator: Allocator, output: *std.ArrayList(u8), tag: *Node, data: anytype, item: []const u8, ctx: *const RenderContext) Allocator.Error!void {
const name = tag.name orelse "div"; const name = tag.name orelse "div";
try output.appendSlice(allocator, "<"); try output.appendSlice(allocator, "<");
@@ -698,14 +698,14 @@ fn renderTagWithItem(allocator: Allocator, output: *std.ArrayListUnmanaged(u8),
} }
} }
fn renderTextWithItem(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), text: *Node, item: []const u8) Allocator.Error!void { fn renderTextWithItem(allocator: Allocator, output: *std.ArrayList(u8), text: *Node, item: []const u8) Allocator.Error!void {
if (text.val) |val| { if (text.val) |val| {
try runtime.appendEscaped(allocator, output, val); try runtime.appendEscaped(allocator, output, val);
_ = item; _ = item;
} }
} }
fn processInterpolationWithItem(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), text: []const u8, escape: bool, data: anytype, item: []const u8) Allocator.Error!void { fn processInterpolationWithItem(allocator: Allocator, output: *std.ArrayList(u8), text: []const u8, escape: bool, data: anytype, item: []const u8) Allocator.Error!void {
_ = data; _ = data;
var i: usize = 0; var i: usize = 0;
while (i < text.len) { while (i < text.len) {
@@ -740,7 +740,7 @@ fn processInterpolationWithItem(allocator: Allocator, output: *std.ArrayListUnma
} }
} }
fn renderComment(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), comment: *Node) Allocator.Error!void { fn renderComment(allocator: Allocator, output: *std.ArrayList(u8), comment: *Node) Allocator.Error!void {
if (!comment.buffer) return; if (!comment.buffer) return;
try output.appendSlice(allocator, "<!--"); try output.appendSlice(allocator, "<!--");
if (comment.val) |val| { if (comment.val) |val| {
@@ -749,7 +749,7 @@ fn renderComment(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), comm
try output.appendSlice(allocator, "-->"); try output.appendSlice(allocator, "-->");
} }
fn renderBlockComment(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), comment: *Node, data: anytype, ctx: *const RenderContext) Allocator.Error!void { fn renderBlockComment(allocator: Allocator, output: *std.ArrayList(u8), comment: *Node, data: anytype, ctx: *const RenderContext) Allocator.Error!void {
if (!comment.buffer) return; if (!comment.buffer) return;
try output.appendSlice(allocator, "<!--"); try output.appendSlice(allocator, "<!--");
if (comment.val) |val| { if (comment.val) |val| {
@@ -765,7 +765,7 @@ fn renderBlockComment(allocator: Allocator, output: *std.ArrayListUnmanaged(u8),
// Import doctypes from runtime (shared with codegen) // Import doctypes from runtime (shared with codegen)
const doctypes = runtime.doctypes; const doctypes = runtime.doctypes;
fn renderDoctype(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), doctype: *Node) Allocator.Error!void { fn renderDoctype(allocator: Allocator, output: *std.ArrayList(u8), doctype: *Node) Allocator.Error!void {
if (doctype.val) |val| { if (doctype.val) |val| {
if (doctypes.get(val)) |dt| { if (doctypes.get(val)) |dt| {
try output.appendSlice(allocator, dt); try output.appendSlice(allocator, dt);
@@ -781,7 +781,7 @@ fn renderDoctype(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), doct
/// Process interpolation #{expr} in text /// Process interpolation #{expr} in text
/// escape_quotes: true for attribute values (escape "), false for text content /// escape_quotes: true for attribute values (escape "), false for text content
fn processInterpolation(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), text: []const u8, escape_quotes: bool, data: anytype) Allocator.Error!void { fn processInterpolation(allocator: Allocator, output: *std.ArrayList(u8), text: []const u8, escape_quotes: bool, data: anytype) Allocator.Error!void {
var i: usize = 0; var i: usize = 0;
while (i < text.len) { while (i < text.len) {
if (i + 1 < text.len and text[i] == '#' and text[i + 1] == '{') { if (i + 1 < text.len and text[i] == '#' and text[i + 1] == '{') {
@@ -867,7 +867,7 @@ fn getFieldValue(data: anytype, name: []const u8) ?[]const u8 {
/// Escape for text content - escapes < > & (NOT quotes) /// Escape for text content - escapes < > & (NOT quotes)
/// Preserves existing HTML entities like &#8217; /// Preserves existing HTML entities like &#8217;
/// Uses shared appendTextEscaped from runtime.zig. /// Uses shared appendTextEscaped from runtime.zig.
fn appendTextEscaped(allocator: Allocator, output: *std.ArrayListUnmanaged(u8), str: []const u8) Allocator.Error!void { fn appendTextEscaped(allocator: Allocator, output: *std.ArrayList(u8), str: []const u8) Allocator.Error!void {
try runtime.appendTextEscaped(allocator, output, str); try runtime.appendTextEscaped(allocator, output, str);
} }

View File

@@ -7,7 +7,7 @@ const pugz = @import("pugz");
/// Normalizes HTML by removing indentation/formatting whitespace. /// Normalizes HTML by removing indentation/formatting whitespace.
/// This allows comparing pretty vs non-pretty output. /// This allows comparing pretty vs non-pretty output.
pub fn normalizeHtml(allocator: std.mem.Allocator, html: []const u8) ![]const u8 { pub fn normalizeHtml(allocator: std.mem.Allocator, html: []const u8) ![]const u8 {
var result = std.ArrayListUnmanaged(u8){}; var result = std.ArrayList(u8){};
var i: usize = 0; var i: usize = 0;
var in_tag = false; var in_tag = false;
var last_was_space = false; var last_was_space = false;

View File

@@ -97,7 +97,7 @@ const ParsedTokens = struct {
}; };
fn parseJsonTokens(allocator: std.mem.Allocator, json_content: []const u8) !ParsedTokens { fn parseJsonTokens(allocator: std.mem.Allocator, json_content: []const u8) !ParsedTokens {
var tokens = std.ArrayListUnmanaged(Token){}; var tokens = std.ArrayList(Token){};
errdefer tokens.deinit(allocator); errdefer tokens.deinit(allocator);
// Use an arena allocator to keep JSON string data alive // Use an arena allocator to keep JSON string data alive
@@ -257,8 +257,8 @@ const TokenTestCase = struct {
} }
}; };
fn loadTokenTestCases(allocator: std.mem.Allocator, dir_path: []const u8) !std.ArrayListUnmanaged(TokenTestCase) { fn loadTokenTestCases(allocator: std.mem.Allocator, dir_path: []const u8) !std.ArrayList(TokenTestCase) {
var cases = std.ArrayListUnmanaged(TokenTestCase){}; var cases = std.ArrayList(TokenTestCase){};
errdefer { errdefer {
for (cases.items) |*c| c.deinit(); for (cases.items) |*c| c.deinit();
cases.deinit(allocator); cases.deinit(allocator);

View File

@@ -20,7 +20,7 @@ pub fn main() !void {
defer dir.close(); defer dir.close();
// Collect .pug files // Collect .pug files
var files = std.ArrayListUnmanaged([]const u8){}; var files = std.ArrayList([]const u8){};
defer { defer {
for (files.items) |f| allocator.free(f); for (files.items) |f| allocator.free(f);
files.deinit(allocator); files.deinit(allocator);

View File

@@ -4,7 +4,7 @@
const std = @import("std"); const std = @import("std");
/// Append HTML-escaped string to buffer /// Append HTML-escaped string to buffer
pub fn appendEscaped(buf: *std.ArrayListUnmanaged(u8), allocator: std.mem.Allocator, str: []const u8) !void { pub fn appendEscaped(buf: *std.ArrayList(u8), allocator: std.mem.Allocator, str: []const u8) !void {
for (str) |c| { for (str) |c| {
switch (c) { switch (c) {
'&' => try buf.appendSlice(allocator, "&amp;"), '&' => try buf.appendSlice(allocator, "&amp;"),
@@ -33,21 +33,21 @@ pub fn isTruthy(val: anytype) bool {
} }
/// Append an integer value to buffer (formatted as decimal string) /// Append an integer value to buffer (formatted as decimal string)
pub fn appendInt(buf: *std.ArrayListUnmanaged(u8), allocator: std.mem.Allocator, value: anytype) !void { pub fn appendInt(buf: *std.ArrayList(u8), allocator: std.mem.Allocator, value: anytype) !void {
var tmp: [32]u8 = undefined; var tmp: [32]u8 = undefined;
const str = std.fmt.bufPrint(&tmp, "{d}", .{value}) catch return; const str = std.fmt.bufPrint(&tmp, "{d}", .{value}) catch return;
try buf.appendSlice(allocator, str); try buf.appendSlice(allocator, str);
} }
/// Append a float value to buffer (formatted with 2 decimal places) /// Append a float value to buffer (formatted with 2 decimal places)
pub fn appendFloat(buf: *std.ArrayListUnmanaged(u8), allocator: std.mem.Allocator, value: anytype) !void { pub fn appendFloat(buf: *std.ArrayList(u8), allocator: std.mem.Allocator, value: anytype) !void {
var tmp: [64]u8 = undefined; var tmp: [64]u8 = undefined;
const str = std.fmt.bufPrint(&tmp, "{d:.2}", .{value}) catch return; const str = std.fmt.bufPrint(&tmp, "{d:.2}", .{value}) catch return;
try buf.appendSlice(allocator, str); try buf.appendSlice(allocator, str);
} }
/// Append any value to buffer (auto-detects type) /// Append any value to buffer (auto-detects type)
pub fn appendValue(buf: *std.ArrayListUnmanaged(u8), allocator: std.mem.Allocator, value: anytype) !void { pub fn appendValue(buf: *std.ArrayList(u8), allocator: std.mem.Allocator, value: anytype) !void {
const T = @TypeOf(value); const T = @TypeOf(value);
switch (@typeInfo(T)) { switch (@typeInfo(T)) {
.int, .comptime_int => try appendInt(buf, allocator, value), .int, .comptime_int => try appendInt(buf, allocator, value),

View File

@@ -239,14 +239,14 @@ fn copyHelpersZig(allocator: mem.Allocator, output_dir: []const u8) !void {
/// Generate root.zig that exports all compiled templates /// Generate root.zig that exports all compiled templates
fn generateRootZig(allocator: mem.Allocator, output_dir: []const u8, template_map: *std.StringHashMap([]const u8)) !void { fn generateRootZig(allocator: mem.Allocator, output_dir: []const u8, template_map: *std.StringHashMap([]const u8)) !void {
var output: std.ArrayListUnmanaged(u8) = .{}; var output: std.ArrayList(u8) = .{};
defer output.deinit(allocator); defer output.deinit(allocator);
try output.appendSlice(allocator, "// Auto-generated by pug-compile\n"); try output.appendSlice(allocator, "// Auto-generated by pug-compile\n");
try output.appendSlice(allocator, "// This file exports all compiled templates\n\n"); try output.appendSlice(allocator, "// This file exports all compiled templates\n\n");
// Sort template names for consistent output // Sort template names for consistent output
var names: std.ArrayListUnmanaged([]const u8) = .{}; var names: std.ArrayList([]const u8) = .{};
defer names.deinit(allocator); defer names.deinit(allocator);
var iter = template_map.keyIterator(); var iter = template_map.keyIterator();
@@ -298,7 +298,7 @@ fn generateRootZig(allocator: mem.Allocator, output_dir: []const u8, template_ma
/// Find all .pug files in a directory recursively /// Find all .pug files in a directory recursively
fn findPugFiles(allocator: mem.Allocator, dir_path: []const u8) ![][]const u8 { fn findPugFiles(allocator: mem.Allocator, dir_path: []const u8) ![][]const u8 {
var results: std.ArrayListUnmanaged([]const u8) = .{}; var results: std.ArrayList([]const u8) = .{};
errdefer { errdefer {
for (results.items) |item| allocator.free(item); for (results.items) |item| allocator.free(item);
results.deinit(allocator); results.deinit(allocator);
@@ -309,7 +309,7 @@ fn findPugFiles(allocator: mem.Allocator, dir_path: []const u8) ![][]const u8 {
return results.toOwnedSlice(allocator); return results.toOwnedSlice(allocator);
} }
fn findPugFilesRecursive(allocator: mem.Allocator, dir_path: []const u8, results: *std.ArrayListUnmanaged([]const u8)) !void { fn findPugFilesRecursive(allocator: mem.Allocator, dir_path: []const u8, results: *std.ArrayList([]const u8)) !void {
var dir = try fs.cwd().openDir(dir_path, .{ .iterate = true }); var dir = try fs.cwd().openDir(dir_path, .{ .iterate = true });
defer dir.close(); defer dir.close();
@@ -365,7 +365,7 @@ fn makeTemplateName(allocator: mem.Allocator, path: []const u8) ![]const u8 {
path; path;
// Replace / and - with _ // Replace / and - with _
var result: std.ArrayListUnmanaged(u8) = .{}; var result: std.ArrayList(u8) = .{};
defer result.deinit(allocator); defer result.deinit(allocator);
for (without_ext) |c| { for (without_ext) |c| {

View File

@@ -45,11 +45,11 @@ pub const TypeInfo = struct {
pub const Codegen = struct { pub const Codegen = struct {
allocator: Allocator, allocator: Allocator,
output: std.ArrayListUnmanaged(u8), output: std.ArrayList(u8),
indent_level: usize, indent_level: usize,
terse: bool, // HTML5 mode vs XHTML terse: bool, // HTML5 mode vs XHTML
// Buffer for combining consecutive static strings // Buffer for combining consecutive static strings
static_buffer: std.ArrayListUnmanaged(u8), static_buffer: std.ArrayList(u8),
// Type hints from @TypeOf annotations // Type hints from @TypeOf annotations
type_hints: std.StringHashMap(TypeInfo), type_hints: std.StringHashMap(TypeInfo),
// Current loop variable for field resolution inside each blocks // Current loop variable for field resolution inside each blocks
@@ -141,7 +141,7 @@ pub const Codegen = struct {
// Initialize buffer // Initialize buffer
try self.writeIndent(); try self.writeIndent();
try self.writeLine("var buf: std.ArrayListUnmanaged(u8) = .{};"); try self.writeLine("var buf: std.ArrayList(u8) = .{};");
try self.writeIndent(); try self.writeIndent();
try self.writeLine("defer buf.deinit(allocator);"); try self.writeLine("defer buf.deinit(allocator);");
@@ -797,7 +797,7 @@ pub fn extractFieldNames(allocator: Allocator, ast: *Node) ![][]const u8 {
try extractFieldNamesRecursive(ast, &fields, &loop_vars); try extractFieldNamesRecursive(ast, &fields, &loop_vars);
// Convert to sorted slice and sanitize field names // Convert to sorted slice and sanitize field names
var result: std.ArrayListUnmanaged([]const u8) = .{}; var result: std.ArrayList([]const u8) = .{};
errdefer { errdefer {
for (result.items) |item| allocator.free(item); for (result.items) |item| allocator.free(item);
result.deinit(allocator); result.deinit(allocator);

View File

@@ -311,7 +311,7 @@ pub const ViewEngine = struct {
// Normalize the path (resolve ".." and ".") // Normalize the path (resolve ".." and ".")
// We need to handle this manually since std.fs.path.resolve needs absolute paths // We need to handle this manually since std.fs.path.resolve needs absolute paths
var components = std.ArrayListUnmanaged([]const u8){}; var components = std.ArrayList([]const u8){};
defer components.deinit(allocator); defer components.deinit(allocator);
var iter = std.mem.splitScalar(u8, joined, '/'); var iter = std.mem.splitScalar(u8, joined, '/');

View File

@@ -19,7 +19,7 @@ pub const WalkOptions = struct {
/// Include dependencies (traverse into FileReference.ast if present) /// Include dependencies (traverse into FileReference.ast if present)
include_dependencies: bool = false, include_dependencies: bool = false,
/// Parent node stack (managed internally during walk) /// Parent node stack (managed internally during walk)
parents: std.ArrayListUnmanaged(*Node) = .{}, parents: std.ArrayList(*Node) = .{},
pub fn deinit(self: *WalkOptions, allocator: Allocator) void { pub fn deinit(self: *WalkOptions, allocator: Allocator) void {
self.parents.deinit(allocator); self.parents.deinit(allocator);
@@ -359,7 +359,7 @@ fn visitChildren(
/// Walk a list of nodes and merge results (handling array replacements) /// Walk a list of nodes and merge results (handling array replacements)
fn walkAndMergeNodes( fn walkAndMergeNodes(
allocator: Allocator, allocator: Allocator,
nodes: *std.ArrayListUnmanaged(*Node), nodes: *std.ArrayList(*Node),
before: ?BeforeCallback, before: ?BeforeCallback,
after: ?AfterCallback, after: ?AfterCallback,
options: *WalkOptions, options: *WalkOptions,
@@ -484,9 +484,9 @@ pub fn collectNodes(
allocator: Allocator, allocator: Allocator,
ast: *Node, ast: *Node,
node_type: NodeType, node_type: NodeType,
) WalkError!std.ArrayListUnmanaged(*Node) { ) WalkError!std.ArrayList(*Node) {
const Collector = struct { const Collector = struct {
collected: std.ArrayListUnmanaged(*Node) = .{}, collected: std.ArrayList(*Node) = .{},
alloc: Allocator, alloc: Allocator,
target_type: NodeType, target_type: NodeType,