1import { assert, it } from "@effect/vitest"
2import { FindMyWay as Router } from "effect/http"
3
4it("path params match", () => {
5 const router = Router.make<1 | 2 | "c" | "param">()
6
7 router.on("GET", "/ab1", 1)
8 router.on("GET", "/ab2", 2)
9 router.on("GET", "/ac", "c")
10 router.on("GET", "/:pam", "param")
11
12 assert.strictEqual(router.find("GET", "/ab1")?.handler, 1)
13 assert.strictEqual(router.find("GET", "/ab1/")?.handler, 1)
14 assert.strictEqual(router.find("GET", "//ab1")?.handler, 1)
15 assert.strictEqual(router.find("GET", "//ab1//")?.handler, 1)
16 assert.strictEqual(router.find("GET", "/ab2")?.handler, 2)
17 assert.strictEqual(router.find("GET", "/ab2/")?.handler, 2)
18 assert.strictEqual(router.find("GET", "//ab2")?.handler, 2)
19 assert.strictEqual(router.find("GET", "//ab2//")?.handler, 2)
20 assert.strictEqual(router.find("GET", "/ac")?.handler, "c")
21 assert.strictEqual(router.find("GET", "/ac/")?.handler, "c")
22 assert.strictEqual(router.find("GET", "//ac")?.handler, "c")
23 assert.strictEqual(router.find("GET", "//ac//")?.handler, "c")
24 assert.strictEqual(router.find("GET", "/foo")?.handler, "param")
25 assert.strictEqual(router.find("GET", "/foo/")?.handler, "param")
26 assert.strictEqual(router.find("GET", "//foo")?.handler, "param")
27 assert.strictEqual(router.find("GET", "//foo//")?.handler, "param")
28 assert.deepStrictEqual(router.find("GET", "/abcdef"), {
29 handler: "param",
30 params: { pam: "abcdef" },
31 searchParams: {}
32 })
33 assert.deepStrictEqual(router.find("GET", "/abcdef/"), {
34 handler: "param",
35 params: { pam: "abcdef" },
36 searchParams: {}
37 })
38 assert.deepStrictEqual(router.find("GET", "//abcdef"), {
39 handler: "param",
40 params: { pam: "abcdef" },
41 searchParams: {}
42 })
43})
44
45it("builds null-prototype params for static and parameterized routes", () => {
46 const router = Router.make<boolean>()
47 router.on("GET", "/health", true)
48 router.on("GET", "/users/:id", true)
49 router.on("GET", "/orgs/:org/repos/:repo", true)
50
51 for (
52 const [path, expected] of [
53 ["/health", {}],
54 ["/users/42", { id: "42" }],
55 ["/orgs/effect/repos/core", { org: "effect", repo: "core" }]
56 ] as const
57 ) {
58 const params = router.find("GET", path)!.params
59 assert.strictEqual(Object.getPrototypeOf(params), null)
60 assert.deepStrictEqual({ ...params }, expected)
61 }
62})
63
64it("does not compile parameter names with Function", () => {
65 const OriginalFunction = globalThis.Function
66 let constructions = 0
67 globalThis.Function = new Proxy(OriginalFunction, {
68 construct(target, args, newTarget) {
69 constructions++
70 return Reflect.construct(target, args, newTarget)
71 }
72 })
73 try {
74 const router = Router.make<boolean>()
75 router.on("GET", "/users/:id", true)
76 router.on("GET", "/orgs/:org/repos/:repo", true)
77 assert.deepStrictEqual({ ...router.find("GET", "/users/42")!.params }, { id: "42" })
78 assert.deepStrictEqual({ ...router.find("GET", "/orgs/effect/repos/core")!.params }, {
79 org: "effect",
80 repo: "core"
81 })
82 } finally {
83 globalThis.Function = OriginalFunction
84 }
85 assert.strictEqual(constructions, 0)
86})
87
88it("does not read inherited static child entries", () => {
89 const label = "\uE000"
90 // oxlint-disable-next-line no-extend-native -- Reproduce an inherited entry without reaching into router internals.
91 Object.defineProperty(Object.prototype, label, {
92 configurable: true,
93 value: {}
94 })
95
96 try {
97 const router = Router.make<boolean>()
98 router.on("GET", `/${label}`, true)
99
100 assert.strictEqual(router.find("GET", `/${label}`)?.handler, true)
101 } finally {
102 Reflect.deleteProperty(Object.prototype, label)
103 }
104})