Makko, the people-oriented static site generator made for blogging.
forge.starlightnet.work/Team/Makko
ssg
static-site-generator
makko
starlight-network
1const std = @import("std");
2const datetime = @import("datetime");
3
4const helper = @import("helper.zig");
5const Data = @import("Data.zig");
6const Makko = @import("Makko.zig");
7
8const FeedGenerator = @This();
9
10name: []const u8,
11func: fn (Makko, data: Data, writer: anytype) anyerror!void,
12
13pub const generator_list = [_]FeedGenerator{
14 .{ .func = html, .name = "html" },
15 .{ .func = rss, .name = "rss" },
16 .{ .func = atom, .name = "atom" },
17};
18
19fn html(state: Makko, data: Data, writer: anytype) !void {
20 const allocator = state.allocator;
21
22 const json_data = try helper.valueToJson(allocator, data);
23 defer json_data.deinit();
24
25 if (state.templates.feed == null)
26 return error.MissingTemplate;
27
28 const first_pass = try helper.template(
29 allocator,
30 state.templates.feed.?,
31 json_data.value,
32 );
33 defer allocator.free(first_pass);
34
35 const second_pass = try helper.template(
36 allocator,
37 first_pass,
38 json_data.value,
39 );
40 defer allocator.free(second_pass);
41
42 try writer.writeAll(second_pass);
43}
44
45fn rss(state: Makko, data: Data, writer: anytype) !void {
46 const allocator = state.allocator;
47 const website = data.website;
48
49 const general_dt = datetime.datetime.Datetime.now();
50 const now_http = try general_dt.formatHttp(allocator);
51 defer allocator.free(now_http);
52
53 try writer.print(
54 \\<?xml version="1.0" encoding="UTF-8"?>
55 \\<rss version="2.0">
56 \\ <channel>
57 \\ <title>{s}</title>
58 \\ <link>{s}</link>
59 \\ <description>{s}</description>
60 \\ <generator>makko</generator>
61 \\ <lastBuildDate>{s}</lastBuildDate>
62 \\
63 ,
64 .{ website.title, website.url, website.description, now_http },
65 );
66
67 for (data.posts.?) |post| {
68 if (post.is_secret) continue;
69
70 const post_link = try std.mem.concat(
71 allocator,
72 u8,
73 &[_][]const u8{ website.url, "/", post.url },
74 );
75 defer allocator.free(post_link);
76
77 const dt = datetime.datetime.Datetime.fromTimestamp(post.created.raw);
78 const pub_date = try dt.formatHttp(allocator);
79 defer allocator.free(pub_date);
80
81 try writer.print(
82 \\ <item>
83 \\ <title>{s}</title>
84 \\ <link>{s}</link>
85 \\ <pubDate>{s}</pubDate>
86 \\ <author>{s}</author>
87 \\ <description>{s}</description>
88 \\ </item>
89 \\
90 ,
91 .{ post.title, post_link, pub_date, post.author, post.description },
92 );
93 }
94
95 try writer.writeAll(
96 \\ </channel>
97 \\</rss>
98 \\
99 );
100}
101
102fn atom(state: Makko, data: Data, writer: anytype) !void {
103 const allocator = state.allocator;
104
105 const now = datetime.datetime.Datetime.now();
106 const now_iso8601 = try now.formatISO8601(allocator, false);
107 defer allocator.free(now_iso8601);
108
109 const website = data.website;
110
111 try writer.print(
112 \\<?xml version="1.0" encoding="utf-8"?>
113 \\<feed xmlns="http://www.w3.org/2005/Atom">
114 \\ <title>{s}</title>
115 \\ <link href="{s}"/>
116 \\ <updated>{s}</updated>
117 \\ <id>{s}</id>
118 \\ <generator>makko</generator>
119 \\
120 ,
121 .{ website.title, website.url, now_iso8601, website.url },
122 );
123
124 for (data.posts.?) |post| {
125 if (post.is_secret) continue;
126
127 const post_link = try std.mem.concat(
128 allocator,
129 u8,
130 &[_][]const u8{ website.url, "/", post.url },
131 );
132 defer allocator.free(post_link);
133
134 const upd_dt = datetime.datetime.Datetime.fromTimestamp(post.updated.raw);
135 const upd_iso8601 = try upd_dt.formatISO8601(allocator, false);
136 defer state.allocator.free(upd_iso8601);
137
138 const pub_dt = datetime.datetime.Datetime.fromTimestamp(post.created.raw);
139 const pub_iso8601 = try pub_dt.formatISO8601(allocator, false);
140 defer state.allocator.free(pub_iso8601);
141
142 try writer.print(
143 \\ <entry>
144 \\ <title>{s}</title>
145 \\ <link href="{s}"/>
146 \\ <id>{s}</id>
147 \\ <published>{s}</published>
148 \\ <updated>{s}</updated>
149 \\ <author><name>{s}</name></author>
150 \\ <summary>{s}</summary>
151 \\ </entry>
152 \\
153 ,
154 .{
155 post.title,
156 post_link,
157 post_link, // use URL as unique ID
158 pub_iso8601,
159 upd_iso8601,
160 post.author,
161 post.description,
162 },
163 );
164 }
165
166 try writer.writeAll("</feed>\n");
167}