Implement #238, handle trailing slashes in frontend match-by-path

This commit is contained in:
Juho Teperi 2019-03-15 17:33:46 +02:00
parent 3644c2e392
commit c86f042f54
2 changed files with 106 additions and 4 deletions

View file

@ -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]

View file

@ -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"))))))