mirror of
https://github.com/metosin/reitit.git
synced 2025-12-22 18:41:10 +00:00
Implement #238, handle trailing slashes in frontend match-by-path
This commit is contained in:
parent
3644c2e392
commit
c86f042f54
2 changed files with 106 additions and 4 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
(ns reitit.frontend
|
(ns reitit.frontend
|
||||||
(:require [clojure.set :as set]
|
(:require [clojure.set :as set]
|
||||||
|
[clojure.string :as str]
|
||||||
[reitit.coercion :as coercion]
|
[reitit.coercion :as coercion]
|
||||||
[reitit.coercion :as rc]
|
[reitit.coercion :as rc]
|
||||||
[reitit.core :as r])
|
[reitit.core :as r])
|
||||||
|
|
@ -16,10 +17,18 @@
|
||||||
|
|
||||||
(defn match-by-path
|
(defn match-by-path
|
||||||
"Given routing tree and current path, return match with possibly
|
"Given routing tree and current path, return match with possibly
|
||||||
coerced parameters. Return nil if no match found."
|
coerced parameters. Returns nil if no match found."
|
||||||
[router path]
|
[router path]
|
||||||
(let [uri (.parse Uri path)]
|
(let [uri (.parse Uri path)
|
||||||
(if-let [match (r/match-by-path router (.getPath uri))]
|
path (.getPath uri)]
|
||||||
|
(if-let [match (or (r/match-by-path router path)
|
||||||
|
(if-let [trailing-slash-handling (:trailing-slash-handling (r/options router))]
|
||||||
|
(if (str/ends-with? path "/")
|
||||||
|
(if (not= trailing-slash-handling :add)
|
||||||
|
(r/match-by-path router (subs path 0 (dec (count path)))))
|
||||||
|
(if (not= trailing-slash-handling :remove)
|
||||||
|
(r/match-by-path router (str path "/"))))))]
|
||||||
|
;; User can update browser location in on-navigate call using replace-state
|
||||||
(let [q (query-params uri)
|
(let [q (query-params uri)
|
||||||
match (assoc match :query-params q)
|
match (assoc match :query-params q)
|
||||||
;; Return uncoerced values if coercion is not enabled - so
|
;; Return uncoerced values if coercion is not enabled - so
|
||||||
|
|
@ -40,7 +49,14 @@
|
||||||
|
|
||||||
(defn router
|
(defn router
|
||||||
"Create a `reitit.core.router` from raw route data and optionally an options map.
|
"Create a `reitit.core.router` from raw route data and optionally an options map.
|
||||||
Enables request coercion. See [[reitit.core/router]] for details on options."
|
Enables request coercion. See [[reitit.core/router]] for details on options.
|
||||||
|
|
||||||
|
Additional options:
|
||||||
|
|
||||||
|
| key | description |
|
||||||
|
| -------------|-------------|
|
||||||
|
| :trailing-slash-handling | TODO |
|
||||||
|
"
|
||||||
([raw-routes]
|
([raw-routes]
|
||||||
(router raw-routes {}))
|
(router raw-routes {}))
|
||||||
([raw-routes opts]
|
([raw-routes opts]
|
||||||
|
|
|
||||||
|
|
@ -104,3 +104,89 @@
|
||||||
(capture-console
|
(capture-console
|
||||||
(fn []
|
(fn []
|
||||||
(rf/match-by-name! router ::foo {}))))))))))
|
(rf/match-by-name! router ::foo {}))))))))))
|
||||||
|
|
||||||
|
|
||||||
|
(deftest trailing-slash-handling-test
|
||||||
|
(testing ":both"
|
||||||
|
(let [router (r/router ["/"
|
||||||
|
["" ::frontpage]
|
||||||
|
["foo" ::foo]
|
||||||
|
["bar/" ::bar]]
|
||||||
|
{:trailing-slash-handling :both})]
|
||||||
|
(is (= (r/map->Match
|
||||||
|
{:template "/foo"
|
||||||
|
:data {:name ::foo}
|
||||||
|
:path-params {}
|
||||||
|
:query-params {}
|
||||||
|
:path "/foo"
|
||||||
|
:parameters {:query {}
|
||||||
|
:path {}}})
|
||||||
|
(rf/match-by-path router "/foo/")
|
||||||
|
(rf/match-by-path router "/foo")))
|
||||||
|
|
||||||
|
(is (= (r/map->Match
|
||||||
|
{:template "/bar/"
|
||||||
|
:data {:name ::bar}
|
||||||
|
:path-params {}
|
||||||
|
:query-params {}
|
||||||
|
:path "/bar/"
|
||||||
|
:parameters {:query {}
|
||||||
|
:path {}}})
|
||||||
|
(rf/match-by-path router "/bar/")
|
||||||
|
(rf/match-by-path router "/bar"))) ))
|
||||||
|
|
||||||
|
(testing ":add"
|
||||||
|
(let [router (r/router ["/"
|
||||||
|
["" ::frontpage]
|
||||||
|
["foo" ::foo]
|
||||||
|
["bar/" ::bar]]
|
||||||
|
{:trailing-slash-handling :add})]
|
||||||
|
(is (= (r/map->Match
|
||||||
|
{:template "/foo"
|
||||||
|
:data {:name ::foo}
|
||||||
|
:path-params {}
|
||||||
|
:query-params {}
|
||||||
|
:path "/foo"
|
||||||
|
:parameters {:query {}
|
||||||
|
:path {}}})
|
||||||
|
(rf/match-by-path router "/foo")))
|
||||||
|
(is (nil? (rf/match-by-path router "/foo/")))
|
||||||
|
|
||||||
|
(is (= (r/map->Match
|
||||||
|
{:template "/bar/"
|
||||||
|
:data {:name ::bar}
|
||||||
|
:path-params {}
|
||||||
|
:query-params {}
|
||||||
|
:path "/bar/"
|
||||||
|
:parameters {:query {}
|
||||||
|
:path {}}})
|
||||||
|
(rf/match-by-path router "/bar/")
|
||||||
|
(rf/match-by-path router "/bar")))))
|
||||||
|
|
||||||
|
(testing ":remove"
|
||||||
|
(let [router (r/router ["/"
|
||||||
|
["" ::frontpage]
|
||||||
|
["foo" ::foo]
|
||||||
|
["bar/" ::bar]]
|
||||||
|
{:trailing-slash-handling :remove})]
|
||||||
|
(is (= (r/map->Match
|
||||||
|
{:template "/foo"
|
||||||
|
:data {:name ::foo}
|
||||||
|
:path-params {}
|
||||||
|
:query-params {}
|
||||||
|
:path "/foo"
|
||||||
|
:parameters {:query {}
|
||||||
|
:path {}}})
|
||||||
|
(rf/match-by-path router "/foo/")
|
||||||
|
(rf/match-by-path router "/foo")))
|
||||||
|
|
||||||
|
(is (= (r/map->Match
|
||||||
|
{:template "/bar/"
|
||||||
|
:data {:name ::bar}
|
||||||
|
:path-params {}
|
||||||
|
:query-params {}
|
||||||
|
:path "/bar/"
|
||||||
|
:parameters {:query {}
|
||||||
|
:path {}}})
|
||||||
|
(rf/match-by-path router "/bar/")))
|
||||||
|
(is (nil? (rf/match-by-path router "/bar"))))))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue