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");
2
3////////////////////////////////////////////////////////
4// The following data structure has a bunch of aliased
5// data types specifically so it's easier to understand
6// for people with no experience in Zig, and perhaps
7// little to no experience programming.
8//
9// Please avoid complicated terminology unless it is
10// fully necessary.
11////////////////////////////////////////////////////////
12
13pub const Tag = struct {
14 name: []const u8,
15 posts: []Post,
16};
17
18pub const Time = struct {
19 raw: Integer,
20
21 year: Integer,
22 month: TwoDigits,
23 day: TwoDigits,
24
25 hour: TwoDigits,
26 minute: TwoDigits,
27 second: TwoDigits,
28};
29
30pub const Post = struct {
31 id: Id = 0,
32 is_secret: bool,
33
34 title: String,
35 description: String,
36 author: String,
37
38 // kebab-case list of tags
39 tags: []const String,
40
41 source: Path,
42 url: Path,
43
44 created: Time,
45 updated: Time,
46
47 body: ?String,
48};
49
50website: struct {
51 title: String,
52 description: String,
53 url: String,
54
55 feeds: struct {
56 html: ?Path = null,
57 rss: ?Path = null,
58 atom: ?Path = null,
59 },
60},
61
62pass: struct {
63 feed_template: Hash,
64 post_template: Hash,
65},
66
67// JSON Map of custom values
68custom: Value,
69
70// Only valid when processing individual posts
71post: ?Post = null,
72
73// Only valid when processing feeds.
74posts: ?[]Post = null,
75
76tags: []Tag,
77
78// Map of tag name to list of posts
79by_tag: Value,
80
81////////////////////////////////////////////////////////
82////////////////////////////////////////////////////////
83////////////////////////////////////////////////////////
84///////////// IMPLEMENTATION DETAILS ///////////////////
85
86const String = []const u8;
87const Path = String;
88const Integer = i64;
89const Float = f64;
90const ArbitraryData = std.json.Value;
91const Value = std.json.Value;
92const TwoDigits = [2]u8;
93
94pub const empty_time = std.mem.zeroes(Time);
95pub const Hash = Integer;
96pub const Id = Integer;
97
98const helper = @import("helper.zig");
99
100// TODO: Zig MUST have a function for this!!!!
101fn formatTwoDigits(n: u8) [2]u8 {
102 return if (n < 10)
103 [_]u8{ '0', '0' + n }
104 else
105 [_]u8{
106 '0' + @as(u8, @intCast(n / 10)),
107 '0' + @as(u8, @intCast(n % 10)),
108 };
109}
110
111pub fn timeFromTimestamp(now: i64) Time {
112 const Datetime = @import("datetime").datetime.Datetime;
113
114 var time: Time = undefined;
115
116 const e = Datetime.fromTimestamp(now);
117
118 time.raw = now;
119 time.year = @intCast(e.date.year);
120
121 time.month = formatTwoDigits(e.date.month);
122 time.day = formatTwoDigits(e.date.day);
123
124 time.hour = formatTwoDigits(e.time.hour);
125 time.minute = formatTwoDigits(e.time.minute);
126 time.second = formatTwoDigits(e.time.second);
127
128 return time;
129}
130
131pub fn copyPost(post: Post, allocator: std.mem.Allocator) !Post {
132 return Post{
133 .id = post.id,
134 .is_secret = post.is_secret,
135
136 .title = try allocator.dupe(u8, post.title),
137 .description = try allocator.dupe(u8, post.description),
138 .author = try allocator.dupe(u8, post.author),
139
140 .tags = try helper.copyStringList(allocator, post.tags),
141
142 .source = try allocator.dupe(u8, post.source), // Relative to source path
143 .url = try allocator.dupe(u8, post.url), // Relative to output path
144
145 .created = post.created,
146 .updated = post.updated,
147
148 .body = if (post.body) |body|
149 try allocator.dupe(u8, body)
150 else
151 null,
152 };
153}
154
155pub fn freePost(post: Post, allocator: std.mem.Allocator) void {
156 allocator.free(post.title);
157 allocator.free(post.description);
158 allocator.free(post.author);
159 helper.freeStringList(allocator, post.tags);
160 allocator.free(post.source);
161 allocator.free(post.url);
162 if (post.body) |body|
163 allocator.free(body);
164}