aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-11-22 04:00:55 -0800
committerGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-11-22 04:00:55 -0800
commit2b4dcc8c817e2597f2de079c27302f9970fbebb6 (patch)
tree1259946f391e7624203c20936e2156a72c20af75
parent15a5aa1a682c81cb017795e9489dbb279e7b6717 (diff)
downloadbun-2b4dcc8c817e2597f2de079c27302f9970fbebb6.tar.gz
bun-2b4dcc8c817e2597f2de079c27302f9970fbebb6.tar.zst
bun-2b4dcc8c817e2597f2de079c27302f9970fbebb6.zip
[FileSystemRouter] base_dir, Request, Response
-rw-r--r--src/bun.js/api/bun.zig9
-rw-r--r--src/bun.js/api/filesystem_router.classes.ts8
-rw-r--r--src/bun.js/api/filesystem_router.zig48
-rw-r--r--src/bun.js/bindings/ZigGeneratedClasses.cpp74
-rw-r--r--src/bun.js/bindings/ZigGeneratedClasses.h1
-rw-r--r--src/bun.js/bindings/generated_classes.zig29
-rw-r--r--src/url.zig13
-rw-r--r--test/bun.js/filesystem_router.test.ts68
8 files changed, 232 insertions, 18 deletions
diff --git a/src/bun.js/api/bun.zig b/src/bun.js/api/bun.zig
index 64c1259c4..3a88f7a04 100644
--- a/src/bun.js/api/bun.zig
+++ b/src/bun.js/api/bun.zig
@@ -820,11 +820,14 @@ pub fn readFileAsString(
}
pub fn getPublicPath(to: string, origin: URL, comptime Writer: type, writer: Writer) void {
- return getPublicPathWithAssetPrefix(to, origin, VirtualMachine.vm.bundler.options.routes.asset_prefix_path, comptime Writer, writer);
+ return getPublicPathWithAssetPrefix(to, VirtualMachine.vm.bundler.fs.top_level_dir, origin, VirtualMachine.vm.bundler.options.routes.asset_prefix_path, comptime Writer, writer);
}
-pub fn getPublicPathWithAssetPrefix(to: string, origin: URL, asset_prefix: string, comptime Writer: type, writer: Writer) void {
- const relative_path = VirtualMachine.vm.bundler.fs.relativeTo(to);
+pub fn getPublicPathWithAssetPrefix(to: string, dir: string, origin: URL, asset_prefix: string, comptime Writer: type, writer: Writer) void {
+ const relative_path = if (strings.hasPrefix(to, dir))
+ strings.withoutTrailingSlash(to[dir.len..])
+ else
+ VirtualMachine.vm.bundler.fs.relative(dir, to);
if (origin.isAbsolute()) {
if (strings.hasPrefix(relative_path, "..") or strings.hasPrefix(relative_path, "./")) {
writer.writeAll(origin.origin) catch return;
diff --git a/src/bun.js/api/filesystem_router.classes.ts b/src/bun.js/api/filesystem_router.classes.ts
index bf492a1c2..987ed620e 100644
--- a/src/bun.js/api/filesystem_router.classes.ts
+++ b/src/bun.js/api/filesystem_router.classes.ts
@@ -63,6 +63,14 @@ export default [
getter: "getFilePath",
cache: true,
},
+ scriptSrc: {
+ getter: "getScriptSrc",
+ cache: true,
+ },
+ src: {
+ getter: "getScriptSrc",
+ cache: "scriptSrc",
+ },
},
klass: {},
}),
diff --git a/src/bun.js/api/filesystem_router.zig b/src/bun.js/api/filesystem_router.zig
index 81ceb33a1..96c094b5c 100644
--- a/src/bun.js/api/filesystem_router.zig
+++ b/src/bun.js/api/filesystem_router.zig
@@ -142,6 +142,7 @@ const DeprecatedGlobalRouter = struct {
route.*,
JSC.VirtualMachine.vm.refCountedString(JSC.VirtualMachine.vm.origin.href, null, false),
JSC.VirtualMachine.vm.refCountedString(JSC.VirtualMachine.vm.bundler.options.routes.asset_prefix_path, null, false),
+ JSC.VirtualMachine.vm.refCountedString(JSC.VirtualMachine.vm.bundler.fs.top_level_dir, null, false),
) catch unreachable;
return matched.toJS(ctx).asObjectRef();
@@ -150,6 +151,7 @@ const DeprecatedGlobalRouter = struct {
pub const FileSystemRouter = struct {
origin: ?*JSC.RefString = null,
+ base_dir: ?*JSC.RefString = null,
router: Router,
arena: *std.heap.ArenaAllocator = undefined,
allocator: std.mem.Allocator = undefined,
@@ -279,11 +281,16 @@ pub const FileSystemRouter = struct {
var fs_router = globalThis.allocator().create(FileSystemRouter) catch unreachable;
fs_router.* = .{
.origin = if (origin_str.len > 0) vm.refCountedString(origin_str.slice(), null, true) else null,
+ .base_dir = vm.refCountedString(if (root_dir_info.abs_real_path.len > 0)
+ root_dir_info.abs_real_path
+ else
+ root_dir_info.abs_path, null, true),
.asset_prefix = if (asset_prefix_slice.len > 0) vm.refCountedString(asset_prefix_slice.slice(), null, true) else null,
.router = router,
.arena = arena,
.allocator = allocator,
};
+ fs_router.base_dir.?.ref();
return fs_router;
}
@@ -336,13 +343,13 @@ pub const FileSystemRouter = struct {
pub fn match(this: *FileSystemRouter, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSValue {
const argument_ = callframe.arguments(2);
if (argument_.len == 0) {
- globalThis.throwInvalidArguments("Expected string or Request", .{});
+ globalThis.throwInvalidArguments("Expected string, Request or Response", .{});
return JSValue.zero;
}
const argument = argument_.ptr[0];
if (argument.isEmptyOrUndefinedOrNull() or !argument.isCell()) {
- globalThis.throwInvalidArguments("Expected string or Request", .{});
+ globalThis.throwInvalidArguments("Expected string, Request or Response", .{});
return JSValue.zero;
}
@@ -356,9 +363,13 @@ pub const FileSystemRouter = struct {
req.ensureURL() catch unreachable;
break :brk ZigString.Slice.fromUTF8NeverFree(req.url).clone(globalThis.allocator()) catch unreachable;
}
+
+ if (argument.as(JSC.WebCore.Response)) |resp| {
+ break :brk ZigString.Slice.fromUTF8NeverFree(resp.url).clone(globalThis.allocator()) catch unreachable;
+ }
}
- globalThis.throwInvalidArguments("Expected string or Request", .{});
+ globalThis.throwInvalidArguments("Expected string, Request or Response", .{});
return JSValue.zero;
};
@@ -366,7 +377,7 @@ pub const FileSystemRouter = struct {
path = ZigString.Slice.fromUTF8NeverFree("/");
}
- if (strings.hasPrefixComptime(path.slice(), "http:") or strings.hasPrefixComptime(path.slice(), "https:")) {
+ if (strings.hasPrefixComptime(path.slice(), "http://") or strings.hasPrefixComptime(path.slice(), "https://") or strings.hasPrefixComptime(path.slice(), "file://")) {
const prev_path = path;
path = ZigString.init(URL.parse(path.slice()).pathname).toSliceFast(globalThis.allocator()).clone(globalThis.allocator()) catch unreachable;
prev_path.deinit();
@@ -387,7 +398,13 @@ pub const FileSystemRouter = struct {
return JSValue.jsNull();
};
- var result = MatchedRoute.init(globalThis.allocator(), route, this.origin, this.asset_prefix) catch unreachable;
+ var result = MatchedRoute.init(
+ globalThis.allocator(),
+ route,
+ this.origin,
+ this.asset_prefix,
+ this.base_dir.?,
+ ) catch unreachable;
return result.toJS(globalThis);
}
@@ -441,6 +458,10 @@ pub const FileSystemRouter = struct {
prefix.deref();
}
+ if (this.base_dir) |dir| {
+ dir.deref();
+ }
+
this.arena.deinit();
}
};
@@ -454,6 +475,7 @@ pub const MatchedRoute = struct {
origin: ?*JSC.RefString = null,
asset_prefix: ?*JSC.RefString = null,
needs_deinit: bool = true,
+ base_dir: ?*JSC.RefString = null,
pub usingnamespace JSC.Codegen.JSMatchedRoute;
@@ -461,7 +483,13 @@ pub const MatchedRoute = struct {
return ZigString.init(this.route.name).withEncoding().toValueGC(globalThis);
}
- pub fn init(allocator: std.mem.Allocator, match: Router.Match, origin: ?*JSC.RefString, asset_prefix: ?*JSC.RefString) !*MatchedRoute {
+ pub fn init(
+ allocator: std.mem.Allocator,
+ match: Router.Match,
+ origin: ?*JSC.RefString,
+ asset_prefix: ?*JSC.RefString,
+ base_dir: *JSC.RefString,
+ ) !*MatchedRoute {
var params_list = try match.params.clone(allocator);
var route = try allocator.create(MatchedRoute);
@@ -471,7 +499,9 @@ pub const MatchedRoute = struct {
.route = undefined,
.asset_prefix = asset_prefix,
.origin = origin,
+ .base_dir = base_dir,
};
+ base_dir.ref();
route.params_list_holder = params_list;
route.route = &route.route_holder;
route.route_holder.params = &route.params_list_holder;
@@ -507,6 +537,9 @@ pub const MatchedRoute = struct {
prefix.deref();
}
+ if (this.base_dir) |base|
+ base.deref();
+
bun.default_allocator.destroy(this);
}
@@ -630,7 +663,8 @@ pub const MatchedRoute = struct {
var writer = stream.writer();
JSC.API.Bun.getPublicPathWithAssetPrefix(
this.route.file_path,
- if (this.origin) |origin| URL.parse(origin) else URL{},
+ if (this.base_dir) |base_dir| base_dir.slice() else VirtualMachine.vm.bundler.fs.top_level_dir,
+ if (this.origin) |origin| URL.parse(origin.slice()) else URL{},
if (this.asset_prefix) |prefix| prefix.slice() else "",
@TypeOf(&writer),
&writer,
diff --git a/src/bun.js/bindings/ZigGeneratedClasses.cpp b/src/bun.js/bindings/ZigGeneratedClasses.cpp
index 4d96e8e0a..4c332ebbd 100644
--- a/src/bun.js/bindings/ZigGeneratedClasses.cpp
+++ b/src/bun.js/bindings/ZigGeneratedClasses.cpp
@@ -5859,6 +5859,12 @@ JSC_DECLARE_CUSTOM_GETTER(MatchedRoutePrototype__pathnameGetterWrap);
extern "C" JSC::EncodedJSValue MatchedRoutePrototype__getQuery(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject);
JSC_DECLARE_CUSTOM_GETTER(MatchedRoutePrototype__queryGetterWrap);
+extern "C" JSC::EncodedJSValue MatchedRoutePrototype__getScriptSrc(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject);
+JSC_DECLARE_CUSTOM_GETTER(MatchedRoutePrototype__scriptSrcGetterWrap);
+
+extern "C" JSC::EncodedJSValue MatchedRoutePrototype__getScriptSrc(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject);
+JSC_DECLARE_CUSTOM_GETTER(MatchedRoutePrototype__srcGetterWrap);
+
STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSMatchedRoutePrototype, JSMatchedRoutePrototype::Base);
static const HashTableValue JSMatchedRoutePrototypeTableValues[] = {
@@ -5867,7 +5873,9 @@ static const HashTableValue JSMatchedRoutePrototypeTableValues[] = {
{ "name"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, MatchedRoutePrototype__nameGetterWrap, 0 } },
{ "params"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, MatchedRoutePrototype__paramsGetterWrap, 0 } },
{ "pathname"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, MatchedRoutePrototype__pathnameGetterWrap, 0 } },
- { "query"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, MatchedRoutePrototype__queryGetterWrap, 0 } }
+ { "query"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, MatchedRoutePrototype__queryGetterWrap, 0 } },
+ { "scriptSrc"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, MatchedRoutePrototype__scriptSrcGetterWrap, 0 } },
+ { "src"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, MatchedRoutePrototype__srcGetterWrap, 0 } }
};
const ClassInfo JSMatchedRoutePrototype::s_info = { "MatchedRoute"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSMatchedRoutePrototype) };
@@ -6070,6 +6078,68 @@ extern "C" EncodedJSValue MatchedRoutePrototype__queryGetCachedValue(JSC::Encode
return JSValue::encode(thisObject->m_query.get());
}
+JSC_DEFINE_CUSTOM_GETTER(MatchedRoutePrototype__scriptSrcGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSMatchedRoute* thisObject = jsCast<JSMatchedRoute*>(JSValue::decode(thisValue));
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ if (JSValue cachedValue = thisObject->m_scriptSrc.get())
+ return JSValue::encode(cachedValue);
+
+ JSC::JSValue result = JSC::JSValue::decode(
+ MatchedRoutePrototype__getScriptSrc(thisObject->wrapped(), globalObject));
+ RETURN_IF_EXCEPTION(throwScope, {});
+ thisObject->m_scriptSrc.set(vm, thisObject, result);
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(result));
+}
+
+extern "C" void MatchedRoutePrototype__scriptSrcSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSMatchedRoute*>(JSValue::decode(thisValue));
+ thisObject->m_scriptSrc.set(vm, thisObject, JSValue::decode(value));
+}
+
+extern "C" EncodedJSValue MatchedRoutePrototype__scriptSrcGetCachedValue(JSC::EncodedJSValue thisValue)
+{
+ auto* thisObject = jsCast<JSMatchedRoute*>(JSValue::decode(thisValue));
+ return JSValue::encode(thisObject->m_scriptSrc.get());
+}
+
+JSC_DEFINE_CUSTOM_GETTER(MatchedRoutePrototype__srcGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSMatchedRoute* thisObject = jsCast<JSMatchedRoute*>(JSValue::decode(thisValue));
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ if (JSValue cachedValue = thisObject->m_scriptSrc.get())
+ return JSValue::encode(cachedValue);
+
+ JSC::JSValue result = JSC::JSValue::decode(
+ MatchedRoutePrototype__getScriptSrc(thisObject->wrapped(), globalObject));
+ RETURN_IF_EXCEPTION(throwScope, {});
+ thisObject->m_scriptSrc.set(vm, thisObject, result);
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(result));
+}
+
+extern "C" void MatchedRoutePrototype__srcSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSMatchedRoute*>(JSValue::decode(thisValue));
+ thisObject->m_scriptSrc.set(vm, thisObject, JSValue::decode(value));
+}
+
+extern "C" EncodedJSValue MatchedRoutePrototype__srcGetCachedValue(JSC::EncodedJSValue thisValue)
+{
+ auto* thisObject = jsCast<JSMatchedRoute*>(JSValue::decode(thisValue));
+ return JSValue::encode(thisObject->m_scriptSrc.get());
+}
+
void JSMatchedRoutePrototype::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
{
Base::finishCreation(vm);
@@ -6166,6 +6236,7 @@ void JSMatchedRoute::visitChildrenImpl(JSCell* cell, Visitor& visitor)
visitor.append(thisObject->m_params);
visitor.append(thisObject->m_pathname);
visitor.append(thisObject->m_query);
+ visitor.append(thisObject->m_scriptSrc);
}
DEFINE_VISIT_CHILDREN(JSMatchedRoute);
@@ -6182,6 +6253,7 @@ void JSMatchedRoute::visitAdditionalChildren(Visitor& visitor)
visitor.append(thisObject->m_params);
visitor.append(thisObject->m_pathname);
visitor.append(thisObject->m_query);
+ visitor.append(thisObject->m_scriptSrc);
;
}
diff --git a/src/bun.js/bindings/ZigGeneratedClasses.h b/src/bun.js/bindings/ZigGeneratedClasses.h
index 32b7a8c5e..2f3a74ab2 100644
--- a/src/bun.js/bindings/ZigGeneratedClasses.h
+++ b/src/bun.js/bindings/ZigGeneratedClasses.h
@@ -899,6 +899,7 @@ public:
mutable JSC::WriteBarrier<JSC::Unknown> m_params;
mutable JSC::WriteBarrier<JSC::Unknown> m_pathname;
mutable JSC::WriteBarrier<JSC::Unknown> m_query;
+ mutable JSC::WriteBarrier<JSC::Unknown> m_scriptSrc;
};
class JSExpect final : public JSC::JSDestructibleObject {
diff --git a/src/bun.js/bindings/generated_classes.zig b/src/bun.js/bindings/generated_classes.zig
index e3ea791d8..49704f23a 100644
--- a/src/bun.js/bindings/generated_classes.zig
+++ b/src/bun.js/bindings/generated_classes.zig
@@ -1809,6 +1809,28 @@ pub const JSMatchedRoute = struct {
return result;
}
+ extern fn MatchedRoutePrototype__scriptSrcSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ extern fn MatchedRoutePrototype__scriptSrcGetCachedValue(JSC.JSValue) JSC.JSValue;
+
+ /// `MatchedRoute.scriptSrc` setter
+ /// This value will be visited by the garbage collector.
+ pub fn scriptSrcSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
+ MatchedRoutePrototype__scriptSrcSetCachedValue(thisValue, globalObject, value);
+ }
+
+ /// `MatchedRoute.scriptSrc` getter
+ /// This value will be visited by the garbage collector.
+ pub fn scriptSrcGetCached(thisValue: JSC.JSValue) ?JSC.JSValue {
+ JSC.markBinding(@src());
+ const result = MatchedRoutePrototype__scriptSrcGetCachedValue(thisValue);
+ if (result == .zero)
+ return null;
+
+ return result;
+ }
+
/// Create a new instance of MatchedRoute
pub fn toJS(this: *MatchedRoute, globalObject: *JSC.JSGlobalObject) JSC.JSValue {
JSC.markBinding(@src());
@@ -1863,6 +1885,12 @@ pub const JSMatchedRoute = struct {
if (@TypeOf(MatchedRoute.getQuery) != GetterType)
@compileLog("Expected MatchedRoute.getQuery to be a getter");
+ if (@TypeOf(MatchedRoute.getScriptSrc) != GetterType)
+ @compileLog("Expected MatchedRoute.getScriptSrc to be a getter");
+
+ if (@TypeOf(MatchedRoute.getScriptSrc) != GetterType)
+ @compileLog("Expected MatchedRoute.getScriptSrc to be a getter");
+
if (!JSC.is_bindgen) {
@export(MatchedRoute.finalize, .{ .name = "MatchedRouteClass__finalize" });
@export(MatchedRoute.getFilePath, .{ .name = "MatchedRoutePrototype__getFilePath" });
@@ -1871,6 +1899,7 @@ pub const JSMatchedRoute = struct {
@export(MatchedRoute.getParams, .{ .name = "MatchedRoutePrototype__getParams" });
@export(MatchedRoute.getPathname, .{ .name = "MatchedRoutePrototype__getPathname" });
@export(MatchedRoute.getQuery, .{ .name = "MatchedRoutePrototype__getQuery" });
+ @export(MatchedRoute.getScriptSrc, .{ .name = "MatchedRoutePrototype__getScriptSrc" });
}
}
};
diff --git a/src/url.zig b/src/url.zig
index 4f6602a3f..97ef74125 100644
--- a/src/url.zig
+++ b/src/url.zig
@@ -486,6 +486,7 @@ pub const QueryStringMap = struct {
var slice = this.map.list.slice();
const hash = slice.items(.name_hash)[this.i];
const name_slice = slice.items(.name)[this.i];
+ std.debug.assert(name_slice.length > 0);
var result = Result{ .name = this.map.str(name_slice), .values = target[0..1] };
target[0] = this.map.str(slice.items(.value)[this.i]);
@@ -859,14 +860,12 @@ fn stringPointerFromStrings(parent: string, in: string) Api.StringPointer {
if (in.len == 0 or parent.len == 0) return Api.StringPointer{};
if (bun.isSliceInBuffer(in, parent)) {
- const end = @ptrToInt(parent.ptr) + parent.len;
- const in_end = @ptrToInt(in.ptr) + in.len;
- if (in_end < end) return Api.StringPointer{};
+ const offset = @minimum(
+ @maximum(@ptrToInt(in.ptr), @ptrToInt(parent.ptr)) - @minimum(@ptrToInt(in.ptr), @ptrToInt(parent.ptr)),
+ @minimum(in.len, parent.len),
+ );
- return Api.StringPointer{
- .offset = @truncate(u32, @maximum(@ptrToInt(in.ptr), @ptrToInt(parent.ptr)) - @ptrToInt(parent.ptr)),
- .length = @truncate(u32, in.len),
- };
+ return Api.StringPointer{ .offset = @truncate(u32, offset), .length = @truncate(u32, in.len) };
} else {
if (strings.indexOf(parent, in)) |i| {
return Api.StringPointer{
diff --git a/test/bun.js/filesystem_router.test.ts b/test/bun.js/filesystem_router.test.ts
index 9aba52a30..8e3e34d9a 100644
--- a/test/bun.js/filesystem_router.test.ts
+++ b/test/bun.js/filesystem_router.test.ts
@@ -109,3 +109,71 @@ it("should support dynamic routes", () => {
expect(name).toBe("/posts/[id]");
expect(filePath).toBe(`${tempdir}fs-router-test-02/posts/[id].tsx`);
});
+
+it("should support Request & Response", async () => {
+ // set up the test
+ const tempdir = realpathSync(tmpdir()) + "/";
+ rmSync(tempdir + "fs-router-test-03", { recursive: true, force: true });
+ createTree(tempdir + "fs-router-test-03", [
+ "index.tsx",
+ "posts/[id].tsx",
+ "posts.tsx",
+ ]);
+
+ const router = new Bun.FileSystemRouter({
+ dir: tempdir + "fs-router-test-03/",
+ style: "nextjs",
+ });
+
+ for (let current of [
+ // Reuqest
+ new Request({ url: "/posts/hello-world" }),
+ new Request({ url: "http://example.com/posts/hello-world" }),
+ // Response
+ // when there's http:// it will be parsed as a URL and only the pathname is used
+ await fetch("http://example.com/posts/hello-world"),
+ ]) {
+ const {
+ name,
+ params: { id },
+ filePath,
+ } = router.match(current);
+ expect(id).toBe("hello-world");
+ expect(name).toBe("/posts/[id]");
+ expect(filePath).toBe(`${tempdir}fs-router-test-03/posts/[id].tsx`);
+ }
+});
+
+it("assetPrefix, src, and origin", async () => {
+ // set up the test
+ const tempdir = realpathSync(tmpdir()) + "/";
+ rmSync(tempdir + "fs-router-test-04", { recursive: true, force: true });
+ createTree(tempdir + "fs-router-test-04", [
+ "index.tsx",
+ "posts/[id].tsx",
+ "posts.tsx",
+ ]);
+
+ const router = new Bun.FileSystemRouter({
+ dir: tempdir + "fs-router-test-04/",
+ style: "nextjs",
+ assetPrefix: "/_next/static/",
+ origin: "https://nextjs.org",
+ });
+
+ for (let current of [
+ // Reuqest
+ new Request({ url: "/posts/hello-world" }),
+ new Request({ url: "https://nextjs.org/posts/hello-world" }),
+ ]) {
+ const {
+ name,
+ params: { id },
+ src,
+ filePath,
+ } = router.match(current);
+ expect(name).toBe("/posts/[id]");
+ expect(src).toBe("https://nextjs.org/_next/static/posts/[id].tsx");
+ expect(filePath).toBe(`${tempdir}fs-router-test-04/posts/[id].tsx`);
+ }
+});