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 jetzig = @import("jetzig");
|
||||||
|
|
||||||
pub const routes = @import("routes").routes;
|
pub const routes = @import("routes");
|
||||||
|
|
||||||
// Override default settings in `jetzig.config` here:
|
// Override default settings in `jetzig.config` here:
|
||||||
pub const jetzig_options = struct {
|
pub const jetzig_options = struct {
|
||||||
@ -92,5 +92,5 @@ pub fn main() !void {
|
|||||||
const app = try jetzig.init(allocator);
|
const app = try jetzig.init(allocator);
|
||||||
defer app.deinit();
|
defer app.deinit();
|
||||||
|
|
||||||
try app.start(comptime jetzig.route(routes));
|
try app.start(routes, .{});
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ const Function = struct {
|
|||||||
path: []const u8,
|
path: []const u8,
|
||||||
source: []const u8,
|
source: []const u8,
|
||||||
params: std.ArrayList([]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
|
/// The full name of a route. This **must** match the naming convention used by static route
|
||||||
/// compilation.
|
/// compilation.
|
||||||
@ -128,8 +129,9 @@ pub fn generateRoutes(self: *Self) !void {
|
|||||||
std.sort.pdq(Function, self.dynamic_routes.items, {}, Function.lessThanFn);
|
std.sort.pdq(Function, self.dynamic_routes.items, {}, Function.lessThanFn);
|
||||||
|
|
||||||
try writer.writeAll(
|
try writer.writeAll(
|
||||||
\\pub const routes = struct {
|
\\const jetzig = @import("jetzig");
|
||||||
\\ pub const static = .{
|
\\
|
||||||
|
\\pub const routes = [_]jetzig.views.Route{
|
||||||
\\
|
\\
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -137,21 +139,14 @@ pub fn generateRoutes(self: *Self) !void {
|
|||||||
try self.writeRoute(writer, static_route);
|
try self.writeRoute(writer, static_route);
|
||||||
}
|
}
|
||||||
|
|
||||||
try writer.writeAll(
|
|
||||||
\\ };
|
|
||||||
\\
|
|
||||||
\\ pub const dynamic = .{
|
|
||||||
\\
|
|
||||||
);
|
|
||||||
|
|
||||||
for (self.dynamic_routes.items) |dynamic_route| {
|
for (self.dynamic_routes.items) |dynamic_route| {
|
||||||
try self.writeRoute(writer, dynamic_route);
|
try self.writeRoute(writer, dynamic_route);
|
||||||
const name = try dynamic_route.fullName(self.allocator);
|
const name = try dynamic_route.fullName(self.allocator);
|
||||||
defer self.allocator.free(name);
|
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("};");
|
try writer.writeAll("};");
|
||||||
|
|
||||||
// std.debug.print("routes.zig\n{s}\n", .{self.buffer.items});
|
// 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 =
|
const output_template =
|
||||||
\\ .{{
|
\\ .{{
|
||||||
\\ .name = "{s}",
|
\\ .name = "{0s}",
|
||||||
\\ .action = "{s}",
|
\\ .action = .{1s},
|
||||||
\\ .view_name = "{s}",
|
\\ .view_name = "{2s}",
|
||||||
\\ .uri_path = "{s}",
|
\\ .view = jetzig.views.Route.ViewType{{ .{3s} = .{{ .{1s} = @import("{7s}").{1s} }} }},
|
||||||
\\ .template = "{s}",
|
\\ .static = {4s},
|
||||||
\\ .module = @import("{s}"),
|
\\ .uri_path = "{5s}",
|
||||||
\\ .function = @import("{s}").{s},
|
\\ .template = "{6s}",
|
||||||
\\ .params = {s},
|
\\ .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);
|
const module_path = try self.allocator.dupe(u8, route.path);
|
||||||
defer self.allocator.free(module_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,
|
full_name,
|
||||||
route.name,
|
route.name,
|
||||||
route.view_name,
|
route.view_name,
|
||||||
|
if (route.static) "static" else "dynamic",
|
||||||
|
if (route.static) "true" else "false",
|
||||||
uri_path,
|
uri_path,
|
||||||
full_name,
|
full_name,
|
||||||
module_path,
|
module_path,
|
||||||
module_path,
|
try std.mem.join(self.allocator, ", \n", route.params.items),
|
||||||
route.name,
|
|
||||||
params_buf.items,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
defer self.allocator.free(output);
|
defer self.allocator.free(output);
|
||||||
@ -237,13 +218,14 @@ fn generateRoutesForView(self: *Self, views_dir: std.fs.Dir, path: []const u8) !
|
|||||||
switch (tag) {
|
switch (tag) {
|
||||||
.fn_proto_multi => {
|
.fn_proto_multi => {
|
||||||
const function = try self.parseFunction(index, path, source);
|
const function = try self.parseFunction(index, path, source);
|
||||||
if (function) |capture| {
|
if (function) |*capture| {
|
||||||
for (capture.args) |arg| {
|
for (capture.args) |arg| {
|
||||||
if (std.mem.eql(u8, try arg.typeBasename(), "StaticRequest")) {
|
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")) {
|
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 {
|
fn compileStaticRoutes(allocator: std.mem.Allocator) !void {
|
||||||
std.fs.cwd().deleteTree("static") catch {};
|
std.fs.cwd().deleteTree("static") catch {};
|
||||||
|
|
||||||
inline for (routes.static) |static_route| {
|
var count: usize = 0;
|
||||||
const static_view = jetzig.views.Route.ViewType{
|
|
||||||
.static = @unionInit(
|
|
||||||
jetzig.views.Route.StaticViewType,
|
|
||||||
static_route.action,
|
|
||||||
static_route.function,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
comptime var static_params_len = 0;
|
for (routes) |route| {
|
||||||
inline for (static_route.params) |_| static_params_len += 1;
|
if (!route.static) continue;
|
||||||
comptime var params: [static_params_len][]const u8 = undefined;
|
|
||||||
inline for (static_route.params, 0..) |json, index| params[index] = json;
|
|
||||||
|
|
||||||
const layout: ?[]const u8 = if (@hasDecl(static_route.module, "layout"))
|
if (route.json_params.len > 0) {
|
||||||
static_route.module.layout
|
for (route.json_params, 0..) |json, index| {
|
||||||
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| {
|
|
||||||
var request = try jetzig.http.StaticRequest.init(allocator, json);
|
var request = try jetzig.http.StaticRequest.init(allocator, json);
|
||||||
defer request.deinit();
|
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 => {
|
.index, .post => {
|
||||||
var request = try jetzig.http.StaticRequest.init(allocator, "{}");
|
var request = try jetzig.http.StaticRequest.init(allocator, "{}");
|
||||||
defer request.deinit();
|
defer request.deinit();
|
||||||
try writeContent(allocator, route, &request, null);
|
try writeContent(allocator, route, &request, null, &count);
|
||||||
},
|
},
|
||||||
inline else => {},
|
inline else => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
std.debug.print("[jetzig] Compiled {} static output(s)\n", .{count});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn writeContent(
|
fn writeContent(
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
comptime route: jetzig.views.Route,
|
route: jetzig.views.Route,
|
||||||
request: *jetzig.http.StaticRequest,
|
request: *jetzig.http.StaticRequest,
|
||||||
index: ?usize,
|
index: ?usize,
|
||||||
|
count: *usize,
|
||||||
) !void {
|
) !void {
|
||||||
const index_suffix = if (index) |capture|
|
const index_suffix = if (index) |capture|
|
||||||
try std.fmt.allocPrint(allocator, "_{}", .{capture})
|
try std.fmt.allocPrint(allocator, "_{}", .{capture})
|
||||||
@ -100,7 +76,7 @@ fn writeContent(
|
|||||||
try json_file.writeAll(try view.data.toJson());
|
try json_file.writeAll(try view.data.toJson());
|
||||||
defer json_file.close();
|
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
|
const html_content = try renderZmplTemplate(allocator, route, view) orelse
|
||||||
try renderMarkdown(allocator, route, view) orelse
|
try renderMarkdown(allocator, route, view) orelse
|
||||||
@ -116,7 +92,7 @@ fn writeContent(
|
|||||||
try html_file.writeAll(content);
|
try html_file.writeAll(content);
|
||||||
defer html_file.close();
|
defer html_file.close();
|
||||||
allocator.free(content);
|
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,
|
.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;
|
_ = 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
|
/// Starts an application. `routes` should be `@import("routes").routes`, a generated file
|
||||||
/// automatically created at build time. `templates` should be
|
/// automatically created at build time. `templates` should be
|
||||||
/// `@import("src/app/views/zmpl.manifest.zig").templates`, created by Zmpl at compile time.
|
/// `@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);
|
var mime_map = jetzig.http.mime.MimeMap.init(self.allocator);
|
||||||
defer mime_map.deinit();
|
defer mime_map.deinit();
|
||||||
try mime_map.build();
|
try mime_map.build();
|
||||||
|
|
||||||
var routes = std.ArrayList(*jetzig.views.Route).init(self.allocator);
|
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);
|
var route = try self.allocator.create(jetzig.views.Route);
|
||||||
route.* = jetzig.views.Route{
|
route.* = .{
|
||||||
.name = comptime_route.name,
|
.name = const_route.name,
|
||||||
.action = comptime_route.action,
|
.action = const_route.action,
|
||||||
.view_name = comptime_route.view_name,
|
.view_name = const_route.view_name,
|
||||||
.uri_path = comptime_route.uri_path,
|
.uri_path = const_route.uri_path,
|
||||||
.view = comptime_route.view,
|
.view = const_route.view,
|
||||||
.static_view = comptime_route.static_view,
|
.static_view = const_route.static_view,
|
||||||
.static = comptime_route.static,
|
.static = const_route.static,
|
||||||
.render = comptime_route.render,
|
.render = const_route.render,
|
||||||
.renderStatic = comptime_route.renderStatic,
|
.renderStatic = const_route.renderStatic,
|
||||||
.layout = comptime_route.layout,
|
.layout = const_route.layout,
|
||||||
.template = comptime_route.template,
|
.template = const_route.template,
|
||||||
.json_params = comptime_route.json_params,
|
.json_params = const_route.json_params,
|
||||||
};
|
};
|
||||||
|
|
||||||
try route.initParams(self.allocator);
|
try route.initParams(self.allocator);
|
||||||
try routes.append(route);
|
try routes.append(route);
|
||||||
}
|
}
|
||||||
|
|
||||||
defer routes.deinit();
|
defer routes.deinit();
|
||||||
defer for (routes.items) |route| {
|
defer for (routes.items) |route| {
|
||||||
route.deinitParams();
|
route.deinitParams();
|
||||||
|
@ -47,7 +47,7 @@ render: RenderFn = renderFn,
|
|||||||
renderStatic: RenderStaticFn = renderStaticFn,
|
renderStatic: RenderStaticFn = renderStaticFn,
|
||||||
layout: ?[]const u8,
|
layout: ?[]const u8,
|
||||||
template: []const u8,
|
template: []const u8,
|
||||||
json_params: [][]const u8,
|
json_params: []const []const u8,
|
||||||
params: std.ArrayList(*jetzig.data.Data) = undefined,
|
params: std.ArrayList(*jetzig.data.Data) = undefined,
|
||||||
|
|
||||||
/// Initializes a route's static params on server launch. Converts static params (JSON strings)
|
/// Initializes a route's static params on server launch. Converts static params (JSON strings)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user