mirror of
https://github.com/jetzig-framework/jetzig.git
synced 2025-05-14 22:16:08 +00:00
Merge pull request #49 from jetzig-framework/simplify-route-generation
Simplify route generation
This commit is contained in:
commit
b94845a415
@ -2,7 +2,7 @@ const std = @import("std");
|
||||
|
||||
pub const jetzig = @import("jetzig");
|
||||
|
||||
pub const routes = @import("routes").routes;
|
||||
pub const routes = @import("routes");
|
||||
|
||||
// Override default settings in `jetzig.config` here:
|
||||
pub const jetzig_options = struct {
|
||||
@ -92,5 +92,5 @@ pub fn main() !void {
|
||||
const app = try jetzig.init(allocator);
|
||||
defer app.deinit();
|
||||
|
||||
try app.start(comptime jetzig.route(routes));
|
||||
try app.start(routes, .{});
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ const Function = struct {
|
||||
path: []const u8,
|
||||
source: []const u8,
|
||||
params: std.ArrayList([]const u8),
|
||||
static: bool = false,
|
||||
|
||||
/// The full name of a route. This **must** match the naming convention used by static route
|
||||
/// compilation.
|
||||
@ -128,8 +129,9 @@ pub fn generateRoutes(self: *Self) !void {
|
||||
std.sort.pdq(Function, self.dynamic_routes.items, {}, Function.lessThanFn);
|
||||
|
||||
try writer.writeAll(
|
||||
\\pub const routes = struct {
|
||||
\\ pub const static = .{
|
||||
\\const jetzig = @import("jetzig");
|
||||
\\
|
||||
\\pub const routes = [_]jetzig.views.Route{
|
||||
\\
|
||||
);
|
||||
|
||||
@ -137,21 +139,14 @@ pub fn generateRoutes(self: *Self) !void {
|
||||
try self.writeRoute(writer, static_route);
|
||||
}
|
||||
|
||||
try writer.writeAll(
|
||||
\\ };
|
||||
\\
|
||||
\\ pub const dynamic = .{
|
||||
\\
|
||||
);
|
||||
|
||||
for (self.dynamic_routes.items) |dynamic_route| {
|
||||
try self.writeRoute(writer, dynamic_route);
|
||||
const name = try dynamic_route.fullName(self.allocator);
|
||||
defer self.allocator.free(name);
|
||||
std.debug.print("[jetzig] Imported route: {s}\n", .{name});
|
||||
}
|
||||
|
||||
try writer.writeAll(" };\n");
|
||||
std.debug.print("[jetzig] Imported {} route(s)\n", .{self.dynamic_routes.items.len});
|
||||
|
||||
try writer.writeAll("};");
|
||||
|
||||
// std.debug.print("routes.zig\n{s}\n", .{self.buffer.items});
|
||||
@ -166,33 +161,19 @@ fn writeRoute(self: *Self, writer: std.ArrayList(u8).Writer, route: Function) !v
|
||||
|
||||
const output_template =
|
||||
\\ .{{
|
||||
\\ .name = "{s}",
|
||||
\\ .action = "{s}",
|
||||
\\ .view_name = "{s}",
|
||||
\\ .uri_path = "{s}",
|
||||
\\ .template = "{s}",
|
||||
\\ .module = @import("{s}"),
|
||||
\\ .function = @import("{s}").{s},
|
||||
\\ .params = {s},
|
||||
\\ .name = "{0s}",
|
||||
\\ .action = .{1s},
|
||||
\\ .view_name = "{2s}",
|
||||
\\ .view = jetzig.views.Route.ViewType{{ .{3s} = .{{ .{1s} = @import("{7s}").{1s} }} }},
|
||||
\\ .static = {4s},
|
||||
\\ .uri_path = "{5s}",
|
||||
\\ .template = "{6s}",
|
||||
\\ .layout = if (@hasDecl(@import("{7s}"), "layout")) @import("{7s}").layout else null,
|
||||
\\ .json_params = &[_][]const u8 {{ {8s} }},
|
||||
\\ }},
|
||||
\\
|
||||
;
|
||||
|
||||
var params_buf = std.ArrayList(u8).init(self.allocator);
|
||||
const params_writer = params_buf.writer();
|
||||
defer params_buf.deinit();
|
||||
if (route.params.items.len > 0) {
|
||||
try params_writer.writeAll(".{\n");
|
||||
for (route.params.items) |item| {
|
||||
try params_writer.writeAll(" ");
|
||||
try params_writer.writeAll(item);
|
||||
try params_writer.writeAll(",\n");
|
||||
}
|
||||
try params_writer.writeAll(" }");
|
||||
} else {
|
||||
try params_writer.writeAll(".{}");
|
||||
}
|
||||
|
||||
const module_path = try self.allocator.dupe(u8, route.path);
|
||||
defer self.allocator.free(module_path);
|
||||
|
||||
@ -205,12 +186,12 @@ fn writeRoute(self: *Self, writer: std.ArrayList(u8).Writer, route: Function) !v
|
||||
full_name,
|
||||
route.name,
|
||||
route.view_name,
|
||||
if (route.static) "static" else "dynamic",
|
||||
if (route.static) "true" else "false",
|
||||
uri_path,
|
||||
full_name,
|
||||
module_path,
|
||||
module_path,
|
||||
route.name,
|
||||
params_buf.items,
|
||||
try std.mem.join(self.allocator, ", \n", route.params.items),
|
||||
});
|
||||
|
||||
defer self.allocator.free(output);
|
||||
@ -237,13 +218,14 @@ fn generateRoutesForView(self: *Self, views_dir: std.fs.Dir, path: []const u8) !
|
||||
switch (tag) {
|
||||
.fn_proto_multi => {
|
||||
const function = try self.parseFunction(index, path, source);
|
||||
if (function) |capture| {
|
||||
if (function) |*capture| {
|
||||
for (capture.args) |arg| {
|
||||
if (std.mem.eql(u8, try arg.typeBasename(), "StaticRequest")) {
|
||||
try static_routes.append(capture);
|
||||
@constCast(capture).static = true;
|
||||
try static_routes.append(capture.*);
|
||||
}
|
||||
if (std.mem.eql(u8, try arg.typeBasename(), "Request")) {
|
||||
try dynamic_routes.append(capture);
|
||||
try dynamic_routes.append(capture.*);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,42 +19,16 @@ pub fn main() !void {
|
||||
fn compileStaticRoutes(allocator: std.mem.Allocator) !void {
|
||||
std.fs.cwd().deleteTree("static") catch {};
|
||||
|
||||
inline for (routes.static) |static_route| {
|
||||
const static_view = jetzig.views.Route.ViewType{
|
||||
.static = @unionInit(
|
||||
jetzig.views.Route.StaticViewType,
|
||||
static_route.action,
|
||||
static_route.function,
|
||||
),
|
||||
};
|
||||
var count: usize = 0;
|
||||
|
||||
comptime var static_params_len = 0;
|
||||
inline for (static_route.params) |_| static_params_len += 1;
|
||||
comptime var params: [static_params_len][]const u8 = undefined;
|
||||
inline for (static_route.params, 0..) |json, index| params[index] = json;
|
||||
for (routes) |route| {
|
||||
if (!route.static) continue;
|
||||
|
||||
const layout: ?[]const u8 = if (@hasDecl(static_route.module, "layout"))
|
||||
static_route.module.layout
|
||||
else
|
||||
null;
|
||||
|
||||
const route = jetzig.views.Route{
|
||||
.name = static_route.name,
|
||||
.action = @field(jetzig.views.Route.Action, static_route.action),
|
||||
.view_name = static_route.view_name,
|
||||
.view = static_view,
|
||||
.static = true,
|
||||
.uri_path = static_route.uri_path,
|
||||
.layout = layout,
|
||||
.template = static_route.template,
|
||||
.json_params = ¶ms,
|
||||
};
|
||||
|
||||
if (static_params_len > 0) {
|
||||
inline for (static_route.params, 0..) |json, index| {
|
||||
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, route, &request, index);
|
||||
try writeContent(allocator, route, &request, index, &count);
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,18 +38,20 @@ fn compileStaticRoutes(allocator: std.mem.Allocator) !void {
|
||||
.index, .post => {
|
||||
var request = try jetzig.http.StaticRequest.init(allocator, "{}");
|
||||
defer request.deinit();
|
||||
try writeContent(allocator, route, &request, null);
|
||||
try writeContent(allocator, route, &request, null, &count);
|
||||
},
|
||||
inline else => {},
|
||||
}
|
||||
}
|
||||
std.debug.print("[jetzig] Compiled {} static output(s)\n", .{count});
|
||||
}
|
||||
|
||||
fn writeContent(
|
||||
allocator: std.mem.Allocator,
|
||||
comptime route: jetzig.views.Route,
|
||||
route: jetzig.views.Route,
|
||||
request: *jetzig.http.StaticRequest,
|
||||
index: ?usize,
|
||||
count: *usize,
|
||||
) !void {
|
||||
const index_suffix = if (index) |capture|
|
||||
try std.fmt.allocPrint(allocator, "_{}", .{capture})
|
||||
@ -100,7 +76,7 @@ fn writeContent(
|
||||
try json_file.writeAll(try view.data.toJson());
|
||||
defer json_file.close();
|
||||
|
||||
std.debug.print("[jetzig] Compiled static route: {s}\n", .{json_path});
|
||||
count.* += 1;
|
||||
|
||||
const html_content = try renderZmplTemplate(allocator, route, view) orelse
|
||||
try renderMarkdown(allocator, route, view) orelse
|
||||
@ -116,7 +92,7 @@ fn writeContent(
|
||||
try html_file.writeAll(content);
|
||||
defer html_file.close();
|
||||
allocator.free(content);
|
||||
std.debug.print("[jetzig] Compiled static route: {s}\n", .{html_path});
|
||||
count.* += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,84 +96,3 @@ pub fn init(allocator: std.mem.Allocator) !App {
|
||||
.allocator = allocator,
|
||||
};
|
||||
}
|
||||
|
||||
// Receives an array of imported modules and detects functions defined on them.
|
||||
// Each detected function is stored as a Route which can be accessed at runtime to route requests
|
||||
// to the appropriate View.
|
||||
pub fn route(comptime routes: anytype) []views.Route {
|
||||
var size: usize = 0;
|
||||
|
||||
for (routes.dynamic) |_| {
|
||||
size += 1;
|
||||
}
|
||||
|
||||
for (routes.static) |_| {
|
||||
size += 1;
|
||||
}
|
||||
|
||||
var detected: [size]views.Route = undefined;
|
||||
var index: usize = 0;
|
||||
|
||||
for (routes.dynamic) |dynamic_route| {
|
||||
const view = views.Route.ViewType{
|
||||
.dynamic = @unionInit(
|
||||
views.Route.DynamicViewType,
|
||||
dynamic_route.action,
|
||||
dynamic_route.function,
|
||||
),
|
||||
};
|
||||
|
||||
const layout: ?[]const u8 = if (@hasDecl(dynamic_route.module, "layout"))
|
||||
dynamic_route.module.layout
|
||||
else
|
||||
null;
|
||||
|
||||
detected[index] = .{
|
||||
.name = dynamic_route.name,
|
||||
.action = @field(views.Route.Action, dynamic_route.action),
|
||||
.view_name = dynamic_route.view_name,
|
||||
.view = view,
|
||||
.static = false,
|
||||
.uri_path = dynamic_route.uri_path,
|
||||
.layout = layout,
|
||||
.template = dynamic_route.template,
|
||||
.json_params = &.{},
|
||||
};
|
||||
index += 1;
|
||||
}
|
||||
|
||||
for (routes.static) |static_route| {
|
||||
const view = views.Route.ViewType{
|
||||
.static = @unionInit(
|
||||
views.Route.StaticViewType,
|
||||
static_route.action,
|
||||
static_route.function,
|
||||
),
|
||||
};
|
||||
|
||||
comptime var params_size = 0;
|
||||
inline for (static_route.params) |_| params_size += 1;
|
||||
comptime var static_params: [params_size][]const u8 = undefined;
|
||||
inline for (static_route.params, 0..) |json, params_index| static_params[params_index] = json;
|
||||
|
||||
const layout: ?[]const u8 = if (@hasDecl(static_route.module, "layout"))
|
||||
static_route.module.layout
|
||||
else
|
||||
null;
|
||||
|
||||
detected[index] = .{
|
||||
.name = static_route.name,
|
||||
.action = @field(views.Route.Action, static_route.action),
|
||||
.view_name = static_route.view_name,
|
||||
.view = view,
|
||||
.static = true,
|
||||
.uri_path = static_route.uri_path,
|
||||
.layout = layout,
|
||||
.template = static_route.template,
|
||||
.json_params = &static_params,
|
||||
};
|
||||
index += 1;
|
||||
}
|
||||
|
||||
return &detected;
|
||||
}
|
||||
|
@ -14,35 +14,43 @@ pub fn deinit(self: Self) void {
|
||||
_ = self;
|
||||
}
|
||||
|
||||
// Not used yet, but allows us to add new options to `start()` without breaking
|
||||
// backward-compatibility.
|
||||
const AppOptions = struct {};
|
||||
|
||||
/// Starts an application. `routes` should be `@import("routes").routes`, a generated file
|
||||
/// automatically created at build time. `templates` should be
|
||||
/// `@import("src/app/views/zmpl.manifest.zig").templates`, created by Zmpl at compile time.
|
||||
pub fn start(self: Self, comptime_routes: []jetzig.views.Route) !void {
|
||||
pub fn start(self: Self, routes_module: type, options: AppOptions) !void {
|
||||
_ = options; // See `AppOptions`
|
||||
|
||||
var mime_map = jetzig.http.mime.MimeMap.init(self.allocator);
|
||||
defer mime_map.deinit();
|
||||
try mime_map.build();
|
||||
|
||||
var routes = std.ArrayList(*jetzig.views.Route).init(self.allocator);
|
||||
|
||||
for (comptime_routes) |*comptime_route| {
|
||||
for (routes_module.routes) |const_route| {
|
||||
var route = try self.allocator.create(jetzig.views.Route);
|
||||
route.* = jetzig.views.Route{
|
||||
.name = comptime_route.name,
|
||||
.action = comptime_route.action,
|
||||
.view_name = comptime_route.view_name,
|
||||
.uri_path = comptime_route.uri_path,
|
||||
.view = comptime_route.view,
|
||||
.static_view = comptime_route.static_view,
|
||||
.static = comptime_route.static,
|
||||
.render = comptime_route.render,
|
||||
.renderStatic = comptime_route.renderStatic,
|
||||
.layout = comptime_route.layout,
|
||||
.template = comptime_route.template,
|
||||
.json_params = comptime_route.json_params,
|
||||
route.* = .{
|
||||
.name = const_route.name,
|
||||
.action = const_route.action,
|
||||
.view_name = const_route.view_name,
|
||||
.uri_path = const_route.uri_path,
|
||||
.view = const_route.view,
|
||||
.static_view = const_route.static_view,
|
||||
.static = const_route.static,
|
||||
.render = const_route.render,
|
||||
.renderStatic = const_route.renderStatic,
|
||||
.layout = const_route.layout,
|
||||
.template = const_route.template,
|
||||
.json_params = const_route.json_params,
|
||||
};
|
||||
|
||||
try route.initParams(self.allocator);
|
||||
try routes.append(route);
|
||||
}
|
||||
|
||||
defer routes.deinit();
|
||||
defer for (routes.items) |route| {
|
||||
route.deinitParams();
|
||||
|
@ -47,7 +47,7 @@ render: RenderFn = renderFn,
|
||||
renderStatic: RenderStaticFn = renderStaticFn,
|
||||
layout: ?[]const u8,
|
||||
template: []const u8,
|
||||
json_params: [][]const u8,
|
||||
json_params: []const []const u8,
|
||||
params: std.ArrayList(*jetzig.data.Data) = undefined,
|
||||
|
||||
/// Initializes a route's static params on server launch. Converts static params (JSON strings)
|
||||
|
Loading…
x
Reference in New Issue
Block a user