mirror of
https://github.com/jetzig-framework/jetzig.git
synced 2025-05-14 14:06:08 +00:00

Detect if provided params are a subset of actual params, provide informative errors if not.
196 lines
6.6 KiB
Zig
196 lines
6.6 KiB
Zig
const std = @import("std");
|
|
const jetzig = @import("jetzig");
|
|
const routes = @import("routes").routes;
|
|
const zmpl = @import("zmpl");
|
|
const markdown_fragments = @import("markdown_fragments");
|
|
pub const Global = if (@hasDecl(@import("main"), "Global"))
|
|
@import("main").Global
|
|
else
|
|
jetzig.DefaultGlobal;
|
|
|
|
pub const database_lazy_connect = true;
|
|
|
|
pub const jetzig_options = struct {
|
|
pub const Schema = @import("Schema");
|
|
pub const middleware: []const type = if (@hasDecl(@import("main").jetzig_options, "middleware"))
|
|
@import("main").jetzig_options.middleware
|
|
else
|
|
&.{};
|
|
};
|
|
|
|
pub fn main() !void {
|
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
|
defer std.debug.assert(gpa.deinit() == .ok);
|
|
const gpa_allocator = gpa.allocator();
|
|
|
|
var arena = std.heap.ArenaAllocator.init(gpa_allocator);
|
|
const allocator = arena.allocator();
|
|
defer arena.deinit();
|
|
|
|
var it = try std.process.argsWithAllocator(allocator);
|
|
var index: usize = 0;
|
|
while (it.next()) |arg| : (index += 1) {
|
|
if (index == 0) continue;
|
|
const file = try std.fs.createFileAbsolute(arg, .{});
|
|
const writer = file.writer();
|
|
try compileStaticRoutes(allocator, writer);
|
|
file.close();
|
|
break;
|
|
}
|
|
}
|
|
|
|
fn compileStaticRoutes(allocator: std.mem.Allocator, writer: anytype) !void {
|
|
var count: usize = 0;
|
|
|
|
try writer.writeAll(
|
|
\\const StaticOutput = struct { json: ?[]const u8 = null, html: ?[]const u8 = null, params: ?[]const u8 };
|
|
\\const Compiled = struct { route_id: []const u8, output: StaticOutput };
|
|
\\pub const compiled = [_]Compiled{
|
|
\\
|
|
);
|
|
for (routes) |route| {
|
|
if (!route.static) continue;
|
|
|
|
if (route.json_params.len > 0) {
|
|
for (route.json_params, 0..) |json, index| {
|
|
var request = try jetzig.http.StaticRequest.init(allocator, json);
|
|
defer request.deinit();
|
|
try writeContent(allocator, writer, route, &request, index, &count, json);
|
|
}
|
|
}
|
|
|
|
// Always provide a fallback for non-resource routes (i.e. `index`, `post`) if params
|
|
// do not match any of the configured param sets.
|
|
switch (route.action) {
|
|
.index, .post => {
|
|
var request = try jetzig.http.StaticRequest.init(allocator, "{}");
|
|
defer request.deinit();
|
|
try writeContent(allocator, writer, route, &request, null, &count, null);
|
|
},
|
|
inline else => {},
|
|
}
|
|
}
|
|
|
|
try writer.writeAll(
|
|
\\};
|
|
\\
|
|
);
|
|
std.debug.print("[jetzig] Compiled {} static output(s)\n", .{count});
|
|
}
|
|
|
|
fn writeContent(
|
|
allocator: std.mem.Allocator,
|
|
writer: anytype,
|
|
route: jetzig.views.Route,
|
|
request: *jetzig.http.StaticRequest,
|
|
index: ?usize,
|
|
count: *usize,
|
|
params_json: ?[]const u8,
|
|
) !void {
|
|
const index_suffix = if (index) |capture|
|
|
try std.fmt.allocPrint(allocator, "_{}", .{capture})
|
|
else
|
|
try allocator.dupe(u8, "");
|
|
defer allocator.free(index_suffix);
|
|
|
|
const view = try route.renderStatic(route, request);
|
|
defer view.deinit();
|
|
|
|
count.* += 1;
|
|
|
|
const html_content = try renderZmplTemplate(allocator, route, view) orelse
|
|
try renderMarkdown(allocator, route, view) orelse
|
|
null;
|
|
|
|
try writer.print(
|
|
\\.{{ .route_id = "{s}", .output = StaticOutput{{ .json = "{s}", .html = "{s}", .params = {s}{s}{s} }} }},
|
|
\\
|
|
\\
|
|
,
|
|
.{
|
|
route.id,
|
|
try zigEscape(allocator, try view.data.toJson()),
|
|
try zigEscape(allocator, html_content orelse ""),
|
|
if (params_json) |_| "\"" else "",
|
|
if (params_json) |params| try zigEscape(allocator, params) else "null",
|
|
if (params_json) |_| "\"" else "",
|
|
},
|
|
);
|
|
|
|
if (html_content) |content| {
|
|
allocator.free(content);
|
|
count.* += 1;
|
|
}
|
|
}
|
|
|
|
fn renderMarkdown(
|
|
allocator: std.mem.Allocator,
|
|
route: jetzig.views.Route,
|
|
view: jetzig.views.View,
|
|
) !?[]const u8 {
|
|
const path = try std.mem.join(allocator, "/", &[_][]const u8{ route.uri_path, @tagName(route.action) });
|
|
defer allocator.free(path);
|
|
const content = try jetzig.markdown.renderFile(
|
|
allocator,
|
|
path,
|
|
.{ .fragments = markdown_fragments },
|
|
) orelse return null;
|
|
|
|
if (route.layout) |layout_name| {
|
|
try view.data.addConst("jetzig_view", view.data.string(route.name));
|
|
try view.data.addConst("jetzig_action", view.data.string(@tagName(route.action)));
|
|
|
|
// TODO: Allow user to configure layouts directory other than src/app/views/layouts/
|
|
const prefixed_name = try std.mem.concat(allocator, u8, &[_][]const u8{ "layouts_", layout_name });
|
|
defer allocator.free(prefixed_name);
|
|
defer allocator.free(prefixed_name);
|
|
|
|
if (zmpl.findPrefixed("views", prefixed_name)) |layout| {
|
|
view.data.content = .{ .data = content };
|
|
return try layout.render(view.data, jetzig.TemplateContext, .{}, &.{}, .{});
|
|
} else {
|
|
std.debug.print("Unknown layout: {s}\n", .{layout_name});
|
|
return content;
|
|
}
|
|
} else return null;
|
|
}
|
|
|
|
fn renderZmplTemplate(
|
|
allocator: std.mem.Allocator,
|
|
route: jetzig.views.Route,
|
|
view: jetzig.views.View,
|
|
) !?[]const u8 {
|
|
if (zmpl.findPrefixed("views", route.template)) |template| {
|
|
try view.data.addConst("jetzig_view", view.data.string(route.name));
|
|
try view.data.addConst("jetzig_action", view.data.string(@tagName(route.action)));
|
|
|
|
if (route.layout) |layout_name| {
|
|
// TODO: Allow user to configure layouts directory other than src/app/views/layouts/
|
|
const prefixed_name = try std.mem.concat(allocator, u8, &[_][]const u8{ "layouts_", layout_name });
|
|
defer allocator.free(prefixed_name);
|
|
|
|
if (zmpl.findPrefixed("views", prefixed_name)) |layout| {
|
|
return try template.render(
|
|
view.data,
|
|
jetzig.TemplateContext,
|
|
.{},
|
|
&.{},
|
|
.{ .layout = layout },
|
|
);
|
|
} else {
|
|
std.debug.print("Unknown layout: {s}\n", .{layout_name});
|
|
return try allocator.dupe(u8, "");
|
|
}
|
|
} else {
|
|
return try template.render(view.data, jetzig.TemplateContext, .{}, &.{}, .{});
|
|
}
|
|
} else return null;
|
|
}
|
|
|
|
fn zigEscape(allocator: std.mem.Allocator, content: []const u8) ![]const u8 {
|
|
var buf = std.ArrayList(u8).init(allocator);
|
|
const writer = buf.writer();
|
|
try std.zig.stringEscape(content, "", .{}, writer);
|
|
return try buf.toOwnedSlice();
|
|
}
|