mirror of
https://github.com/jetzig-framework/jetzig.git
synced 2025-05-14 14:06:08 +00:00
Allow importing .zig files from src/ in views
Views are copied to zig-cache, meaning that any files in `src/` are not available for `@import` by default. Copy all .zig files from `src/` into zig-cache so that relative imports work as expected. This also removes the need to specifically copy views into zig-cache as the full tree is now present. Also fix a bug in static route fallback - remove superfluous underscore so static routes with non-matching params render default HTML/JSON content.
This commit is contained in:
parent
edbf433a81
commit
a78d53a19a
22
build.zig
22
build.zig
@ -90,10 +90,28 @@ pub fn jetzigInit(b: *std.Build, exe: *std.Build.Step.Compile, options: JetzigIn
|
||||
try generate_routes.generateRoutes();
|
||||
const write_files = b.addWriteFiles();
|
||||
const routes_file = write_files.add("routes.zig", generate_routes.buffer.items);
|
||||
for (generate_routes.static_routes.items) |route| _ = write_files.add(route.path, route.source);
|
||||
for (generate_routes.dynamic_routes.items) |route| _ = write_files.add(route.path, route.source);
|
||||
const routes_module = b.createModule(.{ .root_source_file = routes_file });
|
||||
|
||||
var src_dir = try std.fs.openDirAbsolute(b.pathFromRoot("src"), .{ .iterate = true });
|
||||
defer src_dir.close();
|
||||
var walker = try src_dir.walk(b.allocator);
|
||||
defer walker.deinit();
|
||||
|
||||
while (try walker.next()) |entry| {
|
||||
if (entry.kind == .file) {
|
||||
if (!std.mem.eql(u8, ".zig", std.fs.path.extension(entry.path))) continue;
|
||||
|
||||
const stat = try src_dir.statFile(entry.path);
|
||||
const src_data = try src_dir.readFileAlloc(b.allocator, entry.path, stat.size);
|
||||
defer b.allocator.free(src_data);
|
||||
|
||||
const relpath = try std.fs.path.join(b.allocator, &[_][]const u8{ "src", entry.path });
|
||||
defer b.allocator.free(relpath);
|
||||
|
||||
_ = write_files.add(relpath, src_data);
|
||||
}
|
||||
}
|
||||
|
||||
const exe_static_routes = b.addExecutable(.{
|
||||
.name = "static",
|
||||
.root_source_file = jetzig_dep.path("src/compile_static_routes.zig"),
|
||||
|
@ -1,3 +1,3 @@
|
||||
pub fn exampleFunction() []const u8 {
|
||||
return "example value";
|
||||
pub fn exampleFunction(a: i64, b: i64, c: i64) i64 {
|
||||
return a * b * c;
|
||||
}
|
||||
|
@ -1,9 +1,12 @@
|
||||
const jetzig = @import("jetzig");
|
||||
|
||||
const importedFunction = @import("../lib/example.zig").exampleFunction;
|
||||
|
||||
pub fn index(request: *jetzig.Request, data: *jetzig.Data) !jetzig.View {
|
||||
var root = try data.object();
|
||||
try root.put("message", data.string("Welcome to Jetzig!"));
|
||||
try root.put("number", data.integer(customFunction(100, 200, 300)));
|
||||
try root.put("custom_number", data.integer(customFunction(100, 200, 300)));
|
||||
try root.put("imported_number", data.integer(importedFunction(100, 200, 300)));
|
||||
|
||||
try request.response.headers.append("x-example-header", "example header value");
|
||||
|
||||
|
@ -48,6 +48,7 @@ pub fn index(request: *jetzig.StaticRequest, data: *jetzig.Data) !jetzig.View {
|
||||
const params = try request.params();
|
||||
|
||||
if (params.get("foo")) |foo| try root.put("foo", foo);
|
||||
if (params.get("bar")) |foo| try root.put("bar", foo);
|
||||
|
||||
return request.render(.ok);
|
||||
}
|
||||
|
@ -18,30 +18,27 @@ const Function = struct {
|
||||
source: []const u8,
|
||||
params: std.ArrayList([]const u8),
|
||||
|
||||
/// The full name of a route. This **must** match the naming convention used by static route
|
||||
/// compilation.
|
||||
/// path: `src/app/views/iguanas.zig`, action: `index` => `iguanas_index`
|
||||
pub fn fullName(self: @This(), allocator: std.mem.Allocator) ![]const u8 {
|
||||
var path = try allocator.dupe(u8, self.path);
|
||||
const extension = std.fs.path.extension(path);
|
||||
defer allocator.free(path);
|
||||
std.mem.replaceScalar(u8, path, std.fs.path.sep, '_');
|
||||
return std.mem.concat(
|
||||
allocator,
|
||||
u8,
|
||||
&[_][]const u8{ path[0 .. path.len - extension.len], "_", self.name },
|
||||
);
|
||||
// XXX: Currently we do not support nested routes, so we will need to adjust this if we
|
||||
// add nested routes in future.
|
||||
const extension = std.fs.path.extension(self.path);
|
||||
const basename = std.fs.path.basename(self.path);
|
||||
const name = basename[0 .. basename.len - extension.len];
|
||||
|
||||
return std.mem.concat(allocator, u8, &[_][]const u8{ name, "_", self.name });
|
||||
}
|
||||
|
||||
/// The path used to match the route. Resource ID and extension is not included here and is
|
||||
/// appended as needed during matching logic at run time.
|
||||
pub fn uriPath(self: @This(), allocator: std.mem.Allocator) ![]const u8 {
|
||||
if (std.mem.eql(u8, self.path, "root.zig")) return try allocator.dupe(u8, "/");
|
||||
const basename = std.fs.path.basename(self.path);
|
||||
const name = basename[0 .. basename.len - std.fs.path.extension(basename).len];
|
||||
if (std.mem.eql(u8, name, "root")) return try allocator.dupe(u8, "/");
|
||||
|
||||
var path = try allocator.dupe(u8, self.path);
|
||||
const extension = std.fs.path.extension(path);
|
||||
defer allocator.free(path);
|
||||
std.mem.replaceScalar(u8, path, std.fs.path.sep, '/');
|
||||
return std.mem.concat(
|
||||
allocator,
|
||||
u8,
|
||||
&[_][]const u8{ "/", path[0 .. path.len - extension.len] },
|
||||
);
|
||||
return try std.mem.concat(allocator, u8, &[_][]const u8{ "/", name });
|
||||
}
|
||||
|
||||
pub fn lessThanFn(context: void, lhs: @This(), rhs: @This()) bool {
|
||||
@ -108,11 +105,7 @@ pub fn generateRoutes(self: *Self) !void {
|
||||
if (entry.kind != .file) continue;
|
||||
|
||||
const extension = std.fs.path.extension(entry.path);
|
||||
const basename = std.fs.path.basename(entry.path);
|
||||
|
||||
if (std.mem.eql(u8, basename, "routes.zig")) continue;
|
||||
if (std.mem.eql(u8, basename, "zmpl.manifest.zig")) continue;
|
||||
if (std.mem.startsWith(u8, basename, ".")) continue;
|
||||
if (!std.mem.eql(u8, extension, ".zig")) continue;
|
||||
|
||||
const view_routes = try self.generateRoutesForView(views_dir, entry.path);
|
||||
@ -446,7 +439,7 @@ fn parseFunction(
|
||||
|
||||
return .{
|
||||
.name = function_name,
|
||||
.path = try self.allocator.dupe(u8, path),
|
||||
.path = try std.fs.path.join(self.allocator, &[_][]const u8{ "src", "app", "views", path }),
|
||||
.args = try self.allocator.dupe(Arg, args.items),
|
||||
.source = try self.allocator.dupe(u8, source),
|
||||
.params = std.ArrayList([]const u8).init(self.allocator),
|
||||
|
@ -185,7 +185,3 @@ pub fn base64Decode(allocator: std.mem.Allocator, string: []const u8) ![]const u
|
||||
try decoder.decode(ptr, string);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
test {
|
||||
@import("std").testing.refAllDecls(@This());
|
||||
}
|
||||
|
@ -331,6 +331,8 @@ fn matchRoute(self: *Self, request: *jetzig.http.Request, static: bool) !?*jetzi
|
||||
const StaticResource = struct { content: []const u8, mime_type: []const u8 = "application/octet-stream" };
|
||||
|
||||
fn matchStaticResource(self: *Self, request: *jetzig.http.Request) !?StaticResource {
|
||||
// TODO: Map public and static routes at launch to avoid accessing the file system when
|
||||
// matching any route - currently every request causes file system traversal.
|
||||
const public_resource = try self.matchPublicContent(request);
|
||||
if (public_resource) |resource| return resource;
|
||||
|
||||
@ -458,7 +460,7 @@ fn staticPath(request: *jetzig.http.Request, route: jetzig.views.Route) !?[]cons
|
||||
.index, .post => return try std.mem.concat(
|
||||
request.allocator,
|
||||
u8,
|
||||
&[_][]const u8{ route.name, "_", extension },
|
||||
&[_][]const u8{ route.name, extension },
|
||||
),
|
||||
else => return null,
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user