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:
@@ -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>");
|
||||||
|
|||||||
@@ -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, "&"),
|
'&' => try buf.appendSlice(allocator, "&"),
|
||||||
|
|||||||
@@ -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>");
|
||||||
|
|||||||
@@ -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>");
|
||||||
|
|||||||
@@ -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>");
|
||||||
|
|||||||
@@ -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>");
|
||||||
|
|||||||
@@ -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>");
|
||||||
|
|||||||
@@ -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>");
|
||||||
|
|||||||
@@ -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 = .{},
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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").?);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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 ’ or &
|
/// Preserves existing HTML entities like ’ or &
|
||||||
/// 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
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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 ’
|
/// Preserves existing HTML entities like ’
|
||||||
/// 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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, "&"),
|
'&' => try buf.appendSlice(allocator, "&"),
|
||||||
@@ -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),
|
||||||
|
|||||||
@@ -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| {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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, '/');
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user