fix: merge multiple class attributes in zig_codegen (compiled templates)

- zig_codegen.zig: collect and merge class values in both static and dynamic attribute paths
- Completes the fix for multiple classes (.a.b -> class="a b") across all rendering modes
This commit is contained in:
2026-01-29 22:11:38 +05:30
parent 416ddf5b33
commit c3156f88bd
2 changed files with 64 additions and 10 deletions

View File

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

View File

@@ -224,28 +224,69 @@ pub const Codegen = struct {
if (!has_dynamic_attrs) {
// All static attributes - include in buffer
// Collect class values to merge into single attribute
var class_values = std.ArrayListUnmanaged([]const u8){};
defer class_values.deinit(self.allocator);
for (tag.attrs.items) |attr| {
try self.addStatic(" ");
try self.addStatic(attr.name);
if (attr.val) |val| {
try self.addStatic("=\"");
try self.addStatic(val);
try self.addStatic("\"");
if (std.mem.eql(u8, attr.name, "class")) {
// Collect class values for merging
if (attr.val) |val| {
if (val.len > 0) {
try class_values.append(self.allocator, val);
}
}
} else {
// Boolean attribute
if (!self.terse) {
try self.addStatic(" ");
try self.addStatic(attr.name);
if (attr.val) |val| {
try self.addStatic("=\"");
try self.addStatic(attr.name);
try self.addStatic(val);
try self.addStatic("\"");
} else {
// Boolean attribute
if (!self.terse) {
try self.addStatic("=\"");
try self.addStatic(attr.name);
try self.addStatic("\"");
}
}
}
}
// Output merged class attribute
if (class_values.items.len > 0) {
try self.addStatic(" class=\"");
for (class_values.items, 0..) |class_val, i| {
if (i > 0) {
try self.addStatic(" ");
}
try self.addStatic(class_val);
}
try self.addStatic("\"");
}
try self.addStatic(">");
} else {
// Flush static content before dynamic attributes (this closes any open string)
try self.flushStaticBuffer();
// Collect static class values for merging
var static_class_values = std.ArrayListUnmanaged([]const u8){};
defer static_class_values.deinit(self.allocator);
// First pass: output non-class attributes
for (tag.attrs.items) |attr| {
// Skip class attributes - handle them separately
if (std.mem.eql(u8, attr.name, "class")) {
if (attr.val) |val| {
if (val.len > 0) {
try static_class_values.append(self.allocator, val);
}
}
continue;
}
if (attr.val) |val| {
// Quoted values are always static, unquoted can be field references
if (!attr.quoted and self.isDataFieldReference(val)) {
@@ -303,6 +344,19 @@ pub const Codegen = struct {
}
}
// Output merged class attribute
if (static_class_values.items.len > 0) {
try self.writeIndent();
try self.write("try buf.appendSlice(allocator, \" class=\\\"");
for (static_class_values.items, 0..) |class_val, i| {
if (i > 0) {
try self.write(" ");
}
try self.writeEscaped(class_val);
}
try self.writeLine("\\\"\");");
}
try self.writeIndent();
try self.writeLine("try buf.appendSlice(allocator, \">\");");
}