1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
const Self = @This();
pub const Content = union(enum) {
elements: []const Self,
string: []const u8,
void: void,
pub fn content(string: []const u8) @This() {
return .{ .string = string };
}
pub fn children(elements: []const Self) @This() {
return .{ .elements = elements };
}
};
pub const Attribute = struct {
name: []const u8,
value: []const u8,
};
tag: []const u8,
attributes: []const Attribute,
content: Content,
fn attributesFrom(attributes: anytype) []const Attribute {
const T = @TypeOf(attributes);
const info = @typeInfo(T);
if (info != .@"struct") {
@compileError("struct needed");
}
const fields = info.@"struct".fields;
var attrs: []const Attribute = &.{};
for (fields) |field| {
const name = field.name;
const value = @field(attributes, name);
const next_attr: []const Attribute = &.{ .{ .name = name, .value = value } };
attrs = attrs ++ next_attr;
}
return attrs;
}
pub fn native(name: @EnumLiteral(), attrs: anytype, content: Content) Self {
return .{
.tag = @tagName(name),
.attributes = attributesFrom(attrs),
.content = content,
};
}
pub fn transparent(content: Content) Self {
return .{
.tag = "",
.attributes = &.{},
.content = content,
};
}
pub fn toHtml(comptime self: Self) []const u8 {
var string: []const u8 = string: {
if (self.tag.len == 0) {
break :string "";
}
var string: []const u8 = "<" ++ self.tag;
inline for (self.attributes) |attr| {
string = string ++ " " ++ attr.name ++ "='" ++ attr.value ++ "'";
}
string = string ++ ">";
break :string string;
};
switch (self.content) {
.void => {},
.string => |s| {
string = string ++ s ++ "</" ++ self.tag ++ ">";
},
.elements => |els| {
for (els) |el| {
string = string ++ el.toHtml();
}
string = string ++ "</" ++ self.tag ++ ">";
}
}
string = string ++ if (self.tag.len == 0) "" else "</" ++ self.tag ++ ">";
return string;
}
pub fn toDocument(comptime self: Self) []const u8 {
return "<!DOCTYPE html>" ++ self.toHtml();
}
|