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 }