diff options
author | 2022-11-22 04:00:55 -0800 | |
---|---|---|
committer | 2022-11-22 04:00:55 -0800 | |
commit | 2b4dcc8c817e2597f2de079c27302f9970fbebb6 (patch) | |
tree | 1259946f391e7624203c20936e2156a72c20af75 | |
parent | 15a5aa1a682c81cb017795e9489dbb279e7b6717 (diff) | |
download | bun-2b4dcc8c817e2597f2de079c27302f9970fbebb6.tar.gz bun-2b4dcc8c817e2597f2de079c27302f9970fbebb6.tar.zst bun-2b4dcc8c817e2597f2de079c27302f9970fbebb6.zip |
[FileSystemRouter] base_dir, Request, Response
-rw-r--r-- | src/bun.js/api/bun.zig | 9 | ||||
-rw-r--r-- | src/bun.js/api/filesystem_router.classes.ts | 8 | ||||
-rw-r--r-- | src/bun.js/api/filesystem_router.zig | 48 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGeneratedClasses.cpp | 74 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGeneratedClasses.h | 1 | ||||
-rw-r--r-- | src/bun.js/bindings/generated_classes.zig | 29 | ||||
-rw-r--r-- | src/url.zig | 13 | ||||
-rw-r--r-- | test/bun.js/filesystem_router.test.ts | 68 |
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`); + } +}); |