lib/zen/src/site/path/plan.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2
3 const model = @import("model.zig");
4 const transform = @import("transform.zig");
5
6 pub const Limits = struct {
7 max_target_path_bytes: usize,
8 max_public_path_bytes: usize,
9 };
10
11 pub const default_limits: Limits = .{
12 .max_target_path_bytes = std.Io.Dir.max_path_bytes,
13 .max_public_path_bytes = std.Io.Dir.max_path_bytes + 1,
14 };
15
16 pub const Plan = struct {
17 target_path_bytes: usize,
18 public_path_bytes: usize,
19
20 pub fn inspect(
21 relative_path: []const u8,
22 clean_urls: bool,
23 kind: model.PublicKind,
24 limits: Limits,
25 ) model.Error!Plan {
26 const target_path_bytes = try transform.targetLength(relative_path, clean_urls);
27 const result = Plan{
28 .target_path_bytes = target_path_bytes,
29 .public_path_bytes = try transform.publicLength(target_path_bytes, clean_urls, kind),
30 };
31 try result.require(limits);
32 return result;
33 }
34
35 pub fn exactLimits(self: Plan) Limits {
36 return .{
37 .max_target_path_bytes = self.target_path_bytes,
38 .max_public_path_bytes = self.public_path_bytes,
39 };
40 }
41
42 pub fn require(self: Plan, limits: Limits) model.Exhaustion!void {
43 if (self.target_path_bytes > limits.max_target_path_bytes) {
44 return error.SiteTargetPathCapacityExceeded;
45 }
46 if (self.public_path_bytes > limits.max_public_path_bytes) {
47 return error.SitePublicPathCapacityExceeded;
48 }
49 }
50 };
51
52 test "site path plan exposes exact target and public regions" {
53 const plan = try Plan.inspect("guides/start.md", true, .url, default_limits);
54 try std.testing.expectEqual(@as(usize, "guides/start/index.html".len), plan.target_path_bytes);
55 try std.testing.expectEqual(@as(usize, "/guides/start/".len), plan.public_path_bytes);
56 try std.testing.expectEqual(plan.exactLimits(), Limits{
57 .max_target_path_bytes = "guides/start/index.html".len,
58 .max_public_path_bytes = "/guides/start/".len,
59 });
60 }
61
62 test "site path plan rejects every resource limit" {
63 const exact = (try Plan.inspect("guide.md", true, .target, default_limits)).exactLimits();
64 try std.testing.expectError(
65 error.SiteTargetPathCapacityExceeded,
66 Plan.inspect("guide.md", true, .target, .{
67 .max_target_path_bytes = exact.max_target_path_bytes - 1,
68 .max_public_path_bytes = exact.max_public_path_bytes,
69 }),
70 );
71 try std.testing.expectError(
72 error.SitePublicPathCapacityExceeded,
73 Plan.inspect("guide.md", true, .target, .{
74 .max_target_path_bytes = exact.max_target_path_bytes,
75 .max_public_path_bytes = exact.max_public_path_bytes - 1,
76 }),
77 );
78 }