fix(fs): path api for path and url

pull/8914/head
Andelf 2023-03-09 17:22:18 +08:00
parent ad564a4d72
commit 500d8f2c36
1 changed files with 50 additions and 10 deletions

View File

@ -11,6 +11,7 @@
(and (string? s)
(or (string/starts-with? s "file://")
(string/starts-with? s "content://")
(string/starts-with? s "logseq://") ;; reserved for future fs protocl
(string/starts-with? s "s3://"))))
@ -59,11 +60,12 @@
(re-find #"[\u0000-\u001f\u0080-\u009f]" fname)))))
(defn path-join
(defn- path-join-internal
"Joins the given path segments into a single path, handling relative paths,
'..' and '.' normalization."
[& segments]
(let [segments (remove nil? segments) ;; handle (path-join nil path)
_ (prn ::seg segments)
segments (map #(string/replace % #"[/\\]+" "/") segments)
;; a fix for clojure.string/split
split-fn (fn [s]
@ -99,17 +101,28 @@
(join-fn))))
(defn url-join
"Segments are not URL-ecoded"
[base-url & segments]
(let [^js url (.parse Uri base-url)
scheme (.getScheme url)
domain (.getDomain url)
path (.getPath url)
new-path (apply path-join path segments)
new-path (apply path-join-internal path segments)
;; opt_scheme, opt_userInfo, opt_domain, opt_port, opt_path, opt_query, opt_fragment, opt_ignoreCase
new-url (.create Uri scheme nil domain nil new-path nil nil nil)]
(.toString new-url)))
(defn path-normalize
(defn path-join
"Join path segments, or URL base and path segments"
[base & segments]
(prn base segments)
(if (is-file-url base)
(apply url-join base segments)
(apply path-join-internal base segments)))
(defn- path-normalize-internal
"Normalize path using path-join, break into segment and re-join"
[path]
(path-join path))
@ -121,23 +134,50 @@
scheme (.getScheme uri)
domain (.getDomain uri)
path (.getPath uri)
new-path (path-normalize path)
new-path (path-normalize-internal path)
;; opt_scheme, opt_userInfo, opt_domain, opt_port, opt_path, opt_query, opt_fragment, opt_ignoreCase
new-uri (.create Uri scheme nil domain nil new-path nil nil nil)]
(.toString new-uri)))
(defn path-normalize
"Normalize path or URL"
[path]
(if (is-file-url path)
(url-normalize path)
(path-normalize-internal path)))
(defn relative-path
"Get relative path from base path"
[base path]
(defn trim-dir-prefix
"Trim dir prefix from path"
[base sub]
(let [base (path-normalize base)
path (path-normalize path)]
path (path-normalize sub)]
(if (string/starts-with? path base)
(string/replace (subs path (count base)) #"^/+", "")
(do
(js/console.error "unhandled relative path" base path)
(js/console.error "unhandled trim-base" base path)
path))))
(defn relative-path
"Get relative path from base path.
Works for both path and URL."
[base-path sub-path]
(let [base-path (path-normalize base-path)
is-url (is-file-url base-path)
sub-path (path-normalize sub-path)]
(if (string/starts-with? sub-path base-path)
(string/replace (subs sub-path (count base-path)) #"^/+", "")
;; append as many ..
(let [base-segs (string/split base-path #"/" -1)
path-segs (string/split sub-path #"/" -1)
common-segs (take-while #(= (first %) (second %)) (map vector base-segs path-segs))
base-segs (drop (count common-segs) base-segs)
path-segs (drop (count common-segs) path-segs)
base-prefix (repeat (max 0 (dec (count base-segs))) "../")]
#_{:clj-kondo/ignore [:path-invalid-construct/string-join]}
(str (concat base-prefix (string/join "/" path-segs)))))))
(defn decoded-relative-uri
"Get relative uri from base url, url-decoded"
[base-url path-url]
@ -152,5 +192,5 @@
(defn parent
[path]
;; ugly but works
(path-normalize (str path "/..")))
(path-normalize-internal (str path "/..")))